From ea1be44469d40c0015860f7682726c367bc67dac Mon Sep 17 00:00:00 2001 From: David van Buiten Date: Mon, 18 Sep 2023 14:48:22 +0200 Subject: [PATCH] This commit adds a new abstract class, CustomPermission, essential for creating custom permissions independent of existing models, as Django auth Permissions necessitate a ContentType association. Additionally, a sync_custom_permission function is included, which responds to the DjangoSignal post_migrate, facilitating the creation of custom permissions if they do not already exist. --- app/signals/apps/signals/apps.py | 1 + app/signals/apps/signals/models/permission.py | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 app/signals/apps/signals/models/permission.py diff --git a/app/signals/apps/signals/apps.py b/app/signals/apps/signals/apps.py index 707c16647..59fc3799e 100644 --- a/app/signals/apps/signals/apps.py +++ b/app/signals/apps/signals/apps.py @@ -10,3 +10,4 @@ class SignalsConfig(AppConfig): def ready(self): # Import Django signals to connect receiver functions. import signals.apps.signals.signal_receivers # noqa + import signals.apps.signals.models.permission # noqa diff --git a/app/signals/apps/signals/models/permission.py b/app/signals/apps/signals/models/permission.py new file mode 100644 index 000000000..077601334 --- /dev/null +++ b/app/signals/apps/signals/models/permission.py @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (C) 2023 Gemeente Amsterdam +import logging + +from django.contrib.auth.models import Permission +from django.contrib.contenttypes.models import ContentType +from django.db import models +from django.db.models.signals import post_migrate +from django.dispatch import receiver + +logger = logging.getLogger(__name__) + + +class CustomPermission(models.Model): + """ + An abstract class for creating custom permissions that do not belong to any existing model. + + Django's built-in auth Permissions require a ContentType association. + """ + class Meta: + abstract = True + + +@receiver(post_migrate) +def sync_custom_permissions(sender, **kwargs): + """ + Synchronize custom permissions after a migration. + + This function listens to the post_migrate signal in Django and creates custom permissions + if they do not already exist. + + These custom permissions are associated with the CustomPermission model. + + Args: + sender: The sender of the signal (usually the app with the migrations). + **kwargs: Additional keyword arguments provided by the signal. + """ + content_type = ContentType.objects.get_for_model(CustomPermission, for_concrete_model=False) + + custom_permissions = [ + # Custom permission to allow users to create i18next translation files. + ('add_i18next_translation_file', 'Can create i18next translation file') + ] + + for codename, name in custom_permissions: + if not Permission.objects.filter(name=name, codename=codename, content_type=content_type).exists(): + logger.info(f'Creating custom permission "{codename}" with name "{name}"') + Permission.objects.create(name=name, codename=codename, content_type=content_type)