""" DRF Permissions for PX Source User access control. Provides permission classes to restrict API access based on user role: - Source users can only access their own data - Admins have full access """ from rest_framework import permissions from apps.px_sources.models import SourceUser class IsSourceUser(permissions.BasePermission): """ Allow access only to active source users. Use this on views that should ONLY be accessible to source users. Example: permission_classes = [IsSourceUser] """ def has_permission(self, request, view): if not request.user or not request.user.is_authenticated: return False # Check if user has source user profile if not hasattr(request.user, 'source_user_profile'): return False # Check if source user is active source_user = request.user.source_user_profile return source_user.is_active class IsSourceUserOrAdmin(permissions.BasePermission): """ Allow access to source users AND admins. Use this on views that should be accessible to: - Active source users - PX Admins, Hospital Admins, Department Managers Example: permission_classes = [IsSourceUserOrAdmin] """ def has_permission(self, request, view): if not request.user or not request.user.is_authenticated: return False # Allow admins if request.user.is_superuser or request.user.is_px_admin(): return True # Allow hospital admins if request.user.is_hospital_admin(): return True # Allow active source users if hasattr(request.user, 'source_user_profile'): source_user = request.user.source_user_profile return source_user.is_active return False class IsSourceUserOwnData(permissions.BasePermission): """ Object-level permission to ensure source users can only access their own data. Use this on detail views to ensure source users can only view/edit complaints and inquiries from their assigned source. Example: permission_classes = [IsSourceUserOrAdmin, IsSourceUserOwnData] """ def has_object_permission(self, request, view, obj): if not request.user or not request.user.is_authenticated: return False # Admins can access everything if request.user.is_superuser or request.user.is_px_admin(): return True # Check if user is a source user if not hasattr(request.user, 'source_user_profile'): return False source_user = request.user.source_user_profile if not source_user.is_active: return False # Check if object belongs to user's source if hasattr(obj, 'source'): return obj.source == source_user.source # If object doesn't have a source field, deny access return False class IsAdminUser(permissions.BasePermission): """ Allow access only to admin users (not source users). Use this on admin-only API endpoints. Example: permission_classes = [IsAdminUser] """ def has_permission(self, request, view): if not request.user or not request.user.is_authenticated: return False # Block pure source users if _is_pure_source_user(request.user): return False # Allow admins return request.user.is_superuser or request.user.is_px_admin() or request.user.is_hospital_admin() class IsPXAdmin(permissions.BasePermission): """ Allow access only to PX Admins. Use this on PX Admin-only API endpoints. """ def has_permission(self, request, view): if not request.user or not request.user.is_authenticated: return False return request.user.is_px_admin() def _is_pure_source_user(user): """ Check if user is ONLY a source user with no admin roles. """ admin_groups = ['PX Admin', 'Hospital Admin', 'Department Manager'] # Check if user has any admin roles has_admin_role = user.groups.filter(name__in=admin_groups).exists() if has_admin_role: return False # Check if user is a source user has_source_user_profile = hasattr(user, 'source_user_profile') if has_source_user_profile: source_user = user.source_user_profile if source_user.is_active: return True return False