You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

95 lines
3.9 KiB

from rest_framework.permissions import BasePermission, SAFE_METHODS
def can_publish_or_moderate_post(user, institution=None) -> bool:
"""
Evaluates dynamic permission capability without hardcoding any role names or slugs:
1. User must be active and authenticated.
2. Superuser / Super Admin has global authority.
3. User must hold the capability flag: user.has_perm_flag('can_publish_posts_directly').
4. If an institution is associated with the post:
- User must be affiliated with this institution (as a member in institution.members), OR
- User's managed_regions covers the institution's geographical region.
5. Standalone post (no institution):
- User holds 'can_publish_posts_directly'.
"""
if not user or not user.is_authenticated or not user.is_active:
return False
if user.is_superuser or getattr(user, 'is_super_admin', False):
return True
# Dynamic capability check (configurable in Django Admin on Role / custom_permissions)
if not user.has_perm_flag('can_publish_posts_directly'):
return False
if institution:
# Check direct institution membership affiliation
if institution.members.filter(user=user).exists():
return True
# Check managed_regions (if user has managed regions covering this institution's region)
if hasattr(user, 'managed_regions') and getattr(institution, 'region_id', None):
if user.managed_regions.filter(id=institution.region_id).exists():
return True
return False
return True
class IsAuthorOrEditorOrReadOnly(BasePermission):
"""
Read access is public (handled at view queryset level for status).
Object write/delete access:
- Author can edit their own post (draft, pending_review, rejected).
- Editors satisfying can_publish_or_moderate_post() can edit, approve, or reject.
"""
def has_permission(self, request, view):
if request.method in SAFE_METHODS:
return True
return bool(request.user and request.user.is_authenticated and request.user.is_active)
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
if not request.user or not request.user.is_authenticated or not request.user.is_active:
return False
if request.user.is_superuser or getattr(request.user, 'is_super_admin', False):
return True
# Editor / Moderator with capability over post institution
if can_publish_or_moderate_post(request.user, getattr(obj, 'institution', None)):
return True
# Post author or owning institution member can edit or delete their own post depending on HTTP method
is_owner = False
if hasattr(obj, 'author') and obj.author == request.user:
is_owner = True
elif getattr(obj, 'institution', None) and hasattr(obj.institution, 'members'):
if obj.institution.members.filter(user=request.user, role__in=['admin', 'editor']).exists():
is_owner = True
if is_owner:
if request.method == 'DELETE':
return request.user.has_perm_flag('can_delete_own_posts')
return request.user.has_perm_flag('can_edit_own_posts')
return False
class CanPublishPost(BasePermission):
"""
Validates that authenticated user has capability to create posts (can_create_posts).
Actual status transitions (draft vs pending_review vs published) are enforced by serializer.
"""
def has_permission(self, request, view):
if request.method in SAFE_METHODS:
return True
if not request.user or not request.user.is_authenticated or not request.user.is_active:
return False
if request.user.is_superuser or getattr(request.user, 'is_super_admin', False):
return True
return request.user.has_perm_flag('can_create_posts')