diff --git a/backend/src/openarchiefbeheer/accounts/admin.py b/backend/src/openarchiefbeheer/accounts/admin.py index c3c41f2b..d615d288 100644 --- a/backend/src/openarchiefbeheer/accounts/admin.py +++ b/backend/src/openarchiefbeheer/accounts/admin.py @@ -3,10 +3,9 @@ from django.contrib.auth.admin import UserAdmin as _UserAdmin from django.core.exceptions import PermissionDenied, ValidationError from django.urls import reverse_lazy -from django.utils.translation import gettext_lazy as _ from .forms import PreventPrivilegeEscalationMixin, UserChangeForm -from .models import Role, User +from .models import User from .utils import validate_max_user_permissions @@ -14,7 +13,6 @@ class UserAdmin(_UserAdmin): hijack_success_url = reverse_lazy("root") form = UserChangeForm - list_display = _UserAdmin.list_display + ("role",) def get_form(self, request, obj=None, **kwargs): ModelForm = super().get_form(request, obj, **kwargs) @@ -34,18 +32,3 @@ def user_change_password(self, request, id, form_url=""): raise PermissionDenied from exc return super().user_change_password(request, id, form_url) - - def get_fieldsets(self, request, obj=None): - fieldsets = super().get_fieldsets(request, obj) - return tuple(fieldsets) + ((_("Role"), {"fields": ("role",)}),) - - -@admin.register(Role) -class RoleAdmin(admin.ModelAdmin): - list_display = ( - "name", - "can_start_destruction", - "can_review_destruction", - "can_view_case_details", - "can_review_final_list", - ) diff --git a/backend/src/openarchiefbeheer/accounts/api/serializers.py b/backend/src/openarchiefbeheer/accounts/api/serializers.py index f9978b5a..13af868d 100644 --- a/backend/src/openarchiefbeheer/accounts/api/serializers.py +++ b/backend/src/openarchiefbeheer/accounts/api/serializers.py @@ -1,23 +1,49 @@ +from django.utils.translation import gettext_lazy as _ + +from drf_spectacular.utils import extend_schema_field from rest_framework import serializers -from ..models import Role, User +from ..models import User + +class RoleSerializer(serializers.Serializer): + can_start_destruction = serializers.BooleanField() + can_review_destruction = serializers.BooleanField() + can_review_final_list = serializers.BooleanField() -class RoleSerializer(serializers.ModelSerializer): class Meta: - model = Role fields = ( - "name", "can_start_destruction", "can_review_destruction", "can_review_final_list", - "can_view_case_details", ) class UserSerializer(serializers.ModelSerializer): - role = RoleSerializer() + role = serializers.SerializerMethodField( + help_text=_("The role of the user within the application logic."), + allow_null=True, + ) class Meta: model = User fields = ("pk", "username", "first_name", "last_name", "email", "role") + + @extend_schema_field(RoleSerializer) + def get_role(self, user: User) -> dict | None: + serializer = RoleSerializer( + data={ + "can_review_destruction": user.has_perm( + "accounts.can_review_destruction" + ), + "can_start_destruction": user.has_perm( + "accounts.can_start_destruction" + ), + "can_review_final_list": user.has_perm( + "accounts.can_review_final_list" + ), + } + ) + serializer.is_valid() + + return serializer.data diff --git a/backend/src/openarchiefbeheer/accounts/fixtures/permissions.json b/backend/src/openarchiefbeheer/accounts/fixtures/permissions.json new file mode 100644 index 00000000..725328e7 --- /dev/null +++ b/backend/src/openarchiefbeheer/accounts/fixtures/permissions.json @@ -0,0 +1,35 @@ +[ + { + "model": "auth.permission", + "fields": { + "name": "Can start destruction", + "content_type": [ + "accounts", + "user" + ], + "codename": "can_start_destruction" + } + }, + { + "model": "auth.permission", + "fields": { + "name": "Can review destruction", + "content_type": [ + "accounts", + "user" + ], + "codename": "can_review_destruction" + } + }, + { + "model": "auth.permission", + "fields": { + "name": "Can review final list", + "content_type": [ + "accounts", + "user" + ], + "codename": "can_review_final_list" + } + } +] \ No newline at end of file diff --git a/backend/src/openarchiefbeheer/accounts/managers.py b/backend/src/openarchiefbeheer/accounts/managers.py index a4dab7b9..c18e74f7 100644 --- a/backend/src/openarchiefbeheer/accounts/managers.py +++ b/backend/src/openarchiefbeheer/accounts/managers.py @@ -1,4 +1,10 @@ -from django.contrib.auth.models import BaseUserManager +from typing import TYPE_CHECKING + +from django.contrib.auth.models import BaseUserManager, Permission +from django.db.models import Q, QuerySet + +if TYPE_CHECKING: + from .models import User class UserManager(BaseUserManager): @@ -33,8 +39,15 @@ def create_superuser(self, username, email, password, **extra_fields): return self._create_user(username, email, password, **extra_fields) - def reviewers(self): - return self.select_related("role").filter(role__can_review_destruction=True) + 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"]: + permission = Permission.objects.get(codename="can_review_destruction") + return self._users_with_permission(permission) - def archivists(self): - return self.select_related("role").filter(role__can_review_final_list=True) + def archivists(self) -> QuerySet["User"]: + permission = Permission.objects.get(codename="can_review_final_list") + return self._users_with_permission(permission) diff --git a/backend/src/openarchiefbeheer/accounts/migrations/0004_add_groups_permissions.py b/backend/src/openarchiefbeheer/accounts/migrations/0004_add_groups_permissions.py new file mode 100644 index 00000000..3e157dc8 --- /dev/null +++ b/backend/src/openarchiefbeheer/accounts/migrations/0004_add_groups_permissions.py @@ -0,0 +1,58 @@ +# Generated by Django 4.2.15 on 2024-09-30 11:56 + +from django.db import migrations + +PERMISSIONS = { + "can_start_destruction": "Can start destruction", + "can_review_destruction": "Can review destruction", + "can_review_final_list": "Can review final list", +} + +GROUPS = { + "Record Manager": [ + "can_start_destruction", + ], + "Reviewer": [ + "can_review_destruction", + ], + "Archivist": [ + "can_review_final_list", + ], + "Administrator": [ + "can_start_destruction", + "can_review_destruction", + "can_review_final_list", + ], +} + + +def create_groups_permissions(apps, schema_editor): + User = apps.get_model("accounts", "User") + Group = apps.get_model("auth", "Group") + Permission = apps.get_model("auth", "Permission") + ContentType = apps.get_model("contenttypes", "ContentType") + + content_type = ContentType.objects.get_for_model(User) + for code_name, name in PERMISSIONS.items(): + Permission.objects.get_or_create( + codename=code_name, name=name, content_type=content_type + ) + + for group_name, permission_codenames in GROUPS.items(): + group, _ = Group.objects.get_or_create(name=group_name) + + for codename in permission_codenames: + permission = Permission.objects.get(codename=codename) + group.permissions.add(permission) + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0003_role_can_review_final_list"), + ("auth", "0012_alter_user_first_name_max_length"), + ] + + operations = [ + migrations.RunPython(create_groups_permissions, migrations.RunPython.noop), + ] diff --git a/backend/src/openarchiefbeheer/accounts/migrations/0005_add_users_to_groups.py b/backend/src/openarchiefbeheer/accounts/migrations/0005_add_users_to_groups.py new file mode 100644 index 00000000..5d1108d8 --- /dev/null +++ b/backend/src/openarchiefbeheer/accounts/migrations/0005_add_users_to_groups.py @@ -0,0 +1,101 @@ +# Generated by Django 4.2.15 on 2024-09-30 12:10 + +from django.db import migrations + + +def add_users_to_groups(apps, schema_editor): + User = apps.get_model("accounts", "User") + Group = apps.get_model("auth", "Group") + + administrators = User.objects.filter( + role__can_start_destruction=True, + role__can_review_destruction=True, + role__can_review_final_list=True, + ) + admin_group = Group.objects.get(name="Administrator") + for user in administrators: + user.groups.add(admin_group) + + record_managers = User.objects.filter( + role__can_start_destruction=True, + role__can_review_destruction=False, + role__can_review_final_list=False, + ) + record_manager_group = Group.objects.get(name="Record Manager") + for user in record_managers: + user.groups.add(record_manager_group) + + reviewers = User.objects.filter( + role__can_start_destruction=False, + role__can_review_destruction=True, + role__can_review_final_list=False, + ) + reviewer_group = Group.objects.get(name="Reviewer") + for user in reviewers: + user.groups.add(reviewer_group) + + archivists = User.objects.filter( + role__can_start_destruction=False, + role__can_review_destruction=False, + role__can_review_final_list=True, + ) + archivist_group = Group.objects.get(name="Archivist") + for user in archivists: + user.groups.add(archivist_group) + + +def add_role_to_users(apps, schema_editor): + User = apps.get_model("accounts", "User") + Role = apps.get_model("accounts", "Role") + + administrator, _ = Role.objects.get_or_create( + name="Administrator", + can_start_destruction=True, + can_review_destruction=True, + can_review_final_list=True, + ) + record_manager, _ = Role.objects.get_or_create( + name="Record Manager", + can_start_destruction=True, + can_review_destruction=False, + can_review_final_list=False, + ) + reviewer, _ = Role.objects.get_or_create( + name="Reviewer", + can_start_destruction=False, + can_review_destruction=True, + can_review_final_list=False, + ) + archivist, _ = Role.objects.get_or_create( + name="Archivist", + can_start_destruction=False, + can_review_destruction=False, + can_review_final_list=True, + ) + + users = User.objects.all() + + for user in users: + if user.groups.filter(name="Administrator").exists(): + user.role = administrator + elif user.groups.filter(name="Record Manager").exists(): + user.role = record_manager + elif user.groups.filter(name="Reviewer").exists(): + user.role = reviewer + elif user.groups.filter(name="Archivist").exists(): + user.role = archivist + else: + continue + + user.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0004_add_groups_permissions"), + ] + + operations = [ + migrations.RunPython(add_users_to_groups, add_role_to_users), + ] diff --git a/backend/src/openarchiefbeheer/accounts/migrations/0006_remove_user_role_delete_role.py b/backend/src/openarchiefbeheer/accounts/migrations/0006_remove_user_role_delete_role.py new file mode 100644 index 00000000..772f8418 --- /dev/null +++ b/backend/src/openarchiefbeheer/accounts/migrations/0006_remove_user_role_delete_role.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.15 on 2024-09-30 12:55 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("accounts", "0005_add_users_to_groups"), + ] + + operations = [ + migrations.RemoveField( + model_name="user", + name="role", + ), + migrations.DeleteModel( + name="Role", + ), + ] diff --git a/backend/src/openarchiefbeheer/accounts/models.py b/backend/src/openarchiefbeheer/accounts/models.py index 9c9257e3..f67dc0e5 100644 --- a/backend/src/openarchiefbeheer/accounts/models.py +++ b/backend/src/openarchiefbeheer/accounts/models.py @@ -43,13 +43,6 @@ class User(AbstractBaseUser, PermissionsMixin): ), ) date_joined = models.DateTimeField(_("date joined"), default=timezone.now) - role = models.ForeignKey( - "accounts.Role", - on_delete=models.SET_NULL, - blank=True, - null=True, - verbose_name=_("role"), - ) objects = UserManager() @@ -70,46 +63,3 @@ def get_full_name(self): def get_short_name(self): "Returns the short name for the user." return self.first_name - - -class Role(models.Model): - name = models.CharField( - _("name"), max_length=255, unique=True, help_text=_("Name of the role") - ) - can_start_destruction = models.BooleanField( - _("can start destruction"), - default=False, - help_text=_( - "Indicates whether a user can create a list of cases to be deleted." - ), - ) - can_review_final_list = models.BooleanField( - _("can review final list"), - default=False, - help_text=_( - "Indicates whether a user is an 'archivist'. " - "This user can only review lists that have been marked as 'final'." - ), - ) - can_review_destruction = models.BooleanField( - _("can review destruction"), - default=False, - help_text=_( - "Indicates whether a user can review a list of cases to be deleted. " - "They can approve it, reject it or provide feedback." - ), - ) - can_view_case_details = models.BooleanField( - _("can view case details"), - default=False, - help_text=_( - "Indicates whether a user can view the contents of cases in a lists." - ), - ) - - class Meta: - verbose_name = _("role") - verbose_name_plural = _("roles") - - def __str__(self): - return self.name diff --git a/backend/src/openarchiefbeheer/accounts/tests/factories.py b/backend/src/openarchiefbeheer/accounts/tests/factories.py index 9a897908..481c8483 100644 --- a/backend/src/openarchiefbeheer/accounts/tests/factories.py +++ b/backend/src/openarchiefbeheer/accounts/tests/factories.py @@ -1,26 +1,18 @@ from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission import factory +from factory import post_generation from factory.django import DjangoModelFactory -from ..models import Role - User = get_user_model() -class RoleFactory(DjangoModelFactory): - name = factory.Sequence(lambda n: f"Role {n}") - - class Meta: - model = Role - - class UserFactory(DjangoModelFactory): username = factory.Sequence(lambda n: f"user-{n}") first_name = factory.Faker("first_name") last_name = factory.Faker("last_name") password = factory.PostGenerationMethodCall("set_password", "password") - role = factory.SubFactory(RoleFactory) email = factory.Faker("email") class Meta: @@ -31,3 +23,15 @@ class Params: is_staff=True, is_superuser=True, ) + + @post_generation + def post(user, create, extracted, **kwargs): + if not create: + return + + for item, value in kwargs.items(): + if not value: + continue + + permission = Permission.objects.filter(codename=item).first() + user.user_permissions.add(permission) diff --git a/backend/src/openarchiefbeheer/accounts/tests/test_endpoints.py b/backend/src/openarchiefbeheer/accounts/tests/test_endpoints.py index 0f4ebecc..b9aee189 100644 --- a/backend/src/openarchiefbeheer/accounts/tests/test_endpoints.py +++ b/backend/src/openarchiefbeheer/accounts/tests/test_endpoints.py @@ -2,7 +2,7 @@ from rest_framework.reverse import reverse from rest_framework.test import APITestCase -from openarchiefbeheer.accounts.tests.factories import RoleFactory, UserFactory +from openarchiefbeheer.accounts.tests.factories import UserFactory class WhoAmIViewTest(APITestCase): @@ -14,8 +14,7 @@ def test_not_authenticated(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_authenticated(self): - role = RoleFactory.create() - user = UserFactory.create(role=role) + user = UserFactory.create(post__can_start_destruction=True) self.client.force_authenticate(user=user) endpoint = reverse("api:whoami") @@ -30,14 +29,8 @@ def test_authenticated(self): self.assertEqual(data["firstName"], user.first_name) self.assertEqual(data["lastName"], user.last_name) self.assertEqual(data["email"], user.email) - self.assertEqual(data["role"]["name"], role.name) - self.assertEqual( - data["role"]["canStartDestruction"], role.can_start_destruction - ) - self.assertEqual( - data["role"]["canReviewDestruction"], role.can_review_destruction - ) - self.assertEqual(data["role"]["canViewCaseDetails"], role.can_view_case_details) + self.assertTrue(data["role"]["canStartDestruction"]) + self.assertFalse(data["role"]["canReviewDestruction"]) def test_post(self): user = UserFactory.create() @@ -59,10 +52,10 @@ def test_not_authenticated_cant_access(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_get_archivists(self): - UserFactory.create_batch(2, role__can_review_final_list=True) - UserFactory.create_batch(3, role__can_review_final_list=False) + UserFactory.create_batch(2, post__can_review_final_list=True) + UserFactory.create_batch(3, post__can_review_final_list=False) - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) self.client.force_login(record_manager) response = self.client.get(reverse("api:archivists")) diff --git a/backend/src/openarchiefbeheer/accounts/tests/test_migrations.py b/backend/src/openarchiefbeheer/accounts/tests/test_migrations.py new file mode 100644 index 00000000..2d62556c --- /dev/null +++ b/backend/src/openarchiefbeheer/accounts/tests/test_migrations.py @@ -0,0 +1,87 @@ +from openarchiefbeheer.utils.tests.migrations_tests import TestMigrations + + +class TestAddGroups(TestMigrations): + app = "accounts" + migrate_from = "0003_role_can_review_final_list" + migrate_to = "0006_remove_user_role_delete_role" + + def setUpBeforeMigration(self, apps): + User = apps.get_model("accounts", "User") + Role = apps.get_model("accounts", "Role") + + administrator = Role.objects.get( + name="Administrator", + ) + record_manager = Role.objects.get( + name="Record Manager", + ) + reviewer = Role.objects.get( + name="Reviewer", + ) + archivist = Role.objects.get( + name="Archivist", + ) + + self.user_admin = User.objects.create(username="admin1", role=administrator) + self.user_record_manager = User.objects.create( + username="rm1", role=record_manager + ) + self.user_reviewer = User.objects.create(username="r1", role=reviewer) + self.user_archivist = User.objects.create(username="a1", role=archivist) + self.user_no_role = User.objects.create(username="no_role") + + def test_groups_and_permissions(self): + self.assertEqual(self.user_admin.groups.get().name, "Administrator") + self.assertEqual(self.user_record_manager.groups.get().name, "Record Manager") + self.assertEqual(self.user_reviewer.groups.get().name, "Reviewer") + self.assertEqual(self.user_archivist.groups.get().name, "Archivist") + self.assertFalse(self.user_no_role.groups.filter().exists()) + + +class TestReAddRoles(TestMigrations): + app = "accounts" + migrate_from = "0006_remove_user_role_delete_role" + migrate_to = "0003_role_can_review_final_list" + + def setUpBeforeMigration(self, apps): + User = apps.get_model("accounts", "User") + Group = apps.get_model("auth", "Group") + + administrator, _ = Group.objects.get_or_create( + name="Administrator", + ) + record_manager, _ = Group.objects.get_or_create( + name="Record Manager", + ) + reviewer, _ = Group.objects.get_or_create( + name="Reviewer", + ) + archivist, _ = Group.objects.get_or_create( + name="Archivist", + ) + + self.user_admin = User.objects.create(username="admin1") + self.user_admin.groups.add(administrator) + + self.user_record_manager = User.objects.create(username="rm1") + self.user_record_manager.groups.add(record_manager) + + self.user_reviewer = User.objects.create(username="r1") + self.user_reviewer.groups.add(reviewer) + + self.user_archivist = User.objects.create(username="a1") + self.user_archivist.groups.add(archivist) + + self.user_no_role = User.objects.create(username="no_role") + + def test_groups_and_permissions(self): + User = self.apps.get_model("accounts", "User") + + users = User.objects.all() + + self.assertEqual(users.get(username="admin1").role.name, "Administrator") + self.assertEqual(users.get(username="rm1").role.name, "Record Manager") + self.assertEqual(users.get(username="r1").role.name, "Reviewer") + self.assertEqual(users.get(username="a1").role.name, "Archivist") + self.assertIsNone(users.get(username="no_role").role) diff --git a/backend/src/openarchiefbeheer/api/tests/test_role_endpoints.py b/backend/src/openarchiefbeheer/api/tests/test_role_endpoints.py index 8c80ba70..92b0aa44 100644 --- a/backend/src/openarchiefbeheer/api/tests/test_role_endpoints.py +++ b/backend/src/openarchiefbeheer/api/tests/test_role_endpoints.py @@ -12,9 +12,9 @@ def test_user_not_logged_in(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_retrieve_reviewers(self): - admin = UserFactory.create(is_superuser=True, role=None) - UserFactory.create_batch(2, role__can_review_destruction=True) - UserFactory.create_batch(2, role__can_review_destruction=False) + admin = UserFactory.create(is_superuser=True) + UserFactory.create_batch(2, post__can_review_destruction=True) + UserFactory.create_batch(2, post__can_review_destruction=False) self.client.force_authenticate(user=admin) response = self.client.get(reverse("api:reviewers")) diff --git a/backend/src/openarchiefbeheer/config/tests/test_views.py b/backend/src/openarchiefbeheer/config/tests/test_views.py index 40add640..35d60c4d 100644 --- a/backend/src/openarchiefbeheer/config/tests/test_views.py +++ b/backend/src/openarchiefbeheer/config/tests/test_views.py @@ -25,7 +25,7 @@ def test_authenticated_can_retrieve(self): self.assertIn("zaaktypesShortProcess", response.json()) def test_not_record_manager_update(self): - user = UserFactory.create(role__can_start_destruction=False) + user = UserFactory.create(post__can_start_destruction=False) self.client.force_login(user) response = self.client.put( @@ -36,7 +36,7 @@ def test_not_record_manager_update(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_record_manager_update(self): - user = UserFactory.create(role__can_start_destruction=True) + user = UserFactory.create(post__can_start_destruction=True) self.client.force_login(user) response = self.client.put( @@ -51,7 +51,7 @@ def test_record_manager_update(self): self.assertEqual(config.zaaktypes_short_process, ["http://tralala.nl"]) def test_record_manager_partial_update(self): - user = UserFactory.create(role__can_start_destruction=True) + user = UserFactory.create(post__can_start_destruction=True) self.client.force_login(user) response = self.client.patch( @@ -68,7 +68,7 @@ def test_record_manager_partial_update(self): @tag("gh-227") @override_settings(SOLO_CACHE=None) def test_can_send_empty_list(self): - user = UserFactory.create(role__can_start_destruction=True) + user = UserFactory.create(post__can_start_destruction=True) config = ArchiveConfig.get_solo() config.zaaktypes_short_process = ["http://tralala.nl"] diff --git a/backend/src/openarchiefbeheer/destruction/api/permissions.py b/backend/src/openarchiefbeheer/destruction/api/permissions.py index 0c8a08f9..f11eeb38 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 bae6c941..47ae80cf 100644 --- a/backend/src/openarchiefbeheer/destruction/api/serializers.py +++ b/backend/src/openarchiefbeheer/destruction/api/serializers.py @@ -46,7 +46,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." @@ -70,18 +70,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): @@ -354,11 +354,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 c0da957c..4aee33b6 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"), ) ) diff --git a/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_process_review.py b/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_process_review.py index 35545fa4..fa7db3cf 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_process_review.py +++ b/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_process_review.py @@ -82,7 +82,7 @@ async def test_zaaktype_filters_on_process_review_page(self): @sync_to_async def create_data(): record_manager = UserFactory.create( - password="ANic3Password", role__can_start_destruction=True + password="ANic3Password", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( assignee=record_manager, @@ -174,7 +174,7 @@ def create_data(): async def test_zaak_removed_outside_process(self): @sync_to_async def create_data(): - record_manager = UserFactory.create(username="Record Manager", password="ANic3Password", role__can_start_destruction=True) + record_manager = UserFactory.create(username="Record Manager", password="ANic3Password", post__can_start_destruction=True) zaken = ZaakFactory.create_batch(2) list = DestructionListFactory.create( diff --git a/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_review.py b/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_review.py index cd5f2b5a..b2659b78 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_review.py +++ b/backend/src/openarchiefbeheer/destruction/tests/e2e/features/test_feature_list_review.py @@ -97,8 +97,8 @@ async def test_scenario_reviewer_rejects_list(self): async def test_scenario_reviewer_reviews_second_time(self): @sync_to_async def create_data(): - record_manager = UserFactory.create(role__can_start_destruction=True) - reviewer = UserFactory.create(username="Beoordelaar", password="ANic3Password", role__can_review_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) + reviewer = UserFactory.create(username="Beoordelaar", password="ANic3Password", post__can_review_destruction=True) zaken = ZaakFactory.create_batch(2) @@ -195,7 +195,7 @@ async def test_zaaktype_filters(self): @sync_to_async def create_data(): reviewer = UserFactory.create( - password="ANic3Password", role__can_review_destruction=True + password="ANic3Password", post__can_review_destruction=True ) destruction_list = DestructionListFactory.create( assignee=reviewer, @@ -275,8 +275,8 @@ def create_data(): async def test_zaak_removed_outside_process(self): @sync_to_async def create_data(): - record_manager = UserFactory.create(role__can_start_destruction=True) - reviewer = UserFactory.create(username="Beoordelaar", password="ANic3Password", role__can_review_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) + reviewer = UserFactory.create(username="Beoordelaar", password="ANic3Password", post__can_review_destruction=True) zaken = ZaakFactory.create_batch(2) list = DestructionListFactory.create( diff --git a/backend/src/openarchiefbeheer/destruction/tests/e2e/test_views.py b/backend/src/openarchiefbeheer/destruction/tests/e2e/test_views.py index 3c8e6b05..43ca0448 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/e2e/test_views.py +++ b/backend/src/openarchiefbeheer/destruction/tests/e2e/test_views.py @@ -14,7 +14,7 @@ async def test_login_redirects_to_destruction_list(self): @sync_to_async def _create_record_manager(): record_manager = UserFactory.create( - role__can_start_destruction=True, + post__can_start_destruction=True, password="ANic3Password", ) return record_manager diff --git a/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_abort_destruction.py b/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_abort_destruction.py index 5b13d580..13cd3a9e 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_abort_destruction.py +++ b/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_abort_destruction.py @@ -16,7 +16,7 @@ class DestructionListAbortDestructionEndpointTest(APITestCase): def test_only_author_can_abort(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -39,7 +39,7 @@ def test_only_author_can_abort(self): def test_only_ready_to_delete_with_planned_date_can_be_aborted(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -63,7 +63,7 @@ def test_only_ready_to_delete_with_planned_date_can_be_aborted(self): def test_cannot_abort_without_comment(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -88,7 +88,7 @@ def test_cannot_abort_without_comment(self): def test_abort_list_destruction(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", diff --git a/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_list_destruction.py b/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_list_destruction.py index 61ed360b..6499dc6d 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_list_destruction.py +++ b/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_list_destruction.py @@ -17,7 +17,7 @@ class DestructionListStartDestructionEndpointTest(APITestCase): def test_plan_destruction(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -47,7 +47,7 @@ def test_retry_destruction_after_failure_queues_immediately( self, ): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -83,7 +83,7 @@ def test_retry_destruction_after_failure_with_planned_date_in_future_raises_erro ): """This scenario should never happen unless someone manually changes the planned destruction date.""" record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -110,7 +110,7 @@ def test_retry_destruction_after_failure_with_planned_date_in_future_raises_erro ) def test_cannot_start_destruction_if_not_author(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( name="A test list", contains_sensitive_info=True, @@ -131,7 +131,7 @@ def test_cannot_start_destruction_if_not_author(self): m_task.assert_not_called() def test_cannot_start_destruction_if_not_ready_to_delete(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( name="A test list", contains_sensitive_info=True, @@ -154,7 +154,7 @@ def test_cannot_start_destruction_if_not_ready_to_delete(self): def test_cannot_start_destruction_if_archiefactiedatum_in_the_future(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -193,7 +193,7 @@ def test_cannot_start_destruction_if_archiefactiedatum_in_the_future(self): def test_can_start_destruction_if_archiefactiedatum_in_the_future_but_removed(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", diff --git a/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_reviewresponse.py b/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_reviewresponse.py index 38ede9c3..20063ed9 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_reviewresponse.py +++ b/backend/src/openarchiefbeheer/destruction/tests/endpoints/test_reviewresponse.py @@ -54,7 +54,7 @@ def test_filter_on_review(self): self.assertEqual(len(data[0]["itemsResponses"]), 2) def test_create_review_response(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, @@ -133,8 +133,8 @@ def test_create_review_response(self): self.assertEqual(item_response3.action_zaak["archiefactiedatum"], "2030-01-01") def test_cannot_create_response_if_not_author(self): - record_manager1 = UserFactory.create(role__can_start_destruction=True) - record_manager2 = UserFactory.create(role__can_start_destruction=True) + record_manager1 = UserFactory.create(post__can_start_destruction=True) + record_manager2 = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager1, @@ -165,7 +165,7 @@ def test_cannot_create_response_if_not_author(self): ) def test_cannot_create_response_if_not_changes_requested(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, @@ -198,14 +198,14 @@ def test_cannot_create_response_if_not_changes_requested(self): @freezegun.freeze_time("2023-09-15T21:36:00+02:00") def test_audit_log(self): # Reassign - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( name="Test audittrail", status=ListStatus.ready_to_review, author=record_manager, ) DestructionListAssigneeFactory.create(destruction_list=destruction_list) - other_reviewer = UserFactory.create(role__can_review_destruction=True) + other_reviewer = UserFactory.create(post__can_review_destruction=True) self.client.force_authenticate(user=record_manager) endpoint_reassign = reverse( diff --git a/backend/src/openarchiefbeheer/destruction/tests/factories.py b/backend/src/openarchiefbeheer/destruction/tests/factories.py index eab5d17d..8df064e0 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/factories.py +++ b/backend/src/openarchiefbeheer/destruction/tests/factories.py @@ -1,9 +1,13 @@ +from django.contrib.auth.models import Permission + import factory.fuzzy from factory import post_generation from openarchiefbeheer.accounts.tests.factories import UserFactory from openarchiefbeheer.zaken.tests.factories import ZaakFactory +from ..constants import ListRole + class DestructionListFactory(factory.django.DjangoModelFactory): name = factory.Faker("word") @@ -14,6 +18,14 @@ class Meta: model = "destruction.DestructionList" django_get_or_create = ("name",) + @post_generation + def post(destruction_list, create, extracted, **kwargs): + if not create: + return + + permission = Permission.objects.get(codename="can_start_destruction") + destruction_list.author.user_permissions.add(permission) + class DestructionListAssigneeFactory(factory.django.DjangoModelFactory): destruction_list = factory.SubFactory(DestructionListFactory) @@ -22,6 +34,22 @@ class DestructionListAssigneeFactory(factory.django.DjangoModelFactory): class Meta: model = "destruction.DestructionListAssignee" + @post_generation + def post(assignee, create, extracted, **kwargs): + if not create: + return + + match (assignee.role): + case ListRole.author: + permission = Permission.objects.get(codename="can_start_destruction") + assignee.user.user_permissions.add(permission) + case ListRole.reviewer: + permission = Permission.objects.get(codename="can_review_destruction") + assignee.user.user_permissions.add(permission) + case ListRole.archivist: + permission = Permission.objects.get(codename="can_review_final_list") + assignee.user.user_permissions.add(permission) + class DestructionListItemFactory(factory.django.DjangoModelFactory): destruction_list = factory.SubFactory(DestructionListFactory) diff --git a/backend/src/openarchiefbeheer/destruction/tests/serializers/test_reviewresponse.py b/backend/src/openarchiefbeheer/destruction/tests/serializers/test_reviewresponse.py index 7cf3aa5b..9a448095 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/serializers/test_reviewresponse.py +++ b/backend/src/openarchiefbeheer/destruction/tests/serializers/test_reviewresponse.py @@ -17,7 +17,7 @@ class ReviewResponseSerializerTests(TestCase): def test_rejecting_suggestion_cannot_have_zaak_action(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, @@ -53,7 +53,7 @@ def test_rejecting_suggestion_cannot_have_zaak_action(self): ) def test_bewaartermijn_zaak_action_cannot_change_selectielijst(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, @@ -92,7 +92,7 @@ def test_bewaartermijn_zaak_action_cannot_change_selectielijst(self): ) def test_selectielijst_zaak_action_requires_selectielijst(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, @@ -130,7 +130,7 @@ def test_selectielijst_zaak_action_requires_selectielijst(self): ) def test_update_archiefactiedatum_selectielijst_api_error(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_assignement_logic.py b/backend/src/openarchiefbeheer/destruction/tests/test_assignement_logic.py index 470c6f57..8c0940bd 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_assignement_logic.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_assignement_logic.py @@ -175,7 +175,7 @@ def test_archivist_accepts(self): self.assertEqual(destruction_list.assignee, record_manager.user) def test_reassign_reviewer_ready_to_review(self): - reviewer_old = UserFactory.create(role__can_review_destruction=True) + reviewer_old = UserFactory.create(post__can_review_destruction=True) destruction_list = DestructionListFactory.create( status=ListStatus.ready_to_review, assignee=reviewer_old ) @@ -191,7 +191,7 @@ def test_reassign_reviewer_ready_to_review(self): self.assertEqual(destruction_list.assignee, assignee_new.user) def test_reassign_reviewer_noop(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( status=ListStatus.new, assignee=record_manager, author=record_manager ) diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_endpoints.py b/backend/src/openarchiefbeheer/destruction/tests/test_endpoints.py index c158f609..0cfbad70 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_endpoints.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_endpoints.py @@ -45,7 +45,7 @@ def test_not_authenticated(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_authenticated_without_permission(self): - user = UserFactory.create(role__can_start_destruction=False) + user = UserFactory.create(post__can_start_destruction=False) self.client.force_authenticate(user=user) endpoint = reverse("api:destructionlist-list") @@ -56,10 +56,10 @@ def test_authenticated_without_permission(self): def test_create_destruction_list(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) ZaakFactory.create( url="http://localhost:8003/zaken/api/v1/zaken/111-111-111", @@ -136,9 +136,9 @@ def test_list_destruction_lists(self): self.assertEqual(len(response.json()), 3) def test_zaak_already_in_another_destruction_list(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) DestructionListItemFactory.create( with_zaak=True, @@ -199,9 +199,9 @@ def test_zaak_already_in_another_destruction_list(self): self.assertFalse(DestructionList.objects.filter(name="A test list").exists()) def test_update_destruction_list(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) ZaakFactory.create( url="http://localhost:8003/zaken/api/v1/zaken/111-111-111", @@ -254,7 +254,7 @@ def test_update_destruction_list(self): self.assertEqual(destruction_list.items.all().count(), 1) def test_cannot_update_destruction_list_if_not_new(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( name="A test list", @@ -278,8 +278,8 @@ def test_cannot_update_destruction_list_if_not_new(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_cannot_update_destruction_list_if_not_author(self): - record_manager1 = UserFactory.create(role__can_start_destruction=True) - record_manager2 = UserFactory.create(role__can_start_destruction=True) + record_manager1 = UserFactory.create(post__can_start_destruction=True) + record_manager2 = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( name="A test list", @@ -303,14 +303,14 @@ def test_cannot_update_destruction_list_if_not_author(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_cannot_reassign_destruction_list_if_not_record_manager(self): - not_record_manager = UserFactory.create(role__can_start_destruction=False) + not_record_manager = UserFactory.create(post__can_start_destruction=False) destruction_list = DestructionListFactory.create( status=ListStatus.ready_to_review, ) DestructionListAssigneeFactory.create_batch( 2, destruction_list=destruction_list ) - other_reviewers = UserFactory.create_batch(2, role__can_review_destruction=True) + other_reviewers = UserFactory.create_batch(2, post__can_review_destruction=True) self.client.force_authenticate(user=not_record_manager) endpoint = reverse( @@ -326,8 +326,8 @@ def test_cannot_reassign_destruction_list_if_not_record_manager(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_cannot_reassign_destruction_list_without_comment(self): - record_manager = UserFactory.create(role__can_start_destruction=True) - reviewer = UserFactory.create(role__can_review_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) + reviewer = UserFactory.create(post__can_review_destruction=True) destruction_list = DestructionListFactory.create( author=record_manager, status=ListStatus.new, @@ -354,9 +354,9 @@ def test_cannot_reassign_destruction_list_without_comment(self): self.assertEqual(response.json()["comment"][0], _("This field is required.")) def test_cannot_reassign_destruction_list_with_empty_comment(self): - record_manager1 = UserFactory.create(role__can_start_destruction=True) + record_manager1 = UserFactory.create(post__can_start_destruction=True) reviewer = DestructionListAssigneeFactory.create( - user__role__can_review_destruction=True + user__post__can_review_destruction=True ) destruction_list = DestructionListFactory.create( @@ -387,7 +387,7 @@ def test_cannot_reassign_destruction_list_with_empty_comment(self): def test_cannot_reassign_destruction_list_with_author_as_reviewer(self): record_manager = UserFactory.create( - role__can_start_destruction=True, role__can_review_destruction=True + post__can_start_destruction=True, post__can_review_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -418,12 +418,12 @@ def test_cannot_reassign_destruction_list_with_author_as_reviewer(self): ) def test_reassign_destruction_list(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( status=ListStatus.ready_to_review, author=record_manager ) DestructionListAssigneeFactory.create(destruction_list=destruction_list) - other_reviewer = UserFactory.create(role__can_review_destruction=True) + other_reviewer = UserFactory.create(post__can_review_destruction=True) self.client.force_authenticate(user=record_manager) endpoint = reverse( @@ -457,9 +457,9 @@ def test_reassign_destruction_list(self): self.assertEqual(log_entry.extra_data["comment"], "Lorem ipsum...") def test_partially_update_destruction_list(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) destruction_list = DestructionListFactory.create( @@ -523,10 +523,10 @@ def test_destruction_list_filter_on_assignee(self): def test_mark_as_final(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) archivist = UserFactory.create( - username="archivist", role__can_review_final_list=True + username="archivist", post__can_review_final_list=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -599,10 +599,10 @@ def test_cannot_mark_as_final_if_not_authenticated(self): def test_cannot_mark_as_final_if_not_author(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) archivist = UserFactory.create( - username="archivist", role__can_review_final_list=True + username="archivist", post__can_review_final_list=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -624,10 +624,10 @@ def test_cannot_mark_as_final_if_not_author(self): def test_cannot_mark_as_finally_if_not_internally_reviewed(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) archivist = UserFactory.create( - username="archivist", role__can_review_final_list=True + username="archivist", post__can_review_final_list=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -650,10 +650,10 @@ def test_cannot_mark_as_finally_if_not_internally_reviewed(self): def test_cannot_mark_as_final_if_posted_user_is_not_archivist(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) internal_reviewer = UserFactory.create( - username="archivist", role__can_review_final_list=False + username="archivist", post__can_review_final_list=False ) destruction_list = DestructionListFactory.create( name="A test list", @@ -679,7 +679,7 @@ def test_cannot_mark_as_final_if_posted_user_is_not_archivist(self): ) def test_mark_as_ready_to_review(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) destruction_list = DestructionListFactory.create( name="A test list", @@ -692,7 +692,7 @@ def test_mark_as_ready_to_review(self): reviewer = DestructionListAssigneeFactory.create( destruction_list=destruction_list, role=ListRole.reviewer, - user__role__can_review_destruction=True, + user__post__can_review_destruction=True, ) self.client.force_authenticate(user=record_manager) @@ -741,7 +741,7 @@ def test_cannot_mark_as_ready_to_review_if_not_authenticated(self): def test_cannot_mark_as_ready_to_review_if_not_author(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", @@ -952,7 +952,7 @@ def test_create_review(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -989,7 +989,7 @@ def test_create_review_rejected(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -1041,7 +1041,7 @@ def test_create_review_archivist_accepted(self): archivist = UserFactory.create( username="archivaris", email="archivaris@oab.nl", - role__can_review_final_list=True, + post__can_review_final_list=True, ) destruction_list = DestructionListFactory.create( assignee=archivist, status=ListStatus.ready_for_archivist @@ -1078,7 +1078,7 @@ def test_create_review_archivist_rejected(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_final_list=True, + post__can_review_final_list=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_for_archivist @@ -1176,7 +1176,7 @@ def test_create_review_accepted_long_procedure(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -1235,7 +1235,7 @@ def test_create_review_accepted_short_procedure(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_serializers.py b/backend/src/openarchiefbeheer/destruction/tests/test_serializers.py index 66be9fb5..e0936b44 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_serializers.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_serializers.py @@ -36,10 +36,10 @@ def test_create_destruction_list(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) ZaakFactory.create( url="http://localhost:8003/zaken/api/v1/zaken/111-111-111", @@ -114,10 +114,10 @@ def test_create_destruction_list(self): def test_zaak_already_included_in_other_list(self): reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) ZaakFactory.create( @@ -167,10 +167,10 @@ def test_zaak_already_included_in_other_list(self): def test_zaak_already_included_in_other_list_but_exempt(self): reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) ZaakFactory.create( @@ -209,7 +209,7 @@ def test_zaak_already_included_in_other_list_but_exempt(self): def test_full_list_update(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( @@ -267,7 +267,7 @@ def test_full_list_update(self): def test_partial_list_update(self): reviewer = UserFactory.create( - username="reviewer", role__can_review_destruction=True + username="reviewer", post__can_review_destruction=True ) destruction_list = DestructionListFactory.create( @@ -288,7 +288,7 @@ def test_partial_list_update(self): } record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) request = factory.get("/foo") request.user = record_manager @@ -326,7 +326,7 @@ def test_partial_update_with_zaken(self): "items": [{"zaak": items[0].zaak.url}, {"zaak": items[1].zaak.url}], } - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) request = factory.get("/foo") request.user = record_manager @@ -352,8 +352,8 @@ def test_partial_update_with_zaken(self): def test_assign_author_as_reviewer(self): record_manager = UserFactory.create( username="record_manager", - role__can_start_destruction=True, - role__can_review_destruction=True, + post__can_start_destruction=True, + post__can_review_destruction=True, ) ZaakFactory.create(url="http://localhost:8003/zaken/api/v1/zaken/111-111-111") ZaakFactory.create(url="http://localhost:8003/zaken/api/v1/zaken/222-222-222") @@ -391,10 +391,10 @@ def test_create_list_with_bulk_select_cases(self): reviewer = UserFactory.create( username="reviewer1", email="reviewer1@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) ZaakFactory.create( url="http://localhost:8003/zaken/api/v1/zaken/111-111-111", @@ -453,10 +453,10 @@ def test_create_list_with_bulk_select_cases_no_filters(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) ZaakFactory.create( url="http://localhost:8003/zaken/api/v1/zaken/111-111-111", @@ -497,10 +497,10 @@ def test_no_bulk_select_and_no_items(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) request = factory.get("/foo") @@ -529,10 +529,10 @@ def test_zaak_filters_validation(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) request = factory.get("/foo") @@ -580,7 +580,7 @@ def test_zaak_filters_validation(self): def test_update_with_bulk_select(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( @@ -645,12 +645,12 @@ def test_if_user_not_assigned_cannot_create_review(self): reviewer1 = UserFactory.create( username="reviewer1", email="reviewer1@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) reviewer2 = UserFactory.create( username="reviewer2", email="reviewer2@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create(assignee=reviewer1) @@ -679,8 +679,8 @@ def test_if_list_in_wrong_status_cannot_be_reviewed(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, - role__can_review_final_list=True, + post__can_review_destruction=True, + post__can_review_final_list=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.changes_requested @@ -710,7 +710,7 @@ def test_if_user_not_a_reviewer_cannot_create_review(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=False, + post__can_review_destruction=False, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -740,7 +740,7 @@ def test_if_user_not_an_archivist_cannot_create_review(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_final_list=False, + post__can_review_final_list=False, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_for_archivist @@ -769,7 +769,7 @@ def test_create_review_accepted(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, @@ -828,7 +828,7 @@ def test_create_review_accepted_cannot_have_item_reviews(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -865,7 +865,7 @@ def test_create_review_rejected_must_have_item_reviews(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -893,7 +893,7 @@ def test_create_review_rejected(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, name="Test list", status=ListStatus.ready_to_review @@ -956,7 +956,7 @@ def test_reviewing_cases_not_in_destruction_list(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review @@ -996,7 +996,7 @@ def test_reviewing_cases_removed_from_destruction_list(self): reviewer = UserFactory.create( username="reviewer", email="reviewer@oab.nl", - role__can_review_destruction=True, + post__can_review_destruction=True, ) destruction_list = DestructionListFactory.create( assignee=reviewer, status=ListStatus.ready_to_review diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py b/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py index 6517f1e8..e64cb443 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_tasks.py @@ -429,7 +429,7 @@ def mock_exceptions(zaak, result_store): @override_settings(CELERY_TASK_ALWAYS_EAGER=True) def test_deleting_list_with_zaken_archiefactiedatum_in_the_future(self): record_manager = UserFactory.create( - username="record_manager", role__can_start_destruction=True + username="record_manager", post__can_start_destruction=True ) destruction_list = DestructionListFactory.create( name="A test list", diff --git a/backend/src/openarchiefbeheer/destruction/tests/test_utils.py b/backend/src/openarchiefbeheer/destruction/tests/test_utils.py index e45291c4..10f8cdbe 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/test_utils.py +++ b/backend/src/openarchiefbeheer/destruction/tests/test_utils.py @@ -19,7 +19,7 @@ def test_process_assignees(self): 3, role=ListRole.reviewer, destruction_list=destruction_list ) - new_reviewer = UserFactory.create(role__can_review_destruction=True) + new_reviewer = UserFactory.create(post__can_review_destruction=True) process_new_reviewer(destruction_list, new_reviewer) diff --git a/backend/src/openarchiefbeheer/destruction/tests/vcr/test_serializers.py b/backend/src/openarchiefbeheer/destruction/tests/vcr/test_serializers.py index a9aeacd7..8599d74b 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/vcr/test_serializers.py +++ b/backend/src/openarchiefbeheer/destruction/tests/vcr/test_serializers.py @@ -30,7 +30,7 @@ def setUpClass(cls) -> None: ) def test_new_selectielijst_blijvend_bewaren(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, @@ -74,7 +74,7 @@ def test_new_selectielijst_blijvend_bewaren(self): ) def test_selectielijst_blijvend_bewaren_update_archiefactiedatum(self): - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) review = DestructionListReviewFactory.create( destruction_list__author=record_manager, destruction_list__status=ListStatus.changes_requested, diff --git a/backend/src/openarchiefbeheer/destruction/tests/vcr/test_tasks.py b/backend/src/openarchiefbeheer/destruction/tests/vcr/test_tasks.py index b02c7001..608bd089 100644 --- a/backend/src/openarchiefbeheer/destruction/tests/vcr/test_tasks.py +++ b/backend/src/openarchiefbeheer/destruction/tests/vcr/test_tasks.py @@ -40,9 +40,9 @@ def test_process_response(self): with freeze_time("2024-08-29T16:00:00+02:00"): retrieve_and_cache_zaken_from_openzaak() - record_manager = UserFactory.create(role__can_start_destruction=True) + record_manager = UserFactory.create(post__can_start_destruction=True) reviewer = UserFactory.create( - role__can_review_destruction=True, + post__can_review_destruction=True, ) zaak = Zaak.objects.get(identificatie="ZAAK-01") diff --git a/backend/src/openarchiefbeheer/fixtures/default_admin_index.json b/backend/src/openarchiefbeheer/fixtures/default_admin_index.json index f999e7bd..93482bb2 100644 --- a/backend/src/openarchiefbeheer/fixtures/default_admin_index.json +++ b/backend/src/openarchiefbeheer/fixtures/default_admin_index.json @@ -19,7 +19,7 @@ "slug": "users", "models": [ ["accounts", "user"], - ["accounts", "role"] + ["auth", "group"] ] } }, diff --git a/backend/src/openarchiefbeheer/fixtures/roles.json b/backend/src/openarchiefbeheer/fixtures/roles.json deleted file mode 100644 index 796cdb3c..00000000 --- a/backend/src/openarchiefbeheer/fixtures/roles.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "model": "accounts.role", - "pk": 1, - "fields": { - "name": "Record manager", - "can_start_destruction": true, - "can_review_final_list": false, - "can_review_destruction": false, - "can_view_case_details": false - } - }, - { - "model": "accounts.role", - "pk": 2, - "fields": { - "name": "Reviewer", - "can_start_destruction": false, - "can_review_final_list": false, - "can_review_destruction": true, - "can_view_case_details": false - } - }, - { - "model": "accounts.role", - "pk": 3, - "fields": { - "name": "Admin", - "can_start_destruction": true, - "can_review_final_list": false, - "can_review_destruction": true, - "can_view_case_details": true - } - } -] - \ No newline at end of file diff --git a/backend/src/openarchiefbeheer/utils/tests/e2e.py b/backend/src/openarchiefbeheer/utils/tests/e2e.py index 6059f03a..0302d6e3 100644 --- a/backend/src/openarchiefbeheer/utils/tests/e2e.py +++ b/backend/src/openarchiefbeheer/utils/tests/e2e.py @@ -46,6 +46,7 @@ async def browser_page_with_tracing(): class PlaywrightTestCase(StaticLiveServerTestCase): port = settings.E2E_PORT + fixtures = ["permissions.json"] def setUp(self): super().setUp() diff --git a/backend/src/openarchiefbeheer/utils/tests/gherkin.py b/backend/src/openarchiefbeheer/utils/tests/gherkin.py index 46a69846..df0ed287 100644 --- a/backend/src/openarchiefbeheer/utils/tests/gherkin.py +++ b/backend/src/openarchiefbeheer/utils/tests/gherkin.py @@ -99,7 +99,7 @@ async def record_manager_exists(self, **kwargs): "username": "Record Manager", "first_name": "Record", "last_name": "Manager", - "role__can_start_destruction": True, + "post__can_start_destruction": True, } merged_kwargs = {**base_kwargs, **kwargs} return await self.user_exists(**merged_kwargs) @@ -109,7 +109,7 @@ async def reviewer_exists(self, **kwargs): "username": "Beoordelaar", "first_name": "Beoor", "last_name": "del Laar", - "role__can_review_destruction": True, + "post__can_review_destruction": True, } merged_kwargs = {**base_kwargs, **kwargs} return await self.user_exists(**merged_kwargs) @@ -119,7 +119,7 @@ async def archivist_exists(self, **kwargs): "username": "Achivaris", "first_name": "Archi", "last_name": "Varis", - "role__can_review_final_list": True, + "post__can_review_final_list": True, } merged_kwargs = {**base_kwargs, **kwargs} return await self.user_exists(**merged_kwargs) @@ -256,7 +256,15 @@ async def _get_or_create(self, factory, **kwargs): get_kwargs = kwargs.copy() if "password" in get_kwargs: get_kwargs.pop("password") - return await self._orm_get(factory._meta.model, **get_kwargs) + + # Remove any traits/postgeneration attributes of the factory + orm_params = { + key: value + for key, value in get_kwargs.items() + if key not in factory._meta.parameters + and not key.startswith("post__") + } + return await self._orm_get(factory._meta.model, **orm_params) except factory._meta.model.DoesNotExist: return await self._factory_create(factory, **kwargs) diff --git a/backend/src/openarchiefbeheer/zaken/tests/test_filtersets.py b/backend/src/openarchiefbeheer/zaken/tests/test_filtersets.py index d411f9fe..5f2eb72c 100644 --- a/backend/src/openarchiefbeheer/zaken/tests/test_filtersets.py +++ b/backend/src/openarchiefbeheer/zaken/tests/test_filtersets.py @@ -26,7 +26,7 @@ def test_filter_out_zaken_already_in_destruction_lists(self): # This zaak SHOULD be returned by the endpoint (it was included in a destruction list, but was then excluded) DestructionListItemFactory.create(status=ListItemStatus.removed, with_zaak=True) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["not_in_destruction_list"] = "True" @@ -46,7 +46,7 @@ def test_using_query_params_to_filter(self): ZaakFactory.create_batch(2, startdatum=date(2020, 1, 1)) recent_zaken = ZaakFactory.create_batch(3, startdatum=date(2022, 1, 1)) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["startdatum__gt"] = "2021-01-01" @@ -90,7 +90,7 @@ def test_filter_resultaattype(self): }, ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["_expand__resultaat__resultaattype"] = ( @@ -122,7 +122,7 @@ def test_filter_bewaartermijn(self): }, ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["bewaartermijn"] = "P1D" @@ -142,7 +142,7 @@ def test_filter_vcs(self): 2, post___expand={"zaaktype": {"selectielijst_procestype": {"nummer": 2}}} ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["vcs"] = 1 @@ -168,7 +168,7 @@ def test_filter_heeft_relaties(self): ) no_relations_zaken = ZaakFactory.create_batch(2, relevante_andere_zaken=[]) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["heeft_relaties"] = True @@ -212,7 +212,7 @@ def test_partial_filter(self): post___expand={"zaaktype": {"omschrijving": "Aangifte behandelen"}}, ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["identificatie__icontains"] = "ABC" @@ -240,7 +240,7 @@ def test_filter_out_zaken_already_in_destruction_lists_except_one(self): status=ListItemStatus.suggested, with_zaak=True ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["not_in_destruction_list_except"] = item.destruction_list.uuid @@ -311,7 +311,7 @@ def test_filter_behandelend_afdeling(self): } ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["behandelend_afdeling__icontains"] = "BLA" @@ -328,7 +328,7 @@ def test_ordering(self): zaak_1 = ZaakFactory.create(identificatie="ZAAK-0000-0000000001") zaak_3 = ZaakFactory.create(identificatie="ZAAK-0000-0000000003") - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) self.client.force_authenticate(user) @@ -375,7 +375,7 @@ def test_filter_on_destruction_list(self): destruction_list=destruction_list, ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["in_destruction_list"] = destruction_list.uuid @@ -392,7 +392,7 @@ def test_filter_on_zaaktype(self): ZaakFactory.create_batch(3, identificatie="ZAAK-01") zaken_2 = ZaakFactory.create_batch(2, identificatie="ZAAK-02") - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) endpoint = furl(reverse("api:zaken-list")) endpoint.args["zaaktype__in"] = ",".join( diff --git a/backend/src/openarchiefbeheer/zaken/tests/test_tasks.py b/backend/src/openarchiefbeheer/zaken/tests/test_tasks.py index c61f85ba..ee446cac 100644 --- a/backend/src/openarchiefbeheer/zaken/tests/test_tasks.py +++ b/backend/src/openarchiefbeheer/zaken/tests/test_tasks.py @@ -347,6 +347,10 @@ def test_retrieve_zaken_with_geometry(self, m): @Mocker() class RetrieveCachedZakenWithProcestypeTest(TransactionTestCase): + # Needed, because the test teardown calls the management command "flush", which + # removes the permissions created with the data migration from the db. + fixtures = ["permissions.json"] + def setUp(self): super().setUp() diff --git a/backend/src/openarchiefbeheer/zaken/tests/test_views.py b/backend/src/openarchiefbeheer/zaken/tests/test_views.py index 11551374..c44e9ad7 100644 --- a/backend/src/openarchiefbeheer/zaken/tests/test_views.py +++ b/backend/src/openarchiefbeheer/zaken/tests/test_views.py @@ -423,7 +423,7 @@ def test_retrieve_choices(self, m): api_type=APITypes.orc, api_root="http://selectielijst.nl/api/v1", ) - user = UserFactory.create(role__can_start_destruction=True) + user = UserFactory.create(post__can_start_destruction=True) zaak = ZaakFactory.create() process_type_url = zaak._expand["zaaktype"]["selectielijst_procestype"]["url"] @@ -505,7 +505,7 @@ def test_retrieve_choices_without_zaak(self, m): ) # Create a user with the appropriate role - user = UserFactory.create(role__can_start_destruction=True) + user = UserFactory.create(post__can_start_destruction=True) # Mock the response from the external API m.get( @@ -587,7 +587,7 @@ def test_response_cached(self, m): api_type=APITypes.orc, api_root="http://selectielijst.nl/api/v1", ) - user = UserFactory.create(role__can_start_destruction=True) + user = UserFactory.create(post__can_start_destruction=True) zaak = ZaakFactory.create() process_type_url = zaak._expand["zaaktype"]["selectielijst_procestype"]["url"] diff --git a/backend/src/openarchiefbeheer/zaken/tests/test_viewsets.py b/backend/src/openarchiefbeheer/zaken/tests/test_viewsets.py index 7c9e9d67..02461d92 100644 --- a/backend/src/openarchiefbeheer/zaken/tests/test_viewsets.py +++ b/backend/src/openarchiefbeheer/zaken/tests/test_viewsets.py @@ -25,7 +25,7 @@ def test_not_authenticated(self): self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) def test_authenticated_without_permission(self): - user = UserFactory.create(role__can_start_destruction=False) + user = UserFactory.create(post__can_start_destruction=False) self.client.force_authenticate(user=user) endpoint = reverse("api:zaken-list") @@ -37,7 +37,7 @@ def test_authenticated_without_permission(self): def test_retrieve_all_zaken_as_record_manager(self): ZaakFactory.create_batch(4) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) self.client.force_authenticate(user) response = self.client.get(reverse("api:zaken-list")) @@ -49,7 +49,7 @@ def test_retrieve_all_zaken_as_record_manager(self): def test_retrieve_all_zaken_as_reviewer(self): ZaakFactory.create_batch(4) - user = UserFactory(username="reviewer", role__can_review_destruction=True) + user = UserFactory(username="reviewer", post__can_review_destruction=True) self.client.force_authenticate(user) response = self.client.get(reverse("api:zaken-list")) @@ -68,7 +68,7 @@ def test_retrieve_all_zaken_with_removed_zaken(self): processing_status=InternalStatus.succeeded, ) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) self.client.force_authenticate(user) @@ -94,7 +94,7 @@ def test_filter_zaken_with_removed_zaken(self): for zaak in zaken_in_list: DestructionListItemFactory.create(destruction_list=list, zaak=zaak) - user = UserFactory(username="record_manager", role__can_start_destruction=True) + user = UserFactory(username="record_manager", post__can_start_destruction=True) self.client.force_authenticate(user) endpoint = furl(reverse("api:zaken-list")) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e7b9230d..b0ca5e14 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -126,9 +126,6 @@ function App() { {user?.firstName} {user?.lastName}

