diff --git a/backend/src/openarchiefbeheer/accounts/managers.py b/backend/src/openarchiefbeheer/accounts/managers.py index d99e50776..c18e74f7d 100644 --- a/backend/src/openarchiefbeheer/accounts/managers.py +++ b/backend/src/openarchiefbeheer/accounts/managers.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING -from django.contrib.auth.models import BaseUserManager, Group -from django.db.models import QuerySet +from django.contrib.auth.models import BaseUserManager, Permission +from django.db.models import Q, QuerySet if TYPE_CHECKING: from .models import User @@ -39,10 +39,15 @@ def create_superuser(self, username, email, password, **extra_fields): return self._create_user(username, email, password, **extra_fields) + def _users_with_permission(self, permission: Permission) -> QuerySet["User"]: + return self.filter( + Q(groups__permissions=permission) | Q(user_permissions=permission) + ).distinct() + def reviewers(self) -> QuerySet["User"]: - reviewers_group = Group.objects.get(name="Reviewer") - return reviewers_group.user_set.all() + permission = Permission.objects.get(codename="can_review_destruction") + return self._users_with_permission(permission) def archivists(self) -> QuerySet["User"]: - archivists_group = Group.objects.get(name="Archivist") - return archivists_group.user_set.all() + permission = Permission.objects.get(codename="can_review_final_list") + return self._users_with_permission(permission) diff --git a/backend/src/openarchiefbeheer/destruction/api/permissions.py b/backend/src/openarchiefbeheer/destruction/api/permissions.py index 0c8a08f90..f11eeb38d 100644 --- a/backend/src/openarchiefbeheer/destruction/api/permissions.py +++ b/backend/src/openarchiefbeheer/destruction/api/permissions.py @@ -9,17 +9,16 @@ class CanStartDestructionPermission(permissions.BasePermission): message = _("You are not allowed to create a destruction list.") def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") class CanReviewPermission(permissions.BasePermission): message = _("You are not allowed to review a destruction list.") def has_permission(self, request, view): - return request.user.role and ( - request.user.role.can_review_destruction - or request.user.role.can_review_final_list - ) + return request.user.has_perm( + "accounts.can_review_destruction" + ) or request.user.has_perm("accounts.can_review_final_list") class CanUpdateDestructionList(permissions.BasePermission): @@ -29,7 +28,7 @@ class CanUpdateDestructionList(permissions.BasePermission): ) def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") def has_object_permission(self, request, view, destruction_list): return ( @@ -45,7 +44,7 @@ class CanMarkListAsFinal(permissions.BasePermission): ) def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") def has_object_permission(self, request, view, destruction_list): return ( @@ -61,7 +60,7 @@ class CanTriggerDeletion(permissions.BasePermission): ) def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") def has_object_permission(self, request, view, destruction_list): return ( @@ -74,7 +73,7 @@ class CanReassignDestructionList(permissions.BasePermission): message = _("You are not allowed to reassign the destruction list.") def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") def has_object_permission(self, request, view, destruction_list): return request.user == destruction_list.author and destruction_list.status in [ @@ -87,7 +86,7 @@ class CanMarkAsReadyToReview(permissions.BasePermission): message = _("You are not allowed to mark this destruction list as ready to review.") def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") def has_object_permission(self, request, view, destruction_list): return ( @@ -100,7 +99,7 @@ class CanAbortDestruction(permissions.BasePermission): message = _("You are not allowed to stop the planned destruction of the list.") def has_permission(self, request, view): - return request.user.role and request.user.role.can_start_destruction + return request.user.has_perm("accounts.can_start_destruction") def has_object_permission(self, request, view, destruction_list): return ( diff --git a/backend/src/openarchiefbeheer/destruction/api/serializers.py b/backend/src/openarchiefbeheer/destruction/api/serializers.py index 6fa7acd80..230a901e7 100644 --- a/backend/src/openarchiefbeheer/destruction/api/serializers.py +++ b/backend/src/openarchiefbeheer/destruction/api/serializers.py @@ -44,7 +44,7 @@ class Meta: fields = ("user",) def validate_user(self, user: User) -> User: - if not user.role.can_review_destruction: + if not user.has_perm("accounts.can_review_destruction"): raise ValidationError( _( "The chosen user does not have the permission of reviewing a destruction list." @@ -68,18 +68,18 @@ def validate(self, attrs: dict) -> dict: class MarkAsFinalSerializer(serializers.Serializer): comment = serializers.CharField(allow_blank=True) user = serializers.PrimaryKeyRelatedField( - queryset=User.objects.all().select_related("role") + queryset=User.objects.all().prefetch_related("user_permissions") ) - def validate_user(self, value: User) -> User: - if not value.role.can_review_final_list: + def validate_user(self, user: User) -> User: + if not user.has_perm("accounts.can_review_final_list"): raise ValidationError( _( "The chosen user does not have the permission to review a final list." ) ) - return value + return user class DestructionListAssigneeReadSerializer(serializers.ModelSerializer): @@ -352,11 +352,11 @@ def validate(self, attrs: dict) -> dict: if ( ( destruction_list.status == ListStatus.ready_to_review - and not user.role.can_review_destruction + and not user.has_perm("accounts.can_review_destruction") ) or ( destruction_list.status == ListStatus.ready_for_archivist - and not user.role.can_review_final_list + and not user.has_perm("accounts.can_review_final_list") ) or destruction_list.status not in [ListStatus.ready_to_review, ListStatus.ready_for_archivist] diff --git a/backend/src/openarchiefbeheer/destruction/api/viewsets.py b/backend/src/openarchiefbeheer/destruction/api/viewsets.py index c0da957c6..4aee33b6f 100644 --- a/backend/src/openarchiefbeheer/destruction/api/viewsets.py +++ b/backend/src/openarchiefbeheer/destruction/api/viewsets.py @@ -217,12 +217,12 @@ class DestructionListViewSet( serializer_class = DestructionListWriteSerializer queryset = ( DestructionList.objects.all() - .select_related("author", "author__role", "assignee", "assignee__role") + .select_related("author", "assignee") .prefetch_related( Prefetch( "assignees", - queryset=DestructionListAssignee.objects.select_related( - "user", "user__role" + queryset=DestructionListAssignee.objects.prefetch_related( + "user__user_permissions" ).order_by("pk"), ) )