HH/apps/px_sources/decorators.py
2026-03-09 16:10:24 +03:00

175 lines
5.3 KiB
Python

"""
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