diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py index 8bff9408655273aaad6b05901f8f1dd3e38706c1..88a01c15cf28489fde10c788895a35758bf857db 100644 --- a/aleksis/core/mixins.py +++ b/aleksis/core/mixins.py @@ -43,6 +43,8 @@ class _ExtensibleModelBase(models.base.ModelBase): # Register all non-abstract models with django-reversion mcls = reversion.register(mcls) + mcls.extra_permissions = [] + return mcls @@ -100,6 +102,8 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase): objects = CurrentSiteManager() objects_all_sites = models.Manager() + extra_permissions = [] + def get_absolute_url(self) -> str: """Get the URL o a view representing this model instance.""" pass @@ -226,6 +230,11 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase): """Collect all fields that can be synced on a model.""" return lazy(cls.syncable_fields_choices, tuple) + @classmethod + def add_permission(cls, name: str, verbose_name: str): + """Dynamically add a new permission to a model.""" + cls.extra_permissions.append((name, verbose_name)) + class Meta: abstract = True diff --git a/aleksis/core/util/apps.py b/aleksis/core/util/apps.py index d263feb9a2ba0c9e36d821a56e12f77726a7a672..1d2b76881e0ca9d04ed972200dde6ab229687c42 100644 --- a/aleksis/core/util/apps.py +++ b/aleksis/core/util/apps.py @@ -189,6 +189,9 @@ class AppConfig(django.apps.AppConfig): pass def _maintain_default_data(self): + from django.contrib.auth.models import Permission + from django.contrib.contenttypes.models import ContentType + if not self.models_module: # This app does not have any models, so bail out early return @@ -197,3 +200,12 @@ class AppConfig(django.apps.AppConfig): if hasattr(model, "maintain_default_data"): # Method implemented by each model object; can be left out model.maintain_default_data() + if hasattr(model, "extra_permissions"): + ct = ContentType.objects.get_for_model(model) + for perm, verbose_name in model.extra_permissions: + Permission.objects.get_or_create( + codename=perm, + name=verbose_name, + content_type=ct + ) +