""" Tenant-aware middleware for multi-tenancy """ from django.http import HttpResponseRedirect from django.urls import reverse from django.utils.deprecation import MiddlewareMixin class TenantMiddleware(MiddlewareMixin): """ Middleware that sets the current hospital context from the authenticated user. This middleware ensures that: - authenticated users have their tenant_hospital set from their profile - PX admins can switch between hospitals via session - PX admins without a selected hospital are redirected to select-hospital - Source Users have their source context available - All requests have tenant context available """ EXEMPT_PATHS = [ "/core/select-hospital/", "/accounts/logout/", "/accounts/password_reset/", "/accounts/password_reset/done/", "/accounts/reset/", "/api/", "/health/", "/admin/", "/__debug__/", ] def process_request(self, request): """Set tenant hospital context on each request.""" if request.user and request.user.is_authenticated: request.user_roles = request.user.get_role_names() request.source_user = None request.source_user_profile = None if request.user.is_source_user(): profile = request.user.get_source_user_profile_active() if profile: request.source_user = profile request.source_user_profile = profile if request.user.is_px_admin(): hospital_id = request.session.get("selected_hospital_id") if hospital_id: from apps.organizations.models import Hospital try: request.tenant_hospital = Hospital.objects.get(id=hospital_id) except Hospital.DoesNotExist: request.tenant_hospital = None request.session.pop("selected_hospital_id", None) else: request.tenant_hospital = None else: request.tenant_hospital = request.user.hospital else: request.tenant_hospital = None request.user_roles = [] request.source_user = None request.source_user_profile = None return None def process_view(self, request, view_func, view_args, view_kwargs): """Redirect PX admins without hospital to select-hospital page.""" if not request.user or not request.user.is_authenticated: return None if not request.user.is_px_admin(): return None if request.tenant_hospital: return None path = request.path for exempt_path in self.EXEMPT_PATHS: if path.startswith(exempt_path): return None if request.headers.get("x-requested-with") == "XMLHttpRequest": return None return HttpResponseRedirect(reverse("core:select_hospital"))