roosterwijs/backend/core/permissions.py
bes-r c845588e5e
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
Add roles modules audit logging and CI
2026-07-04 23:01:06 +02:00

139 lines
4.5 KiB
Python

"""Gedeelde permissies voor roltoegang en module-gating."""
from rest_framework.permissions import BasePermission, SAFE_METHODS
def _profile(user):
return getattr(user, "gebruikersprofiel", None)
def user_role(user):
profile = _profile(user)
return getattr(profile, "rol", None)
def linked_person(user):
profile = _profile(user)
return getattr(profile, "persoon", None)
def is_admin_user(user):
return bool(
user
and user.is_authenticated
and (user.is_staff or user_role(user) == "beheerder")
)
INTERNAL_READ_ROLES = {
"medewerker",
"roostermaker",
"directie",
"zorgcoordinator",
"stagebegeleider",
"kijker",
}
def has_view_write_role(user, view):
write_roles = set(getattr(view, "write_roles", ()))
return user_role(user) in write_roles
class CoreDataPermission(BasePermission):
"""Kerngegevens: schrijven per rol, lezen rolbewust."""
message = "Je hebt geen rechten voor deze roostergegevens."
def has_permission(self, request, view):
if not request.user or not request.user.is_authenticated:
return False
if is_admin_user(request.user):
return True
if request.method in SAFE_METHODS:
return True
return has_view_write_role(request.user, view)
def has_object_permission(self, request, view, obj):
if is_admin_user(request.user):
return True
if request.method not in SAFE_METHODS:
return has_view_write_role(request.user, view)
role = user_role(request.user)
person = linked_person(request.user)
if role in ("leerling", "ouder") and person is not None:
if obj.__class__.__name__ == "Persoon":
return obj.pk == person.pk
if hasattr(obj, "persoon_id"):
return obj.persoon_id == person.pk
return role in INTERNAL_READ_ROLES
class StaffDataPermission(BasePermission):
"""Rapportages: interne rollen mogen lezen, beheerders/rolhouders schrijven."""
message = "Je hebt geen rechten voor deze rapportage."
def has_permission(self, request, view):
if not request.user or not request.user.is_authenticated:
return False
if is_admin_user(request.user):
return True
if request.method in SAFE_METHODS:
return user_role(request.user) in INTERNAL_READ_ROLES
return has_view_write_role(request.user, view)
class AdminRolePermission(BasePermission):
"""Beheerder via Django staff of via de applicatierol beheerder."""
message = "Je hebt beheerdersrechten nodig."
def has_permission(self, request, view):
return is_admin_user(request.user)
def restrict_core_queryset(request, queryset):
"""Filter gevoelige lijsten voor leerling/ouderaccounts met gekoppelde persoon."""
user = request.user
if is_admin_user(user) or user_role(user) in INTERNAL_READ_ROLES:
return queryset
person = linked_person(user)
if person is None:
return queryset.none()
model_name = queryset.model.__name__
if model_name == "Groep":
return queryset.filter(pk=person.groep_id) if getattr(person, "groep_id", None) else queryset.none()
if model_name == "Subgroep":
return queryset.filter(leden=person).distinct()
if model_name == "Persoon":
return queryset.filter(pk=person.pk)
if model_name == "Afwezigheid":
return queryset.filter(persoon=person)
if model_name == "Roosterblok":
qs = queryset.filter(leerling=person)
if getattr(person, "groep_id", None):
qs = qs | queryset.filter(groep_id=person.groep_id)
qs = qs | queryset.filter(subgroep__leden=person)
return qs.distinct()
if model_name == "BlokUitzondering":
qs = queryset.filter(roosterblok__leerling=person)
if getattr(person, "groep_id", None):
qs = qs | queryset.filter(roosterblok__groep_id=person.groep_id)
qs = qs | queryset.filter(roosterblok__subgroep__leden=person)
return qs.distinct()
return queryset
def module_permission_class(module_key):
"""Maak een DRF-permissieklasse die een module-aan/uit vlag afdwingt."""
class IsModuleEnabled(BasePermission):
message = f"Module '{module_key}' is uitgeschakeld."
def has_permission(self, request, view):
from plugins import services
return services.is_enabled(module_key)
IsModuleEnabled.__name__ = f"IsModuleEnabled_{module_key}"
return IsModuleEnabled