- -

{user?.role.name}

-

{user?.email}

diff --git a/frontend/src/fixtures/user.ts b/frontend/src/fixtures/user.ts index 43dcf67d..b3337f0f 100644 --- a/frontend/src/fixtures/user.ts +++ b/frontend/src/fixtures/user.ts @@ -2,11 +2,9 @@ import { Role, User } from "../lib/api/auth"; import { createArrayFactory, createObjectFactory } from "./factory"; const FIXTURE_ROLE = { - name: "Test Role", canStartDestruction: false, canReviewDestruction: false, canReviewFinalList: false, - canViewCaseDetails: true, }; export const roleFactory = createObjectFactory(FIXTURE_ROLE); @@ -26,11 +24,9 @@ const FIXTURE_RECORD_MANAGER: User = { lastName: "Manager", email: "recordmanager@example.com", role: { - name: "recordmanager", canStartDestruction: true, canReviewDestruction: false, canReviewFinalList: false, - canViewCaseDetails: false, }, }; @@ -41,11 +37,9 @@ const FIXTURE_BEOORDELAAR: User = { lastName: "del Laar", email: "beoordelaar@example.com", role: { - name: "beoordelaar", canStartDestruction: false, canReviewDestruction: true, canReviewFinalList: false, - canViewCaseDetails: false, }, }; @@ -56,11 +50,9 @@ const FIXTURE_PROCES_EIGENAAR: User = { lastName: "ei Genaar", email: "proceseigenaar@example.com", role: { - name: "proceseigenaar", canStartDestruction: false, canReviewDestruction: true, canReviewFinalList: false, - canViewCaseDetails: false, }, }; diff --git a/frontend/src/lib/api/auth.ts b/frontend/src/lib/api/auth.ts index 85d11d36..86d37a79 100644 --- a/frontend/src/lib/api/auth.ts +++ b/frontend/src/lib/api/auth.ts @@ -11,11 +11,9 @@ export type User = { }; export type Role = { - name: string; canStartDestruction: boolean; canReviewDestruction: boolean; canReviewFinalList: boolean; - canViewCaseDetails: boolean; }; /** diff --git a/frontend/src/lib/format/user.ts b/frontend/src/lib/format/user.ts index b49a663a..04ecede8 100644 --- a/frontend/src/lib/format/user.ts +++ b/frontend/src/lib/format/user.ts @@ -6,10 +6,7 @@ import { User } from "../api/auth"; * @param showUsername * @param showRole */ -export function formatUser( - user: User, - { showUsername = true, showRole = false } = {}, -) { +export function formatUser(user: User, { showUsername = true } = {}) { if (!user) { return ""; } @@ -20,8 +17,5 @@ export function formatUser( ? `${user.firstName} ${user.lastName}${userNameSuffix}` : user.username; - if (showRole && user.role.name) { - return `${displayName} (${user.role.name})`; - } return displayName; } diff --git a/frontend/src/pages/destructionlist/create/DestructionListCreate.stories.tsx b/frontend/src/pages/destructionlist/create/DestructionListCreate.stories.tsx index ac42d7be..e74e01d6 100644 --- a/frontend/src/pages/destructionlist/create/DestructionListCreate.stories.tsx +++ b/frontend/src/pages/destructionlist/create/DestructionListCreate.stories.tsx @@ -57,11 +57,9 @@ const meta: Meta = { lastName: "Doe", email: "aaa@aaa.aaa", role: { - name: "Admin", canStartDestruction: true, canReviewDestruction: true, canReviewFinalList: false, - canViewCaseDetails: true, }, }, }, diff --git a/frontend/src/pages/destructionlist/detail/components/DestructionListToolbar/DestructionListToolbar.tsx b/frontend/src/pages/destructionlist/detail/components/DestructionListToolbar/DestructionListToolbar.tsx index b49a5172..681c3bba 100644 --- a/frontend/src/pages/destructionlist/detail/components/DestructionListToolbar/DestructionListToolbar.tsx +++ b/frontend/src/pages/destructionlist/detail/components/DestructionListToolbar/DestructionListToolbar.tsx @@ -95,8 +95,7 @@ export function DestructionListToolbar({ title }: DestructionListToolbarProps) { diff --git a/frontend/src/pages/landing/Landing.tsx b/frontend/src/pages/landing/Landing.tsx index 945b6c7d..276008ae 100644 --- a/frontend/src/pages/landing/Landing.tsx +++ b/frontend/src/pages/landing/Landing.tsx @@ -166,7 +166,6 @@ export const Landing = () => {   {formatUser(currentAssignee, { showUsername: false, - showRole: false, })} {otherAssignees.length && ( @@ -186,9 +185,7 @@ export const Landing = () => { timeAgo: timeAgo(list.created), assignees: otherAssignees.length ? ( formatUser(a.user, { showRole: true })) - .join(", ")} + content={otherAssignees.map((a) => formatUser(a.user)).join(", ")} placement="bottom" > {footer}