diff --git a/aleksis/core/checks.py b/aleksis/core/checks.py index db3199b6081d77e9bd8e2c559db07f7924484599..fc1c54e88e60a76728f2b347339737b761cc081b 100644 --- a/aleksis/core/checks.py +++ b/aleksis/core/checks.py @@ -3,7 +3,7 @@ from typing import Optional import django.apps from django.core.checks import Tags, Warning, register -from .mixins import ExtensibleModel, PureDjangoModel +from .mixins import ExtensibleModel, GlobalPermissionModel, PureDjangoModel from .util.apps import AppConfig @@ -39,7 +39,10 @@ def check_app_configs_base_class( def check_app_models_base_class( app_configs: Optional[django.apps.registry.Apps] = None, **kwargs ) -> list: - """Check whether all app models derive from AlekSIS's base ExtensibleModel.""" + """Check whether all app models derive from AlekSIS's allowed base models. + + Does only allow ExtensibleModel, GlobalPermissionModel and PureDjangoModel. + """ results = [] if app_configs is None: @@ -47,14 +50,19 @@ def check_app_models_base_class( for app_config in filter(lambda c: c.name.startswith("aleksis."), app_configs): for model in app_config.get_models(): - if ExtensibleModel not in model.__mro__ and PureDjangoModel not in model.__mro__: + if not ( + set(model.__mro__) & set((ExtensibleModel, PureDjangoModel, GlobalPermissionModel)) + ): results.append( Warning( - f"Model {model._meta.object_name} in app config {app_config.name} does" - "not derive from aleksis.core.mixins.ExtensibleModel.", + f"Model {model._meta.object_name} in app config {app_config.name} does " + "not derive from aleksis.core.mixins.ExtensibleModel " + "or aleksis.core.mixins.GlobalPermissionModel.", hint=( - "Ensure all models in AlekSIS use ExtensibleModel as base." - "If your deviation is intentional, you can add the PureDjangoModel" + "Ensure all models in AlekSIS use ExtensibleModel (or " + "GlobalPermissionModel, if you want to define global permissions) " + "as base. " + "If your deviation is intentional, you can add the PureDjangoModel " "mixin instead to silence this warning." ), obj=model, diff --git a/aleksis/core/migrations/0001_initial.py b/aleksis/core/migrations/0001_initial.py index 9999e1a6615138251c1745d4e33b3d9d404d0c7b..07e4bf433df4d8aec43814493d7dde6527d1f8f1 100644 --- a/aleksis/core/migrations/0001_initial.py +++ b/aleksis/core/migrations/0001_initial.py @@ -26,15 +26,12 @@ class Migration(migrations.Migration): name='GlobalPermissions', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)), ], options={ - 'permissions': (('view_system_status', 'Can view system status'), ('link_persons_accounts', 'Can link persons to accounts'), ('manage_data', 'Can manage data'), ('impersonate', 'Can impersonate'), ('search', 'Can use search'), ('change_site_preferences', 'Can change site preferences'), ('change_person_preferences', 'Can change person preferences'), ('change_group_preferences', 'Can change group preferences')), + 'default_permissions': (), + 'permissions': (('view_system_status', 'Can view system status'), ('link_persons_accounts', 'Can link persos to accounts'), ('manage_data', 'Can manage data'), ('impersonate', 'Can impersonate'), ('search', 'Can use search'), ('change_site_preferences', 'Can change site preferences'), ('change_person_preferences', 'Can change person preferences'), ('change_group_preferences', 'Can change group preferences')), 'managed': False, }, - managers=[ - ('objects', django.contrib.sites.managers.CurrentSiteManager()), - ], ), migrations.CreateModel( name='AdditionalField', diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py index 7b7b0b2b466e2c4f35311eb9253d6af144b5660d..d2c8fc0539293eda74713fea0d84287851c940aa 100644 --- a/aleksis/core/mixins.py +++ b/aleksis/core/mixins.py @@ -354,6 +354,17 @@ class PureDjangoModel(object): pass +class GlobalPermissionModel(models.Model): + """Base model for global permissions. + + This base model ensures that global permissions are not managed.""" + + class Meta: + default_permissions = () + abstract = True + managed = False + + class _ExtensibleFormMetaclass(ModelFormMetaclass): def __new__(cls, name, bases, dct): x = super().__new__(cls, name, bases, dct) diff --git a/aleksis/core/models.py b/aleksis/core/models.py index 24b6c8ca1c5f18889679d9c81b972eaac6cd72c4..1089d98cc3cc12cb9243670706eb0ec78e4bd1d5 100644 --- a/aleksis/core/models.py +++ b/aleksis/core/models.py @@ -34,7 +34,12 @@ from .managers import ( GroupQuerySet, SchoolTermQuerySet, ) -from .mixins import ExtensibleModel, PureDjangoModel, SchoolTermRelatedExtensibleModel +from .mixins import ( + ExtensibleModel, + GlobalPermissionModel, + PureDjangoModel, + SchoolTermRelatedExtensibleModel, +) from .tasks import send_notification from .util.core_helpers import get_site_preferences, now_tomorrow from .util.model_helpers import ICONS @@ -830,11 +835,10 @@ class GroupType(ExtensibleModel): verbose_name_plural = _("Group types") -class GlobalPermissions(ExtensibleModel): +class GlobalPermissions(GlobalPermissionModel): """Container for global permissions.""" - class Meta: - managed = False + class Meta(GlobalPermissionModel.Meta): permissions = ( ("view_system_status", _("Can view system status")), ("link_persons_accounts", _("Can link persons to accounts")),