""" Custom decorators for PX Source User access control. Provides decorators to: - Restrict views to source users only - Block source users from admin pages """ from functools import wraps from django.core.exceptions import PermissionDenied from django.contrib.auth.decorators import login_required from django.shortcuts import redirect from django.contrib import messages from django.utils.translation import gettext_lazy as _ def source_user_required(view_func): """ Decorator to restrict access to source users only. Use this on views that should ONLY be accessible to source users. Blocks all admin/management/staff pages. Example: @source_user_required def source_user_dashboard(request): # Only source users can access this """ @wraps(view_func) @login_required def _wrapped_view(request, *args, **kwargs): # Check if user has source user profile if not hasattr(request.user, 'source_user_profile'): raise PermissionDenied( _("Access denied. Source user privileges required.") ) source_user = request.user.source_user_profile # Check if source user is active if not source_user.is_active: # Log out the user from django.contrib.auth import logout logout(request) messages.error( request, _("Your source user account is inactive. Please contact your administrator.") ) return redirect('accounts:login') # Store source_user and source in request for easy access request.source_user = source_user request.source = source_user.source return view_func(request, *args, **kwargs) return _wrapped_view def block_source_user(view_func): """ Decorator to BLOCK source users from accessing admin pages. Use this on admin/management views that source users should NOT access. Allows all other users (PX Admin, Hospital Admin, Department Manager, etc.) Example: @block_source_user def source_list(request): # Source users CANNOT access this """ @wraps(view_func) @login_required def _wrapped_view(request, *args, **kwargs): # Check if user is ONLY a source user (no other admin roles) if _is_pure_source_user(request.user): messages.error( request, _("Access denied. Source users cannot access admin pages.") ) return redirect('px_sources:source_user_dashboard') return view_func(request, *args, **kwargs) return _wrapped_view def source_user_or_admin(view_func): """ Decorator that allows both source users AND admins. Use this on views that should be accessible to: - Source users (for their own data) - PX Admins, Hospital Admins, Department Managers Example: @source_user_or_admin def complaint_detail(request, pk): # Both source users and admins can view complaints """ @wraps(view_func) @login_required def _wrapped_view(request, *args, **kwargs): # Allow if user has admin roles if _has_admin_role(request.user): return view_func(request, *args, **kwargs) # Allow if user is an active source user if hasattr(request.user, 'source_user_profile'): source_user = request.user.source_user_profile if source_user.is_active: request.source_user = source_user request.source = source_user.source return view_func(request, *args, **kwargs) # Deny access raise PermissionDenied(_("Access denied.")) return _wrapped_view def _is_pure_source_user(user): """ Check if user is ONLY a source user with no admin roles. Returns True if: - User is in 'PX Source User' group - User is NOT in any admin groups """ 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 def _has_admin_role(user): """ Check if user has any admin role. """ admin_groups = ['PX Admin', 'Hospital Admin', 'Department Manager'] return user.groups.filter(name__in=admin_groups).exists() def px_admin_required(view_func): """ Decorator to restrict access to PX Admins only. Use this on views that should ONLY be accessible to PX Admins. """ @wraps(view_func) @login_required def _wrapped_view(request, *args, **kwargs): if not user.is_px_admin(): messages.error( request, _("Access denied. PX Admin privileges required.") ) return redirect('dashboard:dashboard') return view_func(request, *args, **kwargs) return _wrapped_view