diff --git a/aleksis/core/apps.py b/aleksis/core/apps.py index a3efe2ce8fc43d490a90de14f5b869ccc8e45d85..4e33bf83fbe4c5e18032fbd087dc91281968b622 100644 --- a/aleksis/core/apps.py +++ b/aleksis/core/apps.py @@ -4,6 +4,9 @@ import django.apps from django.contrib.auth.signals import user_logged_in from django.http import HttpRequest +from dynamic_preferences.registries import preference_models + +from .registries import group_preferences_registry, person_preferences_registry, site_preferences_registry from .signals import clean_scss from .util.apps import AppConfig from .util.core_helpers import has_person @@ -27,6 +30,15 @@ class CoreConfig(AppConfig): ([2019, 2020], "Tom Teichler", "tom.teichler@teckids.org"), ) + def ready(self): + SitePreferenceModel = self.get_model('SitePreferenceModel') + PersonPreferenceModel = self.get_model('PersonPreferenceModel') + GroupPreferenceModel = self.get_model('GroupPreferenceModel') + + preference_models.register(SitePreferenceModel, site_preferences_registry) + preference_models.register(PersonPreferenceModel, person_preferences_registry) + preference_models.register(GroupPreferenceModel, group_preferences_registry) + def preference_updated( self, sender: Any, diff --git a/aleksis/core/models.py b/aleksis/core/models.py index f8845671c419e500bc2b25d0fdcf9cd7b6272c09..85ef2c2e5fe1877d6a98eab5fe82404960b0d247 100644 --- a/aleksis/core/models.py +++ b/aleksis/core/models.py @@ -5,12 +5,14 @@ from django.contrib.auth import get_user_model from django.contrib.auth.models import Group as DjangoGroup from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType +from django.contrib.sites.models import Site from django.db import models from django.db.models import QuerySet from django.forms.widgets import Media from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from dynamic_preferences.models import PerInstancePreferenceModel from image_cropping import ImageCropField, ImageRatioField from phonenumber_field.modelfields import PhoneNumberField from polymorphic.models import PolymorphicModel @@ -25,69 +27,6 @@ from dynamic_preferences.registries import global_preferences_registry global_preferences = global_preferences_registry.manager() -class School(ExtensibleModel): - """A school that will have many other objects linked to it. - AlekSIS has multi-tenant support by linking all objects to a school, - and limiting all features to objects related to the same school as the - currently logged-in user. - """ - - name = models.CharField(verbose_name=_("Name"), max_length=255) - name_official = models.CharField( - verbose_name=_("Official name"), - max_length=255, - help_text=_("Official name of the school, e.g. as given by supervisory authority"), - ) - - logo = ImageCropField(verbose_name=_("School logo"), blank=True, null=True) - logo_cropping = ImageRatioField("logo", "600x600", size_warning=True) - - @classmethod - def get_default(cls): - return cls.objects.first() - - @property - def current_term(self): - return SchoolTerm.objects.get(current=True) - - class Meta: - ordering = ["name", "name_official"] - verbose_name = _("School") - verbose_name_plural = _("Schools") - - -class SchoolTerm(ExtensibleModel): - """ Information about a term (limited time frame) that data can - be linked to. - """ - - caption = models.CharField(verbose_name=_("Visible caption of the term"), max_length=255) - - date_start = models.DateField(verbose_name=_("Effective start date of term"), null=True) - date_end = models.DateField(verbose_name=_("Effective end date of term"), null=True) - - current = models.NullBooleanField(default=None, unique=True) - - def save(self, *args, **kwargs): - if self.current is False: - self.current = None - super().save(*args, **kwargs) - - @classmethod - def maintain_default_data(cls): - if not cls.objects.filter(current=True).exists(): - if cls.objects.exists(): - term = cls.objects.latest('date_start') - term.current=True - term.save() - else: - cls.objects.create(date_start=date.today(), current=True) - - class Meta: - verbose_name = _("School term") - verbose_name_plural = _("School terms") - - class Person(ExtensibleModel): """ A model describing any person related to a school, including, but not limited to, students, teachers and guardians (parents). @@ -586,3 +525,15 @@ class GlobalPermissions(ExtensibleModel): ("impersonate", _("Can impersonate")), ("search", _("Can use search")), ) + + +class SitePreferenceModel(PerInstancePreferenceModel): + instance = models.ForeignKey(Site) + + +class PersonPreferenceModel(PerInstancePreferenceModel): + instance = models.ForeignKey(Person) + + +class GroupPreferenceModel(PerInstancePreferenceModel): + instance = models.ForeignKey(Group) diff --git a/aleksis/core/preferences.py b/aleksis/core/preferences.py index be34422b0ac35b49b7cc587f719e5946797d76ba..cd4255fb5b6bb5915324904260124fa46fbbd8fe 100644 --- a/aleksis/core/preferences.py +++ b/aleksis/core/preferences.py @@ -6,11 +6,13 @@ from colorfield.widgets import ColorWidget from dynamic_preferences.types import BooleanPreference, ChoicePreference, StringPreference from dynamic_preferences.preferences import Section from dynamic_preferences.registries import global_preferences_registry -from dynamic_preferences.users.registries import user_preferences_registry +from .registries import group_preferences_registry, person_preferences_registry, site_preferences_registry from .util.notifications import get_notification_choices_lazy + general = Section("general") +school = Section("school") theme = Section("theme") mail = Section("mail") notification = Section("notification") @@ -18,7 +20,7 @@ footer = Section("footer") account = Section("account") -@global_preferences_registry.register +@site_preferences_registry.register class SiteTitle(StringPreference): section = general name = "title" @@ -27,7 +29,7 @@ class SiteTitle(StringPreference): verbose_name = _("Site title") -@global_preferences_registry.register +@site_preferences_registry.register class SiteDescription(StringPreference): section = general name = "description" @@ -36,7 +38,7 @@ class SiteDescription(StringPreference): verbose_name = _("Site description") -@global_preferences_registry.register +@site_preferences_registry.register class ColourPrimary(StringPreference): section = theme name = "primary" @@ -45,7 +47,7 @@ class ColourPrimary(StringPreference): verbose_name = _("Primary colour") -@global_preferences_registry.register +@site_preferences_registry.register class ColourSecondary(StringPreference): section = theme name = "secondary" @@ -54,7 +56,7 @@ class ColourSecondary(StringPreference): verbose_name = _("Secondary colour") -@global_preferences_registry.register +@site_preferences_registry.register class MailOutName(StringPreference): section = mail name = "name" @@ -63,7 +65,7 @@ class MailOutName(StringPreference): verbose_name = _("Mail out name") -@global_preferences_registry.register +@site_preferences_registry.register class MailOut(StringPreference): section = mail name = "address" @@ -73,7 +75,7 @@ class MailOut(StringPreference): field_class = EmailField -@global_preferences_registry.register +@site_preferences_registry.register class PrivacyURL(StringPreference): section = footer name = "privacy_url" @@ -83,7 +85,7 @@ class PrivacyURL(StringPreference): field_class = URLField -@global_preferences_registry.register +@site_preferences_registry.register class ImprintURL(StringPreference): section = footer name = "imprint_url" @@ -93,7 +95,7 @@ class ImprintURL(StringPreference): field_class = URLField -@user_preferences_registry.register +@person_preferences_registry.register class AdressingNameFormat(ChoicePreference): section = notification name = "addressing_name_format" @@ -108,7 +110,7 @@ class AdressingNameFormat(ChoicePreference): ) -@user_preferences_registry.register +@person_preferences_registry.register class NotificationChannels(ChoicePreference): # FIXME should be a MultipleChoicePreference section = notification @@ -119,10 +121,28 @@ class NotificationChannels(ChoicePreference): choices = get_notification_choices_lazy() -@global_preferences_registry.register +@site_preferences_registry.register class PrimaryGroupPattern(StringPreference): section = account name = "primary_group_pattern" default = "" required = False verbose_name = _("Regular expression to match primary group, e.g. '^Class .*'") + + +@site_preferences_registry.register +class SchoolName(StringPreference): + section = school + name = "name" + default = "" + required = False + verbose_name = _("Display name of the school") + + +@site_preferences_registry.register +class SchoolNameOfficial(StringPreference): + section = school + name = "name_official" + default = "" + required = False + verbose_name = _("Official name of the school, e.g. as given by supervisory authority") diff --git a/aleksis/core/registries.py b/aleksis/core/registries.py new file mode 100644 index 0000000000000000000000000000000000000000..eab1cb333336bc416a09a73931ff0bdcec3903ae --- /dev/null +++ b/aleksis/core/registries.py @@ -0,0 +1,18 @@ +from dynamic_preferences.registries import PerInstancePreferenceRegistry + + +class SitePreferenceRegistry(PerInstancePreferenceRegistry): + pass + + +class PersonPreferenceRegistry(PerInstancePreferenceRegistry): + pass + + +class GroupPreferenceRegistry(PerInstancePreferenceRegistry): + pass + + +site_preferences_registry = SitePreferenceRegistry() +person_preferences_registry = PersonPreferenceRegistry() +group_preferences_registry = GroupPreferenceRegistry() diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py index 56acf80295546ac73cbffd4bc0e36770d8bb3687..7a567e94f86a3e8784b9bcabcdeb3eb6bbe55c65 100644 --- a/aleksis/core/util/core_helpers.py +++ b/aleksis/core/util/core_helpers.py @@ -93,10 +93,11 @@ def lazy_preference(section: str, name: str) -> Callable[[str, str], Any]: """ def _get_preference(section: str, name: str) -> Any: - from dynamic_preferences.registries import global_preferences_registry # noqa - global_preferences = global_preferences_registry.manager() + from ..registries import site_preferences_registry # noqa - return global_preferences["%s__%s" % (section, name)] + site_preferences = site_preferences_registry.manager() + + return site_preferences["%s__%s" % (section, name)] # The type is guessed from the default value to improve lazy()'s behaviour # FIXME Reintroduce the behaviour described above