diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d36458971660c0b5ab354ad1e4b03068fb46ebea..7e79081953846c2db12c3c9e2a91656e5126759b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,4 +3,5 @@ include:
     - local: "/ci/test.yml"
     - local: "/ci/build_dist.yml"
     - local: "/ci/build_docker.yml"
+    - local: "/ci/pages.yml"
     - local: "/ci/deploy.yml"
diff --git a/aleksis/core/apps.py b/aleksis/core/apps.py
index aeda609326941428e483e05cabd6e5412b2832f7..e627b0a2e6b93a6e661cdceaef21ec824e4daedb 100644
--- a/aleksis/core/apps.py
+++ b/aleksis/core/apps.py
@@ -1,6 +1,8 @@
 from typing import Any, List, Optional, Tuple
 
 import django.apps
+from django.conf import settings
+from django.db import ProgrammingError
 from django.http import HttpRequest
 from django.utils.module_loading import autodiscover_modules
 
@@ -12,7 +14,7 @@ from .registries import (
     site_preferences_registry,
 )
 from .util.apps import AppConfig
-from .util.core_helpers import has_person
+from .util.core_helpers import get_site_preferences, has_person
 from .util.sass_helpers import clean_scss
 
 
@@ -48,6 +50,26 @@ class CoreConfig(AppConfig):
         preference_models.register(personpreferencemodel, person_preferences_registry)
         preference_models.register(grouppreferencemodel, group_preferences_registry)
 
+        self._refresh_authentication_backends()
+
+    @classmethod
+    def _refresh_authentication_backends(cls):
+        """Refresh config list of enabled authentication backends."""
+        from .preferences import AuthenticationBackends  # noqa
+
+        idx = settings.AUTHENTICATION_BACKENDS.index("django.contrib.auth.backends.ModelBackend")
+
+        try:
+            # Don't set array directly in order to keep object reference
+            settings._wrapped.AUTHENTICATION_BACKENDS.clear()
+            settings._wrapped.AUTHENTICATION_BACKENDS += settings.ORIGINAL_AUTHENTICATION_BACKENDS
+
+            for backend in get_site_preferences()["auth__backends"]:
+                settings._wrapped.AUTHENTICATION_BACKENDS.insert(idx, backend)
+                idx += 1
+        except ProgrammingError:
+            pass
+
     def preference_updated(
         self,
         sender: Any,
@@ -57,6 +79,9 @@ class CoreConfig(AppConfig):
         new_value: Optional[Any] = None,
         **kwargs,
     ) -> None:
+        if section == "auth" and name == "backends":
+            self._refresh_authentication_backends()
+
         if section == "theme":
             if name in ("primary", "secondary"):
                 clean_scss()
diff --git a/aleksis/core/filters.py b/aleksis/core/filters.py
index c0159567101fe2620deb0f116019ca68e4cf9652..aa287690b3d72d7f4e72f1a41708e38401f2b0db 100644
--- a/aleksis/core/filters.py
+++ b/aleksis/core/filters.py
@@ -1,20 +1,74 @@
-from django_filters import CharFilter, FilterSet
+from typing import Sequence
+
+from django.db.models import Q
+from django.utils.translation import gettext as _
+
+from django_filters import CharFilter, FilterSet, ModelChoiceFilter, ModelMultipleChoiceFilter
 from material import Layout, Row
 
+from aleksis.core.models import Group, GroupType, Person, SchoolTerm
+
+
+class MultipleCharFilter(CharFilter):
+    """Filter for filtering multiple fields with one input.
+
+    >>> multiple_filter = MultipleCharFilter(["name__icontains", "short_name__icontains"])
+    """
+
+    def filter(self, qs, value):  # noqa
+        q = None
+        for field in self.fields:
+            if not q:
+                q = Q(**{field: value})
+            else:
+                q = q | Q(**{field: value})
+        return qs.filter(q)
+
+    def __init__(self, fields: Sequence[str], *args, **kwargs):
+        self.fields = fields
+        super().__init__(self, *args, **kwargs)
+
 
 class GroupFilter(FilterSet):
-    name = CharFilter(lookup_expr="icontains")
-    short_name = CharFilter(lookup_expr="icontains")
+    school_term = ModelChoiceFilter(queryset=SchoolTerm.objects.all())
+    group_type = ModelChoiceFilter(queryset=GroupType.objects.all())
+    parent_groups = ModelMultipleChoiceFilter(queryset=Group.objects.all())
+
+    search = MultipleCharFilter(["name__icontains", "short_name__icontains"], label=_("Search"))
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self.form.layout = Layout(Row("name", "short_name"))
+        self.form.layout = Layout(Row("search"), Row("school_term", "group_type", "parent_groups"))
+        self.form.initial = {"school_term": SchoolTerm.current}
 
 
 class PersonFilter(FilterSet):
-    first_name = CharFilter(lookup_expr="icontains")
-    last_name = CharFilter(lookup_expr="icontains")
+    name = MultipleCharFilter(
+        [
+            "first_name__icontains",
+            "additional_name__icontains",
+            "last_name__icontains",
+            "short_name__icontains",
+        ],
+        label=_("Search by name"),
+    )
+    contact = MultipleCharFilter(
+        [
+            "street__icontains",
+            "housenumber__icontains",
+            "postal_code__icontains",
+            "place__icontains",
+            "phone_number__icontains",
+            "mobile_number__icontains",
+            "email__icontains",
+        ],
+        label=_("Search by contact details"),
+    )
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self.form.layout = Layout(Row("first_name", "last_name"))
+        self.form.layout = Layout(Row("name", "contact"), Row("is_active", "sex", "primary_group"))
+
+    class Meta:
+        model = Person
+        fields = ["sex", "is_active", "primary_group"]
diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py
index 208cbff93f76b7d44451550b73d3b5659ba4aa59..9297980c7cc8bbd494f6124ee914f6d542b1863f 100644
--- a/aleksis/core/forms.py
+++ b/aleksis/core/forms.py
@@ -5,7 +5,7 @@ from django.contrib.auth import get_user_model
 from django.core.exceptions import ValidationError
 from django.utils.translation import gettext_lazy as _
 
-from django_select2.forms import ModelSelect2MultipleWidget, Select2Widget
+from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget, Select2Widget
 from dynamic_preferences.forms import PreferenceForm
 from material import Fieldset, Layout, Row
 
@@ -24,7 +24,7 @@ class PersonAccountForm(forms.ModelForm):
     class Meta:
         model = Person
         fields = ["last_name", "first_name", "user"]
-        widgets = {"user": Select2Widget}
+        widgets = {"user": Select2Widget(attrs={"class": "browser-default"})}
 
     new_user = forms.CharField(required=False)
 
@@ -80,10 +80,7 @@ class EditPersonForm(ExtensibleForm):
         Fieldset(_("Address"), Row("street", "housenumber"), Row("postal_code", "place")),
         Fieldset(_("Contact data"), "email", Row("phone_number", "mobile_number")),
         Fieldset(
-            _("Advanced personal data"),
-            Row("sex", "date_of_birth"),
-            Row("photo", "photo_cropping"),
-            "guardians",
+            _("Advanced personal data"), Row("sex", "date_of_birth"), Row("photo"), "guardians",
         ),
     )
 
@@ -106,11 +103,24 @@ class EditPersonForm(ExtensibleForm):
             "date_of_birth",
             "sex",
             "photo",
-            "photo_cropping",
             "guardians",
             "primary_group",
         ]
-        widgets = {"user": Select2Widget}
+        widgets = {
+            "user": Select2Widget(attrs={"class": "browser-default"}),
+            "primary_group": ModelSelect2Widget(
+                search_fields=["name__icontains", "short_name__icontains"],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+            ),
+            "guardians": ModelSelect2MultipleWidget(
+                search_fields=[
+                    "first_name__icontains",
+                    "last_name__icontains",
+                    "short_name__icontains",
+                ],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+            ),
+        }
 
     new_user = forms.CharField(
         required=False, label=_("New user"), help_text=_("Create a new account")
@@ -140,19 +150,25 @@ class EditGroupForm(SchoolTermRelatedExtensibleForm):
                     "first_name__icontains",
                     "last_name__icontains",
                     "short_name__icontains",
-                ]
+                ],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
             ),
             "owners": ModelSelect2MultipleWidget(
                 search_fields=[
                     "first_name__icontains",
                     "last_name__icontains",
                     "short_name__icontains",
-                ]
+                ],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
             ),
             "parent_groups": ModelSelect2MultipleWidget(
-                search_fields=["name__icontains", "short_name__icontains"]
+                search_fields=["name__icontains", "short_name__icontains"],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+            ),
+            "additional_fields": ModelSelect2MultipleWidget(
+                search_fields=["title__icontains",],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
             ),
-            "additional_fields": ModelSelect2MultipleWidget(search_fields=["title__icontains",]),
         }
 
 
@@ -169,9 +185,27 @@ class AnnouncementForm(ExtensibleForm):
     valid_until_time = forms.TimeField(label=_("Time"))
 
     persons = forms.ModelMultipleChoiceField(
-        Person.objects.all(), label=_("Persons"), required=False
+        queryset=Person.objects.all(),
+        label=_("Persons"),
+        required=False,
+        widget=ModelSelect2MultipleWidget(
+            search_fields=[
+                "first_name__icontains",
+                "last_name__icontains",
+                "short_name__icontains",
+            ],
+            attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+        ),
+    )
+    groups = forms.ModelMultipleChoiceField(
+        queryset=None,
+        label=_("Groups"),
+        required=False,
+        widget=ModelSelect2MultipleWidget(
+            search_fields=["name__icontains", "short_name__icontains",],
+            attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+        ),
     )
-    groups = forms.ModelMultipleChoiceField(queryset=None, label=_("Groups"), required=False)
 
     layout = Layout(
         Fieldset(
diff --git a/aleksis/core/locale/ar/LC_MESSAGES/django.po b/aleksis/core/locale/ar/LC_MESSAGES/django.po
index f21f799bef0ace8309d458095e83ab705354ff96..92ad8782664c5f8ec329b96d4054bdc057596d40 100644
--- a/aleksis/core/locale/ar/LC_MESSAGES/django.po
+++ b/aleksis/core/locale/ar/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: AlekSIS (School Information System) 0.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-04 15:39+0200\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,8 +16,21 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
-"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
+
+#: filters.py:37 templates/core/base.html:77 templates/core/group/list.html:20
+#: templates/core/person/list.html:24 templates/search/search.html:7
+#: templates/search/search.html:22
+msgid "Search"
+msgstr ""
+
+#: filters.py:53
+msgid "Search by name"
+msgstr ""
+
+#: filters.py:65
+msgid "Search by contact details"
+msgstr ""
 
 #: forms.py:46
 msgid "You cannot set a new username when also selecting an existing user."
@@ -43,64 +56,71 @@ msgstr ""
 msgid "Advanced personal data"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "New user"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "Create a new account"
 msgstr ""
 
-#: forms.py:128
+#: forms.py:126 models.py:91
+msgid "School term"
+msgstr ""
+
+#: forms.py:127
 msgid "Common data"
 msgstr ""
 
-#: forms.py:129 forms.py:169 menus.py:141 models.py:54
-#: templates/core/persons.html:8 templates/core/persons.html:9
+#: forms.py:128 forms.py:170 menus.py:152 models.py:105
+#: templates/core/person/list.html:8 templates/core/person/list.html:9
 msgid "Persons"
 msgstr ""
 
-#: forms.py:162 forms.py:165 models.py:31
+#: forms.py:129
+msgid "Additional data"
+msgstr ""
+
+#: forms.py:163 forms.py:166 models.py:35
 msgid "Date"
 msgstr ""
 
-#: forms.py:163 forms.py:166 models.py:39
+#: forms.py:164 forms.py:167 models.py:43
 msgid "Time"
 msgstr ""
 
-#: forms.py:171 menus.py:149 models.py:253 templates/core/groups.html:8
-#: templates/core/groups.html:9 templates/core/person_full.html:106
+#: forms.py:172 menus.py:160 models.py:319 templates/core/group/list.html:8
+#: templates/core/group/list.html:9 templates/core/person/full.html:136
 msgid "Groups"
 msgstr ""
 
-#: forms.py:175
+#: forms.py:176
 msgid "From when until when should the announcement be displayed?"
 msgstr ""
 
-#: forms.py:178
+#: forms.py:179
 msgid "Who should see the announcement?"
 msgstr ""
 
-#: forms.py:179
+#: forms.py:180
 msgid "Write your announcement:"
 msgstr ""
 
-#: forms.py:216
-msgid ""
-"You are not allowed to create announcements which are only valid in the past."
+#: forms.py:219
+msgid "You are not allowed to create announcements which are only valid in the past."
 msgstr ""
 
-#: forms.py:220
+#: forms.py:223
 msgid "The from date and time must be earlier then the until date and time."
 msgstr ""
 
-#: forms.py:229
+#: forms.py:232
 msgid "You need at least one recipient."
 msgstr ""
 
 #: menus.py:7 templates/two_factor/core/login.html:6
 #: templates/two_factor/core/login.html:10
-#: templates/two_factor/core/login.html:73
+#: templates/two_factor/core/login.html:86
 msgid "Login"
 msgstr ""
 
@@ -136,502 +156,556 @@ msgstr ""
 msgid "Admin"
 msgstr ""
 
-#: menus.py:75 models.py:487 templates/core/announcement/list.html:7
+#: menus.py:75 models.py:564 templates/core/announcement/list.html:7
 #: templates/core/announcement/list.html:8
 msgid "Announcements"
 msgstr ""
 
-#: menus.py:86 templates/core/data_management.html:6
-#: templates/core/data_management.html:7
+#: menus.py:86 models.py:92 templates/core/school_term/list.html:8
+#: templates/core/school_term/list.html:9
+msgid "School terms"
+msgstr ""
+
+#: menus.py:97 templates/core/management/data_management.html:6
+#: templates/core/management/data_management.html:7
 msgid "Data management"
 msgstr ""
 
-#: menus.py:94 templates/core/system_status.html:5
-#: templates/core/system_status.html:7
+#: menus.py:105 templates/core/pages/system_status.html:5
+#: templates/core/pages/system_status.html:7
 msgid "System status"
 msgstr ""
 
-#: menus.py:105
+#: menus.py:116
 msgid "Impersonation"
 msgstr ""
 
-#: menus.py:113
+#: menus.py:124
 msgid "Configuration"
 msgstr ""
 
-#: menus.py:124
+#: menus.py:135
 msgid "Backend Admin"
 msgstr ""
 
-#: menus.py:132
+#: menus.py:143
 msgid "People"
 msgstr ""
 
-#: menus.py:157
+#: menus.py:168 models.py:727 templates/core/group_type/list.html:8
+#: templates/core/group_type/list.html:9
+msgid "Group types"
+msgstr ""
+
+#: menus.py:179
 msgid "Persons and accounts"
 msgstr ""
 
-#: menus.py:168
+#: menus.py:190
 msgid "Groups and child groups"
 msgstr ""
 
-#: menus.py:183 templates/core/groups_child_groups.html:7
-#: templates/core/groups_child_groups.html:9
+#: menus.py:201 models.py:363 templates/core/additional_field/list.html:8
+#: templates/core/additional_field/list.html:9
+msgid "Additional fields"
+msgstr ""
+
+#: menus.py:216 templates/core/group/child_groups.html:7
+#: templates/core/group/child_groups.html:9
 msgid "Assign child groups to groups"
 msgstr ""
 
-#: models.py:29
+#: mixins.py:406
+msgid "Linked school term"
+msgstr ""
+
+#: models.py:33
 msgid "Boolean (Yes/No)"
 msgstr ""
 
-#: models.py:30
+#: models.py:34
 msgid "Text (one line)"
 msgstr ""
 
-#: models.py:32
+#: models.py:36
 msgid "Date and time"
 msgstr ""
 
-#: models.py:33
+#: models.py:37
 msgid "Decimal number"
 msgstr ""
 
-#: models.py:34 models.py:95
+#: models.py:38 models.py:146
 msgid "E-mail address"
 msgstr ""
 
-#: models.py:35
+#: models.py:39
 msgid "Integer"
 msgstr ""
 
-#: models.py:36
+#: models.py:40
 msgid "IP address"
 msgstr ""
 
-#: models.py:37
+#: models.py:41
 msgid "Boolean or empty (Yes/No/Neither)"
 msgstr ""
 
-#: models.py:38
+#: models.py:42
 msgid "Text (multi-line)"
 msgstr ""
 
-#: models.py:40
+#: models.py:44
 msgid "URL / Link"
 msgstr ""
 
-#: models.py:53 templates/core/persons_accounts.html:36
+#: models.py:56 models.py:700
+msgid "Name"
+msgstr ""
+
+#: models.py:58
+msgid "Start date"
+msgstr ""
+
+#: models.py:59
+msgid "End date"
+msgstr ""
+
+#: models.py:77
+msgid "The start date must be earlier than the end date."
+msgstr ""
+
+#: models.py:84
+msgid "There is already a school term for this time or a part of this time."
+msgstr ""
+
+#: models.py:104 templates/core/person/accounts.html:36
 msgid "Person"
 msgstr ""
 
-#: models.py:56
+#: models.py:107
 msgid "Can view address"
 msgstr ""
 
-#: models.py:57
+#: models.py:108
 msgid "Can view contact details"
 msgstr ""
 
-#: models.py:58
+#: models.py:109
 msgid "Can view photo"
 msgstr ""
 
-#: models.py:59
+#: models.py:110
 msgid "Can view persons groups"
 msgstr ""
 
-#: models.py:60
+#: models.py:111
 msgid "Can view personal details"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "female"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "male"
 msgstr ""
 
-#: models.py:73
+#: models.py:124
 msgid "Linked user"
 msgstr ""
 
-#: models.py:75
+#: models.py:126
 msgid "Is person active?"
 msgstr ""
 
-#: models.py:77
+#: models.py:128
 msgid "First name"
 msgstr ""
 
-#: models.py:78
+#: models.py:129
 msgid "Last name"
 msgstr ""
 
-#: models.py:80
+#: models.py:131
 msgid "Additional name(s)"
 msgstr ""
 
-#: models.py:84 models.py:260
+#: models.py:135 models.py:332
 msgid "Short name"
 msgstr ""
 
-#: models.py:87
+#: models.py:138
 msgid "Street"
 msgstr ""
 
-#: models.py:88
+#: models.py:139
 msgid "Street number"
 msgstr ""
 
-#: models.py:89
+#: models.py:140
 msgid "Postal code"
 msgstr ""
 
-#: models.py:90
+#: models.py:141
 msgid "Place"
 msgstr ""
 
-#: models.py:92
+#: models.py:143
 msgid "Home phone"
 msgstr ""
 
-#: models.py:93
+#: models.py:144
 msgid "Mobile phone"
 msgstr ""
 
-#: models.py:97
+#: models.py:148
 msgid "Date of birth"
 msgstr ""
 
-#: models.py:98
+#: models.py:149
 msgid "Sex"
 msgstr ""
 
-#: models.py:100
+#: models.py:151
 msgid "Photo"
 msgstr ""
 
-#: models.py:105
+#: models.py:155 templates/core/person/full.html:129
 msgid "Guardians / Parents"
 msgstr ""
 
-#: models.py:112
+#: models.py:162
 msgid "Primary group"
 msgstr ""
 
-#: models.py:115 models.py:346 models.py:370 models.py:455 models.py:643
+#: models.py:165 models.py:423 models.py:447 models.py:532 models.py:720
+#: templates/core/person/full.html:112
 msgid "Description"
 msgstr ""
 
-#: models.py:233
+#: models.py:296
 msgid "Title of field"
 msgstr ""
 
-#: models.py:235
+#: models.py:298
 msgid "Type of field"
 msgstr ""
 
-#: models.py:239
+#: models.py:305
 msgid "Addtitional field for groups"
 msgstr ""
 
-#: models.py:240
+#: models.py:306
 msgid "Addtitional fields for groups"
 msgstr ""
 
-#: models.py:252
+#: models.py:318
 msgid "Group"
 msgstr ""
 
-#: models.py:254
+#: models.py:320
 msgid "Can assign child groups to groups"
 msgstr ""
 
-#: models.py:258
+#: models.py:330
 msgid "Long name"
 msgstr ""
 
-#: models.py:268 templates/core/group_full.html:37
+#: models.py:340 templates/core/group/full.html:65
 msgid "Members"
 msgstr ""
 
-#: models.py:271 templates/core/group_full.html:34
+#: models.py:343 templates/core/group/full.html:62
 msgid "Owners"
 msgstr ""
 
-#: models.py:278
+#: models.py:350 templates/core/group/full.html:54
 msgid "Parent groups"
 msgstr ""
 
-#: models.py:286
+#: models.py:358
 msgid "Type of group"
 msgstr ""
 
-#: models.py:290
-msgid "Additional fields"
-msgstr ""
-
-#: models.py:342
+#: models.py:419
 msgid "User"
 msgstr ""
 
-#: models.py:345 models.py:369 models.py:454
+#: models.py:422 models.py:446 models.py:531
 #: templates/core/announcement/list.html:18
 msgid "Title"
 msgstr ""
 
-#: models.py:348
+#: models.py:425
 msgid "Application"
 msgstr ""
 
-#: models.py:354
+#: models.py:431
 msgid "Activity"
 msgstr ""
 
-#: models.py:355
+#: models.py:432
 msgid "Activities"
 msgstr ""
 
-#: models.py:361
+#: models.py:438
 msgid "Sender"
 msgstr ""
 
-#: models.py:366
+#: models.py:443
 msgid "Recipient"
 msgstr ""
 
-#: models.py:371 models.py:624
+#: models.py:448 models.py:701
 msgid "Link"
 msgstr ""
 
-#: models.py:373
+#: models.py:450
 msgid "Read"
 msgstr ""
 
-#: models.py:374
+#: models.py:451
 msgid "Sent"
 msgstr ""
 
-#: models.py:387
+#: models.py:464
 msgid "Notification"
 msgstr ""
 
-#: models.py:388
+#: models.py:465
 msgid "Notifications"
 msgstr ""
 
-#: models.py:456
+#: models.py:533
 msgid "Link to detailed view"
 msgstr ""
 
-#: models.py:459
+#: models.py:536
 msgid "Date and time from when to show"
 msgstr ""
 
-#: models.py:462
+#: models.py:539
 msgid "Date and time until when to show"
 msgstr ""
 
-#: models.py:486
+#: models.py:563
 msgid "Announcement"
 msgstr ""
 
-#: models.py:524
+#: models.py:601
 msgid "Announcement recipient"
 msgstr ""
 
-#: models.py:525
+#: models.py:602
 msgid "Announcement recipients"
 msgstr ""
 
-#: models.py:575
+#: models.py:652
 msgid "Widget Title"
 msgstr ""
 
-#: models.py:576
+#: models.py:653
 msgid "Activate Widget"
 msgstr ""
 
-#: models.py:594
+#: models.py:671
 msgid "Dashboard Widget"
 msgstr ""
 
-#: models.py:595
+#: models.py:672
 msgid "Dashboard Widgets"
 msgstr ""
 
-#: models.py:601
+#: models.py:678
 msgid "Menu ID"
 msgstr ""
 
-#: models.py:613
+#: models.py:690
 msgid "Custom menu"
 msgstr ""
 
-#: models.py:614
+#: models.py:691
 msgid "Custom menus"
 msgstr ""
 
-#: models.py:621
+#: models.py:698
 msgid "Menu"
 msgstr ""
 
-#: models.py:623
-msgid "Name"
-msgstr ""
-
-#: models.py:625
+#: models.py:702
 msgid "Icon"
 msgstr ""
 
-#: models.py:631
+#: models.py:708
 msgid "Custom menu item"
 msgstr ""
 
-#: models.py:632
+#: models.py:709
 msgid "Custom menu items"
 msgstr ""
 
-#: models.py:642
+#: models.py:719
 msgid "Title of type"
 msgstr ""
 
-#: models.py:646
+#: models.py:726 templates/core/group/full.html:46
 msgid "Group type"
 msgstr ""
 
-#: models.py:647
-msgid "Group types"
-msgstr ""
-
-#: models.py:656
+#: models.py:736
 msgid "Can view system status"
 msgstr ""
 
-#: models.py:657
+#: models.py:737
 msgid "Can link persons to accounts"
 msgstr ""
 
-#: models.py:658
+#: models.py:738
 msgid "Can manage data"
 msgstr ""
 
-#: models.py:659
+#: models.py:739
 msgid "Can impersonate"
 msgstr ""
 
-#: models.py:660
+#: models.py:740
 msgid "Can use search"
 msgstr ""
 
-#: models.py:661
+#: models.py:741
 msgid "Can change site preferences"
 msgstr ""
 
-#: models.py:662
+#: models.py:742
 msgid "Can change person preferences"
 msgstr ""
 
-#: models.py:663
+#: models.py:743
 msgid "Can change group preferences"
 msgstr ""
 
-#: preferences.py:27
+#: preferences.py:24
+msgid "Authentication"
+msgstr ""
+
+#: preferences.py:33
 msgid "Site title"
 msgstr ""
 
-#: preferences.py:36
+#: preferences.py:42
 msgid "Site description"
 msgstr ""
 
-#: preferences.py:45
+#: preferences.py:51
 msgid "Primary colour"
 msgstr ""
 
-#: preferences.py:54
+#: preferences.py:60
 msgid "Secondary colour"
 msgstr ""
 
-#: preferences.py:62
+#: preferences.py:68
 msgid "Logo"
 msgstr ""
 
-#: preferences.py:70
+#: preferences.py:76
 msgid "Favicon"
 msgstr ""
 
-#: preferences.py:78
+#: preferences.py:84
 msgid "PWA-Icon"
 msgstr ""
 
-#: preferences.py:87
+#: preferences.py:93
 msgid "Mail out name"
 msgstr ""
 
-#: preferences.py:96
+#: preferences.py:102
 msgid "Mail out address"
 msgstr ""
 
-#: preferences.py:106
+#: preferences.py:112
 msgid "Link to privacy policy"
 msgstr ""
 
-#: preferences.py:116
+#: preferences.py:122
 msgid "Link to imprint"
 msgstr ""
 
-#: preferences.py:126
+#: preferences.py:132
 msgid "Name format for addressing"
 msgstr ""
 
-#: preferences.py:140
+#: preferences.py:146
 msgid "Channels to use for notifications"
 msgstr ""
 
-#: preferences.py:150
+#: preferences.py:156
 msgid "Regular expression to match primary group, e.g. '^Class .*'"
 msgstr ""
 
-#: preferences.py:159
+#: preferences.py:165
 msgid "Field on person to match primary group against"
 msgstr ""
 
-#: preferences.py:171
+#: preferences.py:177
 msgid "Display name of the school"
 msgstr ""
 
-#: preferences.py:180
+#: preferences.py:186
 msgid "Official name of the school, e.g. as given by supervisory authority"
 msgstr ""
 
-#: settings.py:276
+#: preferences.py:194
+msgid "Enabled custom authentication backends"
+msgstr ""
+
+#: settings.py:300
 msgid "English"
 msgstr ""
 
-#: settings.py:277
+#: settings.py:301
 msgid "German"
 msgstr ""
 
-#: settings.py:278
+#: settings.py:302
 msgid "French"
 msgstr ""
 
-#: templates/403.html:10 templates/404.html:10 templates/500.html:10
+#: settings.py:303
+msgid "Norwegian (bokmål)"
+msgstr ""
+
+#: tables.py:19 templates/core/announcement/list.html:36
+#: templates/core/group/full.html:23 templates/core/person/full.html:22
+msgid "Edit"
+msgstr ""
+
+#: tables.py:21 templates/core/announcement/list.html:22
+msgid "Actions"
+msgstr ""
+
+#: tables.py:56 tables.py:57 tables.py:71
+#: templates/core/announcement/list.html:42 templates/core/group/full.html:30
+#: templates/core/pages/delete.html:22 templates/core/person/full.html:29
+msgid "Delete"
+msgstr ""
+
+#: templates/403.html:14 templates/404.html:10 templates/500.html:10
 msgid "Error"
 msgstr ""
 
-#: templates/403.html:10
+#: templates/403.html:14
 msgid ""
 "You are not allowed to access the requested page or\n"
 "          object."
 msgstr ""
 
-#: templates/403.html:13 templates/404.html:17
+#: templates/403.html:19 templates/404.html:17
 msgid ""
 "\n"
-"            If you think this is an error in AlekSIS, please contact your "
-"site\n"
+"            If you think this is an error in AlekSIS, please contact your site\n"
 "            administrators:\n"
 "          "
 msgstr ""
@@ -659,8 +733,7 @@ msgstr ""
 #: templates/500.html:13
 msgid ""
 "\n"
-"            Your site administrators will automatically be notified about "
-"this\n"
+"            Your site administrators will automatically be notified about this\n"
 "            error. You can also contact them directly:\n"
 "          "
 msgstr ""
@@ -674,75 +747,17 @@ msgstr ""
 #: templates/503.html:13
 msgid ""
 "\n"
-"            This page is currently unavailable. If this error persists, "
-"contact your site administrators:\n"
+"            This page is currently unavailable. If this error persists, contact your site administrators:\n"
 "          "
 msgstr ""
 
-#: templates/core/about.html:6 templates/core/about.html:15
-msgid "About AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:7
-msgid "AlekSIS – The Free School Information System"
-msgstr ""
-
-#: templates/core/about.html:17
-msgid ""
-"\n"
-"              This platform is powered by AlekSIS, a web-based school "
-"information system (SIS) which can be used\n"
-"              to manage and/or publish organisational artifacts of "
-"educational institutions. AlekSIS is free software and\n"
-"              can be used by anyone.\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:25
-msgid "Website of AlekSIS"
+#: templates/core/additional_field/edit.html:6
+#: templates/core/additional_field/edit.html:7
+msgid "Edit additional field"
 msgstr ""
 
-#: templates/core/about.html:26
-msgid "Source code"
-msgstr ""
-
-#: templates/core/about.html:35
-msgid "Licence information"
-msgstr ""
-
-#: templates/core/about.html:37
-msgid ""
-"\n"
-"              The core and the official apps of AlekSIS are licenced under "
-"the EUPL, version 1.2 or later. For licence\n"
-"              information from third-party apps, if installed, refer to the "
-"respective components below. The\n"
-"              licences are marked like this:\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:45
-msgid "Free/Open Source Licence"
-msgstr ""
-
-#: templates/core/about.html:46
-msgid "Other Licence"
-msgstr ""
-
-#: templates/core/about.html:50
-msgid "Full licence text"
-msgstr ""
-
-#: templates/core/about.html:51
-msgid "More information about the EUPL"
-msgstr ""
-
-#: templates/core/about.html:90
-#, python-format
-msgid ""
-"\n"
-"                    This app is licenced under %(licence)s.\n"
-"                  "
+#: templates/core/additional_field/list.html:14
+msgid "Create additional field"
 msgstr ""
 
 #: templates/core/announcement/form.html:10
@@ -775,163 +790,134 @@ msgstr ""
 msgid "Recipients"
 msgstr ""
 
-#: templates/core/announcement/list.html:22
-msgid "Actions"
-msgstr ""
-
-#: templates/core/announcement/list.html:36 templates/core/group_full.html:22
-#: templates/core/person_full.html:21
-msgid "Edit"
-msgstr ""
-
-#: templates/core/announcement/list.html:42
-msgid "Delete"
-msgstr ""
-
 #: templates/core/announcement/list.html:50
 msgid "There are no announcements."
 msgstr ""
 
-#: templates/core/announcements.html:9 templates/core/announcements.html:36
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:13
-#, python-format
-msgid ""
-"\n"
-"              Valid from %(from)s until %(until)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:40
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s – %(until)s\n"
-"            "
-msgstr ""
-
 #: templates/core/base.html:54
 msgid "Logged in as"
 msgstr ""
 
-#: templates/core/base.html:76 templates/search/search.html:7
-#: templates/search/search.html:22
-msgid "Search"
-msgstr ""
-
-#: templates/core/base.html:148
+#: templates/core/base.html:147
 msgid "About AlekSIS — The Free School Information System"
 msgstr ""
 
-#: templates/core/base.html:156
+#: templates/core/base.html:155
 msgid "Impress"
 msgstr ""
 
-#: templates/core/base.html:164
+#: templates/core/base.html:163
 msgid "Privacy Policy"
 msgstr ""
 
-#: templates/core/base_print.html:62
+#: templates/core/base_print.html:64
 msgid "Powered by AlekSIS"
 msgstr ""
 
-#: templates/core/edit_group.html:6 templates/core/edit_group.html:7
-msgid "Edit group"
-msgstr ""
-
-#: templates/core/edit_person.html:8 templates/core/edit_person.html:9
-msgid "Edit person"
-msgstr ""
-
-#: templates/core/group_full.html:28 templates/core/person_full.html:28
-msgid "Change preferences"
-msgstr ""
-
-#: templates/core/groups.html:14
-msgid "Create group"
-msgstr ""
-
-#: templates/core/groups_child_groups.html:18
+#: templates/core/group/child_groups.html:18
 msgid ""
 "\n"
-"          You can use this to assign child groups to groups. Please use the "
-"filters below to select groups you want to\n"
+"          You can use this to assign child groups to groups. Please use the filters below to select groups you want to\n"
 "          change and click \"Next\".\n"
 "        "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:31
+#: templates/core/group/child_groups.html:31
 msgid "Update selection"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:35
+#: templates/core/group/child_groups.html:35
 msgid "Clear all filters"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:39
+#: templates/core/group/child_groups.html:39
 msgid "Currently selected groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:52
+#: templates/core/group/child_groups.html:52
 msgid "Start assigning child groups for this groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:61
+#: templates/core/group/child_groups.html:61
 msgid ""
 "\n"
 "            Please select some groups in order to go on with assigning.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:72
+#: templates/core/group/child_groups.html:72
 msgid "Current group:"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:78
+#: templates/core/group/child_groups.html:78
 msgid "Please be careful!"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:79
+#: templates/core/group/child_groups.html:79
 msgid ""
 "\n"
-"            If you click \"Back\" or \"Next\" the current group assignments "
-"are not saved.\n"
-"            If you click \"Save\", you will overwrite all existing child "
-"group relations for this group with what you\n"
+"            If you click \"Back\" or \"Next\" the current group assignments are not saved.\n"
+"            If you click \"Save\", you will overwrite all existing child group relations for this group with what you\n"
 "            selected on this page.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:93
-#: templates/core/groups_child_groups.html:128
+#: templates/core/group/child_groups.html:93
+#: templates/core/group/child_groups.html:128
 #: templates/two_factor/_wizard_actions.html:15
 #: templates/two_factor/_wizard_actions.html:20
 msgid "Back"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:99
-#: templates/core/groups_child_groups.html:134
+#: templates/core/group/child_groups.html:99
+#: templates/core/group/child_groups.html:134
 #: templates/two_factor/_wizard_actions.html:26
 msgid "Next"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:106
-#: templates/core/groups_child_groups.html:141
-#: templates/core/save_button.html:3
+#: templates/core/group/child_groups.html:106
+#: templates/core/group/child_groups.html:141
+#: templates/core/partials/save_button.html:3
 msgid "Save"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:112
-#: templates/core/groups_child_groups.html:147
+#: templates/core/group/child_groups.html:112
+#: templates/core/group/child_groups.html:147
 msgid "Save and next"
 msgstr ""
 
+#: templates/core/group/edit.html:6 templates/core/group/edit.html:7
+msgid "Edit group"
+msgstr ""
+
+#: templates/core/group/full.html:37 templates/core/person/full.html:36
+msgid "Change preferences"
+msgstr ""
+
+#: templates/core/group/list.html:14
+msgid "Create group"
+msgstr ""
+
+#: templates/core/group/list.html:17
+msgid "Filter groups"
+msgstr ""
+
+#: templates/core/group/list.html:24 templates/core/person/list.html:28
+msgid "Clear"
+msgstr ""
+
+#: templates/core/group/list.html:28
+msgid "Selected groups"
+msgstr ""
+
+#: templates/core/group_type/edit.html:6 templates/core/group_type/edit.html:7
+msgid "Edit group type"
+msgstr ""
+
+#: templates/core/group_type/list.html:14
+msgid "Create group type"
+msgstr ""
+
 #: templates/core/index.html:4
 msgid "Home"
 msgstr ""
@@ -956,105 +942,328 @@ msgstr ""
 msgid "No notifications available yet."
 msgstr ""
 
-#: templates/core/no_person.html:12
+#: templates/core/pages/about.html:6 templates/core/pages/about.html:15
+msgid "About AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:7
+msgid "AlekSIS – The Free School Information System"
+msgstr ""
+
+#: templates/core/pages/about.html:17
 msgid ""
 "\n"
-"            Your administrator account is not linked to any person. "
-"Therefore,\n"
-"            a dummy person has been linked to your account.\n"
-"          "
+"              This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used\n"
+"              to manage and/or publish organisational artifacts of educational institutions. AlekSIS is free software and\n"
+"              can be used by anyone.\n"
+"            "
 msgstr ""
 
-#: templates/core/no_person.html:19
+#: templates/core/pages/about.html:25
+msgid "Website of AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:26
+msgid "Source code"
+msgstr ""
+
+#: templates/core/pages/about.html:35
+msgid "Licence information"
+msgstr ""
+
+#: templates/core/pages/about.html:37
 msgid ""
 "\n"
-"            Your user account is not linked to a person. This means you\n"
-"            cannot access any school-related information. Please contact\n"
-"            the managers of AlekSIS at your school.\n"
-"          "
+"              The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence\n"
+"              information from third-party apps, if installed, refer to the respective components below. The\n"
+"              licences are marked like this:\n"
+"            "
 msgstr ""
 
-#: templates/core/person_full.html:34
-msgid "Contact details"
+#: templates/core/pages/about.html:45
+msgid "Free/Open Source Licence"
 msgstr ""
 
-#: templates/core/persons_accounts.html:7
-#: templates/core/persons_accounts.html:9
-msgid "Link persons to accounts"
+#: templates/core/pages/about.html:46
+msgid "Other Licence"
+msgstr ""
+
+#: templates/core/pages/about.html:50
+msgid "Full licence text"
+msgstr ""
+
+#: templates/core/pages/about.html:51
+msgid "More information about the EUPL"
 msgstr ""
 
-#: templates/core/persons_accounts.html:16
+#: templates/core/pages/about.html:90
+#, python-format
 msgid ""
 "\n"
-"        You can use this form to assign user accounts to persons. Use the\n"
-"        dropdowns to select existing accounts; use the text fields to create "
-"new\n"
-"        accounts on-the-fly. The latter will create a new account with the\n"
-"        entered username and copy all other details from the person.\n"
-"      "
+"                    This app is licenced under %(licence)s.\n"
+"                  "
 msgstr ""
 
-#: templates/core/persons_accounts.html:31
-#: templates/core/persons_accounts.html:55
-msgid "Update"
+#: templates/core/pages/delete.html:6
+#, python-format
+msgid "Delete %(object_name)s"
 msgstr ""
 
-#: templates/core/persons_accounts.html:37
-msgid "Existing account"
+#: templates/core/pages/delete.html:13
+#, python-format
+msgid ""
+"\n"
+"      Do you really want to delete the %(object_name)s \"%(object)s\"?\n"
+"    "
 msgstr ""
 
-#: templates/core/persons_accounts.html:38
-msgid "New account"
+#: templates/core/pages/offline.html:6
+msgid ""
+"No internet\n"
+"    connection."
+msgstr ""
+
+#: templates/core/pages/offline.html:10
+msgid ""
+"\n"
+"      There was an error accessing this page. You probably don't have an internet connection. Check to see if your WiFi\n"
+"      or mobile data is turned on and try again. If you think you are connected, please contact the system\n"
+"      administrators:\n"
+"    "
+msgstr ""
+
+#: templates/core/pages/progress.html:27
+msgid ""
+"\n"
+"              Without activated JavaScript the progress status can't be updated.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/progress.html:47
+#: templates/two_factor/core/otp_required.html:19
+msgid "Go back"
 msgstr ""
 
-#: templates/core/system_status.html:12
+#: templates/core/pages/system_status.html:12
 msgid "System checks"
 msgstr ""
 
-#: templates/core/system_status.html:21
+#: templates/core/pages/system_status.html:21
 msgid "Maintenance mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:23
+#: templates/core/pages/system_status.html:23
 msgid ""
 "\n"
-"                Only admin and visitors from internal IPs can access "
-"thesite.\n"
+"                Only admin and visitors from internal IPs can access thesite.\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:34
+#: templates/core/pages/system_status.html:34
 msgid "Maintenance mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:35
+#: templates/core/pages/system_status.html:35
 msgid "Everyone can access the site."
 msgstr ""
 
-#: templates/core/system_status.html:45
+#: templates/core/pages/system_status.html:45
 msgid "Debug mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:47
+#: templates/core/pages/system_status.html:47
 msgid ""
 "\n"
-"                The web server throws back debug information on errors. Do "
-"not use in production!\n"
+"                The web server throws back debug information on errors. Do not use in production!\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:54
+#: templates/core/pages/system_status.html:54
 msgid "Debug mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:56
+#: templates/core/pages/system_status.html:56
 msgid ""
 "\n"
-"                Debug mode is disabled. Default error pages are displayed on "
-"errors.\n"
+"                Debug mode is disabled. Default error pages are displayed on errors.\n"
 "              "
 msgstr ""
 
+#: templates/core/pages/system_status.html:69
+msgid "System health checks"
+msgstr ""
+
+#: templates/core/pages/system_status.html:75
+msgid "Service"
+msgstr ""
+
+#: templates/core/pages/system_status.html:76
+#: templates/core/pages/system_status.html:115
+msgid "Status"
+msgstr ""
+
+#: templates/core/pages/system_status.html:77
+msgid "Time taken"
+msgstr ""
+
+#: templates/core/pages/system_status.html:96
+msgid "seconds"
+msgstr ""
+
+#: templates/core/pages/system_status.html:107
+msgid "Celery task results"
+msgstr ""
+
+#: templates/core/pages/system_status.html:112
+msgid "Task"
+msgstr ""
+
+#: templates/core/pages/system_status.html:113
+msgid "ID"
+msgstr ""
+
+#: templates/core/pages/system_status.html:114
+msgid "Date done"
+msgstr ""
+
+#: templates/core/partials/announcements.html:9
+#: templates/core/partials/announcements.html:36
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:13
+#, python-format
+msgid ""
+"\n"
+"              Valid from %(from)s until %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:40
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s – %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:10
+#, python-format
+msgid ""
+"\n"
+"              Created by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:14
+#: templates/core/partials/crud_events.html:22
+#: templates/core/partials/crud_events.html:26
+#, python-format
+msgid ""
+"\n"
+"              Updated by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:18
+#, python-format
+msgid ""
+"\n"
+"              Deleted by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/language_form.html:16
+msgid "Language"
+msgstr ""
+
+#: templates/core/partials/language_form.html:28
+msgid "Select language"
+msgstr ""
+
+#: templates/core/partials/no_person.html:12
+msgid ""
+"\n"
+"            Your administrator account is not linked to any person. Therefore,\n"
+"            a dummy person has been linked to your account.\n"
+"          "
+msgstr ""
+
+#: templates/core/partials/no_person.html:19
+msgid ""
+"\n"
+"            Your user account is not linked to a person. This means you\n"
+"            cannot access any school-related information. Please contact\n"
+"            the managers of AlekSIS at your school.\n"
+"          "
+msgstr ""
+
+#: templates/core/person/accounts.html:7 templates/core/person/accounts.html:9
+msgid "Link persons to accounts"
+msgstr ""
+
+#: templates/core/person/accounts.html:16
+msgid ""
+"\n"
+"        You can use this form to assign user accounts to persons. Use the\n"
+"        dropdowns to select existing accounts; use the text fields to create new\n"
+"        accounts on-the-fly. The latter will create a new account with the\n"
+"        entered username and copy all other details from the person.\n"
+"      "
+msgstr ""
+
+#: templates/core/person/accounts.html:31
+#: templates/core/person/accounts.html:55
+msgid "Update"
+msgstr ""
+
+#: templates/core/person/accounts.html:37
+msgid "Existing account"
+msgstr ""
+
+#: templates/core/person/accounts.html:38
+msgid "New account"
+msgstr ""
+
+#: templates/core/person/edit.html:11 templates/core/person/edit.html:12
+msgid "Edit person"
+msgstr ""
+
+#: templates/core/person/full.html:42
+msgid "Contact details"
+msgstr ""
+
+#: templates/core/person/full.html:122
+msgid "Children"
+msgstr ""
+
+#: templates/core/person/list.html:17
+msgid "Create person"
+msgstr ""
+
+#: templates/core/person/list.html:21
+msgid "Filter persons"
+msgstr ""
+
+#: templates/core/person/list.html:32
+msgid "Selected persons"
+msgstr ""
+
+#: templates/core/school_term/create.html:6
+#: templates/core/school_term/create.html:7
+#: templates/core/school_term/list.html:14
+msgid "Create school term"
+msgstr ""
+
+#: templates/core/school_term/edit.html:6
+#: templates/core/school_term/edit.html:7
+msgid "Edit school term"
+msgstr ""
+
 #: templates/dynamic_preferences/form.html:9
 msgid "Site preferences"
 msgstr ""
@@ -1080,23 +1289,6 @@ msgstr ""
 msgid "Impersonate user"
 msgstr ""
 
-#: templates/offline.html:6
-msgid ""
-"No internet\n"
-"    connection."
-msgstr ""
-
-#: templates/offline.html:10
-msgid ""
-"\n"
-"      There was an error accessing this page. You probably don't have an "
-"internet connection. Check to see if your WiFi\n"
-"      or mobile data is turned on and try again. If you think you are "
-"connected, please contact the system\n"
-"      administrators:\n"
-"    "
-msgstr ""
-
 #: templates/search/search.html:8
 msgid "Global Search"
 msgstr ""
@@ -1121,28 +1313,43 @@ msgstr ""
 msgid "New notification for"
 msgstr ""
 
-#: templates/templated_email/notification.email:7
-msgid "Dear"
+#: templates/templated_email/notification.email:6
+#: templates/templated_email/notification.email:27
+#, python-format
+msgid "Dear %(notification_user)s,"
 msgstr ""
 
 #: templates/templated_email/notification.email:8
+#: templates/templated_email/notification.email:29
 msgid "we got a new notification for you:"
 msgstr ""
 
-#: templates/templated_email/notification.email:12
+#: templates/templated_email/notification.email:15
+#: templates/templated_email/notification.email:35
 msgid "More information"
 msgstr ""
 
-#: templates/templated_email/notification.email:16
+#: templates/templated_email/notification.email:18
 #, python-format
 msgid ""
 "\n"
-"    <p>By %(trans_sender)s at %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Your AlekSIS team</i>\n"
+"        Sent by %(trans_sender)s at %(trans_created_at)s\n"
 "    "
 msgstr ""
 
+#: templates/templated_email/notification.email:22
+#: templates/templated_email/notification.email:46
+msgid "Your AlekSIS team"
+msgstr ""
+
+#: templates/templated_email/notification.email:40
+#, python-format
+msgid ""
+"\n"
+"            Sent by %(trans_sender)s at %(trans_created_at)s\n"
+"        "
+msgstr ""
+
 #: templates/two_factor/_base_focus.html:6
 #: templates/two_factor/core/otp_required.html:22
 #: templates/two_factor/core/setup.html:5
@@ -1165,10 +1372,8 @@ msgid ""
 "\n"
 "        Backup tokens can be used when your primary and backup\n"
 "        phone numbers aren't available. The backup tokens below can be used\n"
-"        for login verification. If you've used up all your backup tokens, "
-"you\n"
-"        can generate a new set of backup tokens. Only the backup tokens "
-"shown\n"
+"        for login verification. If you've used up all your backup tokens, you\n"
+"        can generate a new set of backup tokens. Only the backup tokens shown\n"
 "        below will be valid.\n"
 "      "
 msgstr ""
@@ -1193,52 +1398,58 @@ msgid "Generate Tokens"
 msgstr ""
 
 #: templates/two_factor/core/login.html:16
-msgid ""
-"You have no permission to view this page. Please login with an other account."
+msgid "You have no permission to view this page. Please login with an other account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:25
+#: templates/two_factor/core/login.html:24
 msgid "Please login to see this page."
 msgstr ""
 
-#: templates/two_factor/core/login.html:28
+#: templates/two_factor/core/login.html:30
+msgid "Login with username and password"
+msgstr ""
+
+#: templates/two_factor/core/login.html:40
 msgid ""
 "We are calling your phone right now, please enter the\n"
 "              digits you hear."
 msgstr ""
 
-#: templates/two_factor/core/login.html:31
+#: templates/two_factor/core/login.html:43
 msgid ""
 "We sent you a text message, please enter the tokens we\n"
 "              sent."
 msgstr ""
 
-#: templates/two_factor/core/login.html:34
+#: templates/two_factor/core/login.html:46
 msgid ""
 "Please enter the tokens generated by your token\n"
 "              generator."
 msgstr ""
 
-#: templates/two_factor/core/login.html:38
+#: templates/two_factor/core/login.html:50
 msgid ""
 "Use this form for entering backup tokens for logging in.\n"
-"            These tokens have been generated for you to print and keep safe. "
-"Please\n"
+"            These tokens have been generated for you to print and keep safe. Please\n"
 "            enter one of these backup tokens to login to your account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:56
+#: templates/two_factor/core/login.html:68
 msgid "Or, alternatively, use one of your backup phones:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:66
+#: templates/two_factor/core/login.html:78
 msgid "As a last resort, you can use a backup token:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:69
+#: templates/two_factor/core/login.html:81
 msgid "Use Backup Token"
 msgstr ""
 
+#: templates/two_factor/core/login.html:93
+msgid "Use alternative login options"
+msgstr ""
+
 #: templates/two_factor/core/otp_required.html:9
 msgid "Permission Denied"
 msgstr ""
@@ -1246,8 +1457,7 @@ msgstr ""
 #: templates/two_factor/core/otp_required.html:10
 msgid ""
 "The page you requested, enforces users to verify using\n"
-"          two-factor authentication for security reasons. You need to enable "
-"these\n"
+"          two-factor authentication for security reasons. You need to enable these\n"
 "          security features in order to access this page."
 msgstr ""
 
@@ -1258,10 +1468,6 @@ msgid ""
 "          security."
 msgstr ""
 
-#: templates/two_factor/core/otp_required.html:19
-msgid "Go back"
-msgstr ""
-
 #: templates/two_factor/core/phone_register.html:5
 #: templates/two_factor/core/phone_register.html:9
 msgid "Add Backup Phone"
@@ -1324,8 +1530,7 @@ msgstr ""
 #: templates/two_factor/core/setup.html:50
 msgid ""
 "\n"
-"            We are calling your phone right now, please enter the digits you "
-"hear.\n"
+"            We are calling your phone right now, please enter the digits you hear.\n"
 "          "
 msgstr ""
 
@@ -1339,12 +1544,9 @@ msgstr ""
 #: templates/two_factor/core/setup.html:63
 msgid ""
 "\n"
-"          We've encountered an issue with the selected authentication "
-"method. Please\n"
-"          go back and verify that you entered your information correctly, "
-"try\n"
-"          again, or use a different authentication method instead. If the "
-"issue\n"
+"          We've encountered an issue with the selected authentication method. Please\n"
+"          go back and verify that you entered your information correctly, try\n"
+"          again, or use a different authentication method instead. If the issue\n"
 "          persists, contact the site administrator.\n"
 "        "
 msgstr ""
@@ -1366,8 +1568,7 @@ msgstr ""
 #: templates/two_factor/core/setup_complete.html:14
 msgid ""
 "\n"
-"        Congratulations, you've successfully enabled two-factor "
-"authentication.\n"
+"        Congratulations, you've successfully enabled two-factor authentication.\n"
 "      "
 msgstr ""
 
@@ -1385,8 +1586,7 @@ msgstr ""
 msgid ""
 "\n"
 "          However, it might happen that you don't have access to\n"
-"          your primary token device. To enable account recovery, generate "
-"backup codes\n"
+"          your primary token device. To enable account recovery, generate backup codes\n"
 "          or add a phone number.\n"
 "        "
 msgstr ""
@@ -1404,9 +1604,7 @@ msgid "Disable Two-Factor Authentication"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:12
-msgid ""
-"You are about to disable two-factor authentication. This weakens your "
-"account security, are you sure?"
+msgid "You are about to disable two-factor authentication. This weakens your account security, are you sure?"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:26
@@ -1497,26 +1695,58 @@ msgstr ""
 msgid "SMS"
 msgstr ""
 
-#: views.py:212
+#: views.py:122
+msgid "The school term has been created."
+msgstr ""
+
+#: views.py:133
+msgid "The school term has been saved."
+msgstr ""
+
+#: views.py:273
 msgid "The child groups were successfully saved."
 msgstr ""
 
-#: views.py:240
+#: views.py:309
 msgid "The person has been saved."
 msgstr ""
 
-#: views.py:276
+#: views.py:346
 msgid "The group has been saved."
 msgstr ""
 
-#: views.py:348
+#: views.py:434
 msgid "The announcement has been saved."
 msgstr ""
 
-#: views.py:364
+#: views.py:450
 msgid "The announcement has been deleted."
 msgstr ""
 
-#: views.py:435
+#: views.py:521
 msgid "The preferences have been saved successfully."
 msgstr ""
+
+#: views.py:544
+msgid "The person has been deleted."
+msgstr ""
+
+#: views.py:557
+msgid "The group has been deleted."
+msgstr ""
+
+#: views.py:588
+msgid "The additional_field has been saved."
+msgstr ""
+
+#: views.py:622
+msgid "The additional field has been deleted."
+msgstr ""
+
+#: views.py:646
+msgid "The group type has been saved."
+msgstr ""
+
+#: views.py:676
+msgid "The group type has been deleted."
+msgstr ""
diff --git a/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po b/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po
index 28f74abb7354ad25df12874286481ef1858f96a0..c48da556b093acc67242995ed684ce8bfa609426 100644
--- a/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po
+++ b/aleksis/core/locale/ar/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-04-28 13:31+0000\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/aleksis/core/locale/de_DE/LC_MESSAGES/django.po b/aleksis/core/locale/de_DE/LC_MESSAGES/django.po
index d8fe1369884426025d603c428f4a4eb21b13d313..e59806834f65d4acced6f3adea79b24ccf3b2f3f 100644
--- a/aleksis/core/locale/de_DE/LC_MESSAGES/django.po
+++ b/aleksis/core/locale/de_DE/LC_MESSAGES/django.po
@@ -7,9 +7,9 @@ msgid ""
 msgstr ""
 "Project-Id-Version: AlekSIS (School Information System) 0.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-04 15:39+0200\n"
-"PO-Revision-Date: 2020-05-04 15:09+0000\n"
-"Last-Translator: Anonymous <noreply@weblate.org>\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
+"PO-Revision-Date: 2020-08-02 15:00+0000\n"
+"Last-Translator: Jonathan Weth <teckids@jonathanweth.de>\n"
 "Language-Team: German <https://translate.edugit.org/projects/aleksis/aleksis/"
 "de/>\n"
 "Language: de_DE\n"
@@ -19,11 +19,23 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Generator: Weblate 4.0.1\n"
 
+#: filters.py:37 templates/core/base.html:77 templates/core/group/list.html:20
+#: templates/core/person/list.html:24 templates/search/search.html:7
+#: templates/search/search.html:22
+msgid "Search"
+msgstr "Suchen"
+
+#: filters.py:53
+msgid "Search by name"
+msgstr "Nach Namen suchen"
+
+#: filters.py:65
+msgid "Search by contact details"
+msgstr "Nach Kontaktdetails suchen"
+
 #: forms.py:46
 msgid "You cannot set a new username when also selecting an existing user."
-msgstr ""
-"Sie können keine neuen Benutzer erstellen, wenn Sie gleichzeitig einen "
-"existierenden Benutzer auswählen."
+msgstr "Sie können keine neuen Benutzer erstellen, wenn Sie gleichzeitig einen existierenden Benutzer auswählen."
 
 #: forms.py:50
 msgid "This username is already in use."
@@ -45,68 +57,71 @@ msgstr "Kontaktdaten"
 msgid "Advanced personal data"
 msgstr "Zusätzliche persönliche Daten"
 
-#: forms.py:116
+#: forms.py:114
 msgid "New user"
 msgstr "Neuer Benutzer"
 
-#: forms.py:116
+#: forms.py:114
 msgid "Create a new account"
 msgstr "Neues Benutzerkonto erstellen"
 
-#: forms.py:128
+#: forms.py:126 models.py:91
+msgid "School term"
+msgstr "Schuljahr"
+
+#: forms.py:127
 msgid "Common data"
 msgstr "Allgemeine Daten"
 
-#: forms.py:129 forms.py:169 menus.py:141 models.py:54
-#: templates/core/persons.html:8 templates/core/persons.html:9
+#: forms.py:128 forms.py:170 menus.py:152 models.py:105
+#: templates/core/person/list.html:8 templates/core/person/list.html:9
 msgid "Persons"
 msgstr "Personen"
 
-#: forms.py:162 forms.py:165 models.py:31
+#: forms.py:129
+msgid "Additional data"
+msgstr "Zusätzliche Datne"
+
+#: forms.py:163 forms.py:166 models.py:35
 msgid "Date"
 msgstr "Datum"
 
-#: forms.py:163 forms.py:166 models.py:39
+#: forms.py:164 forms.py:167 models.py:43
 msgid "Time"
 msgstr "Zeit"
 
-#: forms.py:171 menus.py:149 models.py:253 templates/core/groups.html:8
-#: templates/core/groups.html:9 templates/core/person_full.html:106
+#: forms.py:172 menus.py:160 models.py:319 templates/core/group/list.html:8
+#: templates/core/group/list.html:9 templates/core/person/full.html:136
 msgid "Groups"
 msgstr "Gruppen"
 
-#: forms.py:175
+#: forms.py:176
 msgid "From when until when should the announcement be displayed?"
 msgstr "Von wann bis wann soll die Ankündigung angezeigt werden?"
 
-#: forms.py:178
+#: forms.py:179
 msgid "Who should see the announcement?"
 msgstr "Wer soll die Ankündigung sehen?"
 
-#: forms.py:179
+#: forms.py:180
 msgid "Write your announcement:"
 msgstr "Schreiben Sie ihre Ankündigung:"
 
-#: forms.py:216
-msgid ""
-"You are not allowed to create announcements which are only valid in the past."
-msgstr ""
-"Sie dürfen keine Ankündigungen erstellen, die nur für die Vergangenheit "
-"gültig sind."
+#: forms.py:219
+msgid "You are not allowed to create announcements which are only valid in the past."
+msgstr "Sie dürfen keine Ankündigungen erstellen, die nur für die Vergangenheit gültig sind."
 
-#: forms.py:220
+#: forms.py:223
 msgid "The from date and time must be earlier then the until date and time."
-msgstr ""
-"Das Startdatum und die Startzeit müssen vor dem Enddatum und der Endzeit "
-"sein."
+msgstr "Das Startdatum und die Startzeit müssen vor dem Enddatum und der Endzeit sein."
 
-#: forms.py:229
+#: forms.py:232
 msgid "You need at least one recipient."
 msgstr "Sie benötigen mindestens einen Empfänger."
 
 #: menus.py:7 templates/two_factor/core/login.html:6
 #: templates/two_factor/core/login.html:10
-#: templates/two_factor/core/login.html:73
+#: templates/two_factor/core/login.html:86
 msgid "Login"
 msgstr "Anmelden"
 
@@ -142,493 +157,548 @@ msgstr "Einstellungen"
 msgid "Admin"
 msgstr "Admin"
 
-#: menus.py:75 models.py:487 templates/core/announcement/list.html:7
+#: menus.py:75 models.py:564 templates/core/announcement/list.html:7
 #: templates/core/announcement/list.html:8
 msgid "Announcements"
 msgstr "Ankündigungen"
 
-#: menus.py:86 templates/core/data_management.html:6
-#: templates/core/data_management.html:7
+#: menus.py:86 models.py:92 templates/core/school_term/list.html:8
+#: templates/core/school_term/list.html:9
+msgid "School terms"
+msgstr "Schuljahre"
+
+#: menus.py:97 templates/core/management/data_management.html:6
+#: templates/core/management/data_management.html:7
 msgid "Data management"
 msgstr "Datenverwaltung"
 
-#: menus.py:94 templates/core/system_status.html:5
-#: templates/core/system_status.html:7
+#: menus.py:105 templates/core/pages/system_status.html:5
+#: templates/core/pages/system_status.html:7
 msgid "System status"
 msgstr "Systemstatus"
 
-#: menus.py:105
+#: menus.py:116
 msgid "Impersonation"
 msgstr "Verkleidung"
 
-#: menus.py:113
+#: menus.py:124
 msgid "Configuration"
 msgstr "Konfiguration"
 
-#: menus.py:124
+#: menus.py:135
 msgid "Backend Admin"
 msgstr "Backend-Administration"
 
-#: menus.py:132
+#: menus.py:143
 msgid "People"
 msgstr "Leute"
 
-#: menus.py:157
+#: menus.py:168 models.py:727 templates/core/group_type/list.html:8
+#: templates/core/group_type/list.html:9
+msgid "Group types"
+msgstr "Gruppentypen"
+
+#: menus.py:179
 msgid "Persons and accounts"
 msgstr "Personen und Konten"
 
-#: menus.py:168
+#: menus.py:190
 msgid "Groups and child groups"
 msgstr "Gruppen und Kindgruppen"
 
-#: menus.py:183 templates/core/groups_child_groups.html:7
-#: templates/core/groups_child_groups.html:9
+#: menus.py:201 models.py:363 templates/core/additional_field/list.html:8
+#: templates/core/additional_field/list.html:9
+msgid "Additional fields"
+msgstr "Zusätzliche Felder"
+
+#: menus.py:216 templates/core/group/child_groups.html:7
+#: templates/core/group/child_groups.html:9
 msgid "Assign child groups to groups"
 msgstr "Kindgruppen zu Gruppen zuordnen"
 
-#: models.py:29
+#: mixins.py:406
+msgid "Linked school term"
+msgstr "Zugeordnetes Schuljahr"
+
+#: models.py:33
 msgid "Boolean (Yes/No)"
 msgstr "Boolean (Ja/Nein)"
 
-#: models.py:30
+#: models.py:34
 msgid "Text (one line)"
 msgstr "Text (eine Zeile)"
 
-#: models.py:32
+#: models.py:36
 msgid "Date and time"
 msgstr "Datum und Uhrzeit"
 
-#: models.py:33
+#: models.py:37
 msgid "Decimal number"
 msgstr "Dezimalzahl"
 
-#: models.py:34 models.py:95
+#: models.py:38 models.py:146
 msgid "E-mail address"
 msgstr "E-Mail-Adresse"
 
-#: models.py:35
+#: models.py:39
 msgid "Integer"
 msgstr "Ganze Zahl"
 
-#: models.py:36
+#: models.py:40
 msgid "IP address"
 msgstr "IP-Adresse"
 
-#: models.py:37
+#: models.py:41
 msgid "Boolean or empty (Yes/No/Neither)"
 msgstr "Boolean oder leer (Ja/Nein/weder)"
 
-#: models.py:38
+#: models.py:42
 msgid "Text (multi-line)"
 msgstr "Text (mehrzeilig)"
 
-#: models.py:40
+#: models.py:44
 msgid "URL / Link"
 msgstr "URL / Link"
 
-#: models.py:53 templates/core/persons_accounts.html:36
+#: models.py:56 models.py:700
+msgid "Name"
+msgstr "Name"
+
+#: models.py:58
+msgid "Start date"
+msgstr "Startdatum"
+
+#: models.py:59
+msgid "End date"
+msgstr "Enddatum"
+
+#: models.py:77
+msgid "The start date must be earlier than the end date."
+msgstr "Das Startdatum muss vor dem Enddatum liegen."
+
+#: models.py:84
+msgid "There is already a school term for this time or a part of this time."
+msgstr ""
+"Es gibt bereits ein Schuljahr für diesen Zeitraum oder einen Teilzeitraum."
+
+#: models.py:104 templates/core/person/accounts.html:36
 msgid "Person"
 msgstr "Person"
 
-#: models.py:56
+#: models.py:107
 msgid "Can view address"
 msgstr "Kann Adresse sehen"
 
-#: models.py:57
+#: models.py:108
 msgid "Can view contact details"
 msgstr "Kann Kontaktdetails sehen"
 
-#: models.py:58
+#: models.py:109
 msgid "Can view photo"
 msgstr "Kann Foto sehen"
 
-#: models.py:59
+#: models.py:110
 msgid "Can view persons groups"
 msgstr "Kann Gruppen einer Person sehen"
 
-#: models.py:60
+#: models.py:111
 msgid "Can view personal details"
 msgstr "Kann persönliche Daten sehen"
 
-#: models.py:65
+#: models.py:116
 msgid "female"
 msgstr "weiblich"
 
-#: models.py:65
+#: models.py:116
 msgid "male"
 msgstr "männlich"
 
-#: models.py:73
+#: models.py:124
 msgid "Linked user"
 msgstr "Verknüpfter Benutzer"
 
-#: models.py:75
+#: models.py:126
 msgid "Is person active?"
 msgstr "Ist die Person aktiv?"
 
-#: models.py:77
+#: models.py:128
 msgid "First name"
 msgstr "Vorname"
 
-#: models.py:78
+#: models.py:129
 msgid "Last name"
 msgstr "Nachname"
 
-#: models.py:80
+#: models.py:131
 msgid "Additional name(s)"
 msgstr "Zusätzliche Namen"
 
-#: models.py:84 models.py:260
+#: models.py:135 models.py:332
 msgid "Short name"
 msgstr "Kurzname"
 
-#: models.py:87
+#: models.py:138
 msgid "Street"
 msgstr "Straße"
 
-#: models.py:88
+#: models.py:139
 msgid "Street number"
 msgstr "Hausnummer"
 
-#: models.py:89
+#: models.py:140
 msgid "Postal code"
 msgstr "Postleitzahl"
 
-#: models.py:90
+#: models.py:141
 msgid "Place"
 msgstr "Ort"
 
-#: models.py:92
+#: models.py:143
 msgid "Home phone"
 msgstr "Festnetz"
 
-#: models.py:93
+#: models.py:144
 msgid "Mobile phone"
 msgstr "Handy"
 
-#: models.py:97
+#: models.py:148
 msgid "Date of birth"
 msgstr "Geburtsdatum"
 
-#: models.py:98
+#: models.py:149
 msgid "Sex"
 msgstr "Geschlecht"
 
-#: models.py:100
+#: models.py:151
 msgid "Photo"
 msgstr "Foto"
 
-#: models.py:105
+#: models.py:155 templates/core/person/full.html:129
 msgid "Guardians / Parents"
 msgstr "Erziehungsberechtigte / Eltern"
 
-#: models.py:112
+#: models.py:162
 msgid "Primary group"
 msgstr "Primärgruppe"
 
-#: models.py:115 models.py:346 models.py:370 models.py:455 models.py:643
+#: models.py:165 models.py:423 models.py:447 models.py:532 models.py:720
+#: templates/core/person/full.html:112
 msgid "Description"
 msgstr "Beschreibung"
 
-#: models.py:233
+#: models.py:296
 msgid "Title of field"
 msgstr "Feldtitel"
 
-#: models.py:235
+#: models.py:298
 msgid "Type of field"
 msgstr "Feldtyp"
 
-#: models.py:239
+#: models.py:305
 msgid "Addtitional field for groups"
 msgstr "Zusätzliche Felder für Gruppen"
 
-#: models.py:240
+#: models.py:306
 msgid "Addtitional fields for groups"
 msgstr "Zusätzliche Felder für Gruppen"
 
-#: models.py:252
+#: models.py:318
 msgid "Group"
 msgstr "Gruppe"
 
-#: models.py:254
+#: models.py:320
 msgid "Can assign child groups to groups"
 msgstr "Kann Kindgruppen zu Gruppen zuordnen"
 
-#: models.py:258
+#: models.py:330
 msgid "Long name"
 msgstr "Langer Name"
 
-#: models.py:268 templates/core/group_full.html:37
+#: models.py:340 templates/core/group/full.html:65
 msgid "Members"
 msgstr "Mitglieder"
 
-#: models.py:271 templates/core/group_full.html:34
+#: models.py:343 templates/core/group/full.html:62
 msgid "Owners"
 msgstr "Leiter/-innen"
 
-#: models.py:278
+#: models.py:350 templates/core/group/full.html:54
 msgid "Parent groups"
 msgstr "Übergeordnete Gruppen"
 
-#: models.py:286
+#: models.py:358
 msgid "Type of group"
 msgstr "Gruppentyp"
 
-#: models.py:290
-msgid "Additional fields"
-msgstr "Zusätzliche Felder"
-
-#: models.py:342
+#: models.py:419
 msgid "User"
 msgstr "Benutzer"
 
-#: models.py:345 models.py:369 models.py:454
+#: models.py:422 models.py:446 models.py:531
 #: templates/core/announcement/list.html:18
 msgid "Title"
 msgstr "Titel"
 
-#: models.py:348
+#: models.py:425
 msgid "Application"
 msgstr "Anwendung"
 
-#: models.py:354
+#: models.py:431
 msgid "Activity"
 msgstr "Aktivität"
 
-#: models.py:355
+#: models.py:432
 msgid "Activities"
 msgstr "Aktivitäten"
 
-#: models.py:361
+#: models.py:438
 msgid "Sender"
 msgstr "Absender"
 
-#: models.py:366
+#: models.py:443
 msgid "Recipient"
 msgstr "Empfänger"
 
-#: models.py:371 models.py:624
+#: models.py:448 models.py:701
 msgid "Link"
 msgstr "Link"
 
-#: models.py:373
+#: models.py:450
 msgid "Read"
 msgstr "Gelesen"
 
-#: models.py:374
+#: models.py:451
 msgid "Sent"
 msgstr "Versandt"
 
-#: models.py:387
+#: models.py:464
 msgid "Notification"
 msgstr "Benachrichtigung"
 
-#: models.py:388
+#: models.py:465
 msgid "Notifications"
 msgstr "Benachrichtigungen"
 
-#: models.py:456
+#: models.py:533
 msgid "Link to detailed view"
 msgstr "Link zur detaillierten Ansicht"
 
-#: models.py:459
+#: models.py:536
 msgid "Date and time from when to show"
 msgstr "Datum und Uhrzeit des Anzeigestarts"
 
-#: models.py:462
+#: models.py:539
 msgid "Date and time until when to show"
 msgstr "Anzeigezeitraum"
 
-#: models.py:486
+#: models.py:563
 msgid "Announcement"
 msgstr "Ankündigung"
 
-#: models.py:524
+#: models.py:601
 msgid "Announcement recipient"
 msgstr "Empfänger der Ankündigung"
 
-#: models.py:525
+#: models.py:602
 msgid "Announcement recipients"
 msgstr "Empfänger der Ankündigung"
 
-#: models.py:575
+#: models.py:652
 msgid "Widget Title"
 msgstr "Widget-Titel"
 
-#: models.py:576
+#: models.py:653
 msgid "Activate Widget"
 msgstr "Widget aktivieren"
 
-#: models.py:594
+#: models.py:671
 msgid "Dashboard Widget"
 msgstr "Dashboard-Widget"
 
-#: models.py:595
+#: models.py:672
 msgid "Dashboard Widgets"
 msgstr "Dashboard-Widgets"
 
-#: models.py:601
+#: models.py:678
 msgid "Menu ID"
 msgstr "Menü-ID"
 
-#: models.py:613
+#: models.py:690
 msgid "Custom menu"
 msgstr "Benutzerdefiniertes Menü"
 
-#: models.py:614
+#: models.py:691
 msgid "Custom menus"
 msgstr "Benutzerdefinierte Menüs"
 
-#: models.py:621
+#: models.py:698
 msgid "Menu"
 msgstr "Menü"
 
-#: models.py:623
-msgid "Name"
-msgstr "Name"
-
-#: models.py:625
+#: models.py:702
 msgid "Icon"
 msgstr "Icon"
 
-#: models.py:631
+#: models.py:708
 msgid "Custom menu item"
 msgstr "Benutzerdefiniertes Menüelement"
 
-#: models.py:632
+#: models.py:709
 msgid "Custom menu items"
 msgstr "Benutzerdefinierte Menüelemente"
 
-#: models.py:642
+#: models.py:719
 msgid "Title of type"
 msgstr "Titel des Typs"
 
-#: models.py:646
+#: models.py:726 templates/core/group/full.html:46
 msgid "Group type"
 msgstr "Gruppentyp"
 
-#: models.py:647
-msgid "Group types"
-msgstr "Gruppentypen"
-
-#: models.py:656
+#: models.py:736
 msgid "Can view system status"
 msgstr "Kann Systemstatus sehen"
 
-#: models.py:657
+#: models.py:737
 msgid "Can link persons to accounts"
 msgstr "Kann Personen mit Benutzerkonten verknüpfen"
 
-#: models.py:658
+#: models.py:738
 msgid "Can manage data"
 msgstr "Kann Daten verwalten"
 
-#: models.py:659
+#: models.py:739
 msgid "Can impersonate"
 msgstr "Kann sich verkleiden"
 
-#: models.py:660
+#: models.py:740
 msgid "Can use search"
 msgstr "Kann Suche benutzen"
 
-#: models.py:661
+#: models.py:741
 msgid "Can change site preferences"
 msgstr "Kann Konfiguration ändern"
 
-#: models.py:662
+#: models.py:742
 msgid "Can change person preferences"
 msgstr "Kann Einstellungen einer Person verändern"
 
-#: models.py:663
+#: models.py:743
 msgid "Can change group preferences"
 msgstr "Kann Einstellungen einer Gruppe verändern"
 
-#: preferences.py:27
+#: preferences.py:24
+msgid "Authentication"
+msgstr "Authentifizierung"
+
+#: preferences.py:33
 msgid "Site title"
 msgstr "Seitentitel"
 
-#: preferences.py:36
+#: preferences.py:42
 msgid "Site description"
 msgstr "Seitenbeschreibung"
 
-#: preferences.py:45
+#: preferences.py:51
 msgid "Primary colour"
 msgstr "Primärfarbe"
 
-#: preferences.py:54
+#: preferences.py:60
 msgid "Secondary colour"
 msgstr "Akzentfarbe"
 
-#: preferences.py:62
+#: preferences.py:68
 msgid "Logo"
 msgstr "Logo"
 
-#: preferences.py:70
+#: preferences.py:76
 msgid "Favicon"
 msgstr "Favicon"
 
-#: preferences.py:78
+#: preferences.py:84
 msgid "PWA-Icon"
 msgstr "PWA-Icon"
 
-#: preferences.py:87
+#: preferences.py:93
 msgid "Mail out name"
 msgstr "Ausgangsmailname"
 
-#: preferences.py:96
+#: preferences.py:102
 msgid "Mail out address"
 msgstr "E-Mail-Ausgangsadresse"
 
-#: preferences.py:106
+#: preferences.py:112
 msgid "Link to privacy policy"
 msgstr "Link zur Datenschutzerklärung"
 
-#: preferences.py:116
+#: preferences.py:122
 msgid "Link to imprint"
 msgstr "Link zum Impressum"
 
-#: preferences.py:126
+#: preferences.py:132
 msgid "Name format for addressing"
 msgstr "Namensformat für Anreden"
 
-#: preferences.py:140
+#: preferences.py:146
 msgid "Channels to use for notifications"
 msgstr "Aktivierte Benachrichtungskanäle"
 
-#: preferences.py:150
+#: preferences.py:156
 msgid "Regular expression to match primary group, e.g. '^Class .*'"
 msgstr "Regulärer Ausdruck um Primärgruppen zu finden, z. B.  '^Class .*'"
 
-#: preferences.py:159
+#: preferences.py:165
 msgid "Field on person to match primary group against"
 msgstr "Feld um Primärgruppen zu finden"
 
-#: preferences.py:171
+#: preferences.py:177
 msgid "Display name of the school"
 msgstr "Sichtbarer Name der Schule"
 
-#: preferences.py:180
+#: preferences.py:186
 msgid "Official name of the school, e.g. as given by supervisory authority"
-msgstr ""
-"Offizieller Name der Schule, wie er z.B. von der Behörde vorgegeben ist"
+msgstr "Offizieller Name der Schule, wie er z.B. von der Behörde vorgegeben ist"
 
-#: settings.py:276
+#: preferences.py:194
+msgid "Enabled custom authentication backends"
+msgstr "Benutzerdefinierte Authentifizierungsbackends aktivieren"
+
+#: settings.py:300
 msgid "English"
 msgstr "Englisch"
 
-#: settings.py:277
+#: settings.py:301
 msgid "German"
 msgstr "Deutsch"
 
-#: settings.py:278
+#: settings.py:302
 msgid "French"
 msgstr "Französisch"
 
-#: templates/403.html:10 templates/404.html:10 templates/500.html:10
+#: settings.py:303
+msgid "Norwegian (bokmål)"
+msgstr "Norwegisch (bokmål)"
+
+#: tables.py:19 templates/core/announcement/list.html:36
+#: templates/core/group/full.html:23 templates/core/person/full.html:22
+msgid "Edit"
+msgstr "Bearbeiten"
+
+#: tables.py:21 templates/core/announcement/list.html:22
+msgid "Actions"
+msgstr "Aktionen"
+
+#: tables.py:56 tables.py:57 tables.py:71
+#: templates/core/announcement/list.html:42 templates/core/group/full.html:30
+#: templates/core/pages/delete.html:22 templates/core/person/full.html:29
+msgid "Delete"
+msgstr "Löschen"
+
+#: templates/403.html:14 templates/404.html:10 templates/500.html:10
 msgid "Error"
 msgstr "Fehler"
 
-#: templates/403.html:10
+#: templates/403.html:14
 msgid ""
 "You are not allowed to access the requested page or\n"
 "          object."
@@ -636,17 +706,15 @@ msgstr ""
 "Es ist Ihnen nicht erlaubt, auf die angefragte Seite oder das angefragte\n"
 "             Objekt zuzugreifen."
 
-#: templates/403.html:13 templates/404.html:17
+#: templates/403.html:19 templates/404.html:17
 msgid ""
 "\n"
-"            If you think this is an error in AlekSIS, please contact your "
-"site\n"
+"            If you think this is an error in AlekSIS, please contact your site\n"
 "            administrators:\n"
 "          "
 msgstr ""
 "\n"
-"            Wenn Sie der Meinung sind, dass es sich um einen Fehler in "
-"AlekSIS handelt, kontaktieren Sie bitte einen Ihrer\n"
+"            Wenn Sie der Meinung sind, dass es sich um einen Fehler in AlekSIS handelt, kontaktieren Sie bitte einen Ihrer\n"
 "     Systemadministratoren:\n"
 "          "
 
@@ -666,8 +734,7 @@ msgid ""
 "          "
 msgstr ""
 "\n"
-"            Wenn Sie über einen Link auf einer externen Seite hierher "
-"gelangt sind,\n"
+"            Wenn Sie über einen Link auf einer externen Seite hierher gelangt sind,\n"
 "      ist es möglich, dass dieser veraltet war.\n"
 "          "
 
@@ -682,14 +749,12 @@ msgstr ""
 #: templates/500.html:13
 msgid ""
 "\n"
-"            Your site administrators will automatically be notified about "
-"this\n"
+"            Your site administrators will automatically be notified about this\n"
 "            error. You can also contact them directly:\n"
 "          "
 msgstr ""
 "\n"
-"            Ihre Administratoren werden automatisch über diesen Fehler "
-"informiert.\n"
+"            Ihre Administratoren werden automatisch über diesen Fehler informiert.\n"
 "      Sie können diese auch direkt kontaktieren:\n"
 "          "
 
@@ -704,97 +769,21 @@ msgstr ""
 #: templates/503.html:13
 msgid ""
 "\n"
-"            This page is currently unavailable. If this error persists, "
-"contact your site administrators:\n"
+"            This page is currently unavailable. If this error persists, contact your site administrators:\n"
 "          "
 msgstr ""
 "\n"
-"            Diese Seite ist aktuell nicht erreichbar. Wenn dieser Fehler "
-"bestehen bleibt, kontaktieren Sie bitte einen Ihrer Systemadministratoren:\n"
+"            Diese Seite ist aktuell nicht erreichbar. Wenn dieser Fehler bestehen bleibt, kontaktieren Sie bitte einen Ihrer Systemadministratoren:\n"
 "          "
 
-#: templates/core/about.html:6 templates/core/about.html:15
-msgid "About AlekSIS"
-msgstr "Über AlekSIS"
-
-#: templates/core/about.html:7
-msgid "AlekSIS – The Free School Information System"
-msgstr "AlekSIS – The Free School Information System"
-
-#: templates/core/about.html:17
-msgid ""
-"\n"
-"              This platform is powered by AlekSIS, a web-based school "
-"information system (SIS) which can be used\n"
-"              to manage and/or publish organisational artifacts of "
-"educational institutions. AlekSIS is free software and\n"
-"              can be used by anyone.\n"
-"            "
-msgstr ""
-"\n"
-"              Diese Plattform wird mit AlekSIS, einem webbasierten "
-"Schulinformationssystem (SIS), \n"
-"welches für die Verwaltung und/oder Veröffentlichung von "
-"Bildungseinrichtungen verwendet werden kann.\n"
-"AlekSIS ist freie Software und kann von jedem benutzt werden.\n"
-"            "
-
-#: templates/core/about.html:25
-msgid "Website of AlekSIS"
-msgstr "Website von AlekSIS"
-
-#: templates/core/about.html:26
-msgid "Source code"
-msgstr "Quellcode"
-
-#: templates/core/about.html:35
-msgid "Licence information"
-msgstr "Lizenzinformationen"
+#: templates/core/additional_field/edit.html:6
+#: templates/core/additional_field/edit.html:7
+msgid "Edit additional field"
+msgstr "Zusätzliches Feld bearbeiten"
 
-#: templates/core/about.html:37
-msgid ""
-"\n"
-"              The core and the official apps of AlekSIS are licenced under "
-"the EUPL, version 1.2 or later. For licence\n"
-"              information from third-party apps, if installed, refer to the "
-"respective components below. The\n"
-"              licences are marked like this:\n"
-"            "
-msgstr ""
-"\n"
-"              Der Core und die offiziellen Apps von AlekSIS sind unter der "
-"EUPL, Version 1.2 oder später, lizenziert. Für Lizenzinformationen\n"
-"zu Apps von Drittanbietern, wenn installiert, siehe direkt bei der "
-"jeweiligen App weiter unten auf dieser Seite. Die Lizenzen\n"
-"sind wie folgt markiert:\n"
-"            "
-
-#: templates/core/about.html:45
-msgid "Free/Open Source Licence"
-msgstr "Freie/Open Source Lizenz"
-
-#: templates/core/about.html:46
-msgid "Other Licence"
-msgstr "Andere Lizenz"
-
-#: templates/core/about.html:50
-msgid "Full licence text"
-msgstr "Kompletter Lizenztext"
-
-#: templates/core/about.html:51
-msgid "More information about the EUPL"
-msgstr "Weitere Informationen über die EUPL"
-
-#: templates/core/about.html:90
-#, python-format
-msgid ""
-"\n"
-"                    This app is licenced under %(licence)s.\n"
-"                  "
-msgstr ""
-"\n"
-"                    Diese App ist unter %(licence)s lizenziert.\n"
-"                  "
+#: templates/core/additional_field/list.html:14
+msgid "Create additional field"
+msgstr "Zusätzliches Feld erstellen"
 
 #: templates/core/announcement/form.html:10
 #: templates/core/announcement/form.html:17
@@ -826,129 +815,59 @@ msgstr "Gültig bis"
 msgid "Recipients"
 msgstr "Empfänger"
 
-#: templates/core/announcement/list.html:22
-msgid "Actions"
-msgstr "Aktionen"
-
-#: templates/core/announcement/list.html:36 templates/core/group_full.html:22
-#: templates/core/person_full.html:21
-msgid "Edit"
-msgstr "Bearbeiten"
-
-#: templates/core/announcement/list.html:42
-msgid "Delete"
-msgstr "Löschen"
-
 #: templates/core/announcement/list.html:50
 msgid "There are no announcements."
 msgstr "Es gibt aktuell keine Ankündigungen."
 
-#: templates/core/announcements.html:9 templates/core/announcements.html:36
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s\n"
-"            "
-msgstr ""
-"\n"
-"              Gültig für %(from)s\n"
-"            "
-
-#: templates/core/announcements.html:13
-#, python-format
-msgid ""
-"\n"
-"              Valid from %(from)s until %(until)s\n"
-"            "
-msgstr ""
-"\n"
-"              Gültig von %(from)s bis %(until)s\n"
-"            "
-
-#: templates/core/announcements.html:40
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s – %(until)s\n"
-"            "
-msgstr ""
-"\n"
-"              Gültig von %(from)s – %(until)s\n"
-"            "
-
 #: templates/core/base.html:54
 msgid "Logged in as"
 msgstr "Angemeldet als"
 
-#: templates/core/base.html:76 templates/search/search.html:7
-#: templates/search/search.html:22
-msgid "Search"
-msgstr "Suchen"
-
-#: templates/core/base.html:148
+#: templates/core/base.html:147
 msgid "About AlekSIS — The Free School Information System"
 msgstr "Über AlekSIS — The Free School Information System"
 
-#: templates/core/base.html:156
+#: templates/core/base.html:155
 msgid "Impress"
 msgstr "Impressum"
 
-#: templates/core/base.html:164
+#: templates/core/base.html:163
 msgid "Privacy Policy"
 msgstr "Datenschutzerklärung"
 
-#: templates/core/base_print.html:62
+#: templates/core/base_print.html:64
 msgid "Powered by AlekSIS"
 msgstr "Betrieben mit AlekSIS"
 
-#: templates/core/edit_group.html:6 templates/core/edit_group.html:7
-msgid "Edit group"
-msgstr "Gruppe editieren"
-
-#: templates/core/edit_person.html:8 templates/core/edit_person.html:9
-msgid "Edit person"
-msgstr "Person editieren"
-
-#: templates/core/group_full.html:28 templates/core/person_full.html:28
-msgid "Change preferences"
-msgstr "Einstellungen ändern"
-
-#: templates/core/groups.html:14
-msgid "Create group"
-msgstr "Gruppe erstellen"
-
-#: templates/core/groups_child_groups.html:18
+#: templates/core/group/child_groups.html:18
 msgid ""
 "\n"
-"          You can use this to assign child groups to groups. Please use the "
-"filters below to select groups you want to\n"
+"          You can use this to assign child groups to groups. Please use the filters below to select groups you want to\n"
 "          change and click \"Next\".\n"
 "        "
 msgstr ""
 "\n"
-"          Sie können diese Seite verwenden, um Kindgruppen zu Gruppen "
-"zuzuordnen. Bitte nutzen Sie die folgenden Filter, um die Gruppen "
-"auszuwählen, die Sie \n"
+"          Sie können diese Seite verwenden, um Kindgruppen zu Gruppen zuzuordnen. Bitte nutzen Sie die folgenden Filter, um die Gruppen auszuwählen, die Sie \n"
 "          ändern möchten und klicken auf \"Weiter\".\n"
 "        "
 
-#: templates/core/groups_child_groups.html:31
+#: templates/core/group/child_groups.html:31
 msgid "Update selection"
 msgstr "Auswahl aktualisieren"
 
-#: templates/core/groups_child_groups.html:35
+#: templates/core/group/child_groups.html:35
 msgid "Clear all filters"
 msgstr "Alle Filter leeren"
 
-#: templates/core/groups_child_groups.html:39
+#: templates/core/group/child_groups.html:39
 msgid "Currently selected groups"
 msgstr "Aktuell ausgewählte Gruppen"
 
-#: templates/core/groups_child_groups.html:52
+#: templates/core/group/child_groups.html:52
 msgid "Start assigning child groups for this groups"
 msgstr "Zuordnung von Kindgruppen zu Gruppen starten"
 
-#: templates/core/groups_child_groups.html:61
+#: templates/core/group/child_groups.html:61
 msgid ""
 "\n"
 "            Please select some groups in order to go on with assigning.\n"
@@ -958,56 +877,84 @@ msgstr ""
 "            Bitte wählen Sie Gruppen aus, um Gruppen zuzuordnen.\n"
 "          "
 
-#: templates/core/groups_child_groups.html:72
+#: templates/core/group/child_groups.html:72
 msgid "Current group:"
 msgstr "Aktuelle Gruppe:"
 
-#: templates/core/groups_child_groups.html:78
+#: templates/core/group/child_groups.html:78
 msgid "Please be careful!"
 msgstr "Bitte seien Sie vorsichtig!"
 
-#: templates/core/groups_child_groups.html:79
+#: templates/core/group/child_groups.html:79
 msgid ""
 "\n"
-"            If you click \"Back\" or \"Next\" the current group assignments "
-"are not saved.\n"
-"            If you click \"Save\", you will overwrite all existing child "
-"group relations for this group with what you\n"
+"            If you click \"Back\" or \"Next\" the current group assignments are not saved.\n"
+"            If you click \"Save\", you will overwrite all existing child group relations for this group with what you\n"
 "            selected on this page.\n"
 "          "
 msgstr ""
 "\n"
-"            Wenn Sie auf \"Zurück\" oder \"Weiter\" klicken, werden die "
-"aktuellen Gruppenzuordnungen nicht gespeichert.\n"
-"Wenn Sie auf \"Speichern\" klicken, werden alle existierenden Zuordnungen "
-"von Kindgruppen für diese Gruppe\n"
+"            Wenn Sie auf \"Zurück\" oder \"Weiter\" klicken, werden die aktuellen Gruppenzuordnungen nicht gespeichert.\n"
+"Wenn Sie auf \"Speichern\" klicken, werden alle existierenden Zuordnungen von Kindgruppen für diese Gruppe\n"
 "mit dem überschrieben, was Sie auf dieser Seite ausgewählt haben.\n"
 "          "
 
-#: templates/core/groups_child_groups.html:93
-#: templates/core/groups_child_groups.html:128
+#: templates/core/group/child_groups.html:93
+#: templates/core/group/child_groups.html:128
 #: templates/two_factor/_wizard_actions.html:15
 #: templates/two_factor/_wizard_actions.html:20
 msgid "Back"
 msgstr "Zurück"
 
-#: templates/core/groups_child_groups.html:99
-#: templates/core/groups_child_groups.html:134
+#: templates/core/group/child_groups.html:99
+#: templates/core/group/child_groups.html:134
 #: templates/two_factor/_wizard_actions.html:26
 msgid "Next"
 msgstr "Weiter"
 
-#: templates/core/groups_child_groups.html:106
-#: templates/core/groups_child_groups.html:141
-#: templates/core/save_button.html:3
+#: templates/core/group/child_groups.html:106
+#: templates/core/group/child_groups.html:141
+#: templates/core/partials/save_button.html:3
 msgid "Save"
 msgstr "Speichern"
 
-#: templates/core/groups_child_groups.html:112
-#: templates/core/groups_child_groups.html:147
+#: templates/core/group/child_groups.html:112
+#: templates/core/group/child_groups.html:147
 msgid "Save and next"
 msgstr "Speichern und weiter"
 
+#: templates/core/group/edit.html:6 templates/core/group/edit.html:7
+msgid "Edit group"
+msgstr "Gruppe editieren"
+
+#: templates/core/group/full.html:37 templates/core/person/full.html:36
+msgid "Change preferences"
+msgstr "Einstellungen ändern"
+
+#: templates/core/group/list.html:14
+msgid "Create group"
+msgstr "Gruppe erstellen"
+
+#: templates/core/group/list.html:17
+msgid "Filter groups"
+msgstr "Gruppen filtern"
+
+#: templates/core/group/list.html:24 templates/core/person/list.html:28
+msgid "Clear"
+msgstr "Zurücksetzen"
+
+#: templates/core/group/list.html:28
+msgid "Selected groups"
+msgstr "Ausgewählte Gruppen"
+
+#: templates/core/group_type/edit.html:6 templates/core/group_type/edit.html:7
+msgid "Edit group type"
+msgstr "Gruppentyp editieren"
+
+#: templates/core/group_type/list.html:14
+msgid "Create group type"
+msgstr "Gruppentyp erstellen"
+
 #: templates/core/index.html:4
 msgid "Home"
 msgstr "Startseite"
@@ -1032,137 +979,397 @@ msgstr "Mehr Informationen →"
 msgid "No notifications available yet."
 msgstr "Aktuell keine Benachrichtigungen verfügbar."
 
-#: templates/core/no_person.html:12
+#: templates/core/pages/about.html:6 templates/core/pages/about.html:15
+msgid "About AlekSIS"
+msgstr "Über AlekSIS"
+
+#: templates/core/pages/about.html:7
+msgid "AlekSIS – The Free School Information System"
+msgstr "AlekSIS – The Free School Information System"
+
+#: templates/core/pages/about.html:17
 msgid ""
 "\n"
-"            Your administrator account is not linked to any person. "
-"Therefore,\n"
-"            a dummy person has been linked to your account.\n"
-"          "
+"              This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used\n"
+"              to manage and/or publish organisational artifacts of educational institutions. AlekSIS is free software and\n"
+"              can be used by anyone.\n"
+"            "
 msgstr ""
 "\n"
-"            Ihr Administratorenkonto ist mit keiner Person verknüpft. "
-"Deshalb\n"
-"            wurde Ihr Konto mit einer Dummyperson verknüpft.\n"
-"          "
+"              Diese Plattform wird mit AlekSIS, einem webbasierten Schulinformationssystem (SIS), \n"
+"welches für die Verwaltung und/oder Veröffentlichung von Bildungseinrichtungen verwendet werden kann.\n"
+"AlekSIS ist freie Software und kann von jedem benutzt werden.\n"
+"            "
+
+#: templates/core/pages/about.html:25
+msgid "Website of AlekSIS"
+msgstr "Website von AlekSIS"
 
-#: templates/core/no_person.html:19
+#: templates/core/pages/about.html:26
+msgid "Source code"
+msgstr "Quellcode"
+
+#: templates/core/pages/about.html:35
+msgid "Licence information"
+msgstr "Lizenzinformationen"
+
+#: templates/core/pages/about.html:37
 msgid ""
 "\n"
-"            Your user account is not linked to a person. This means you\n"
-"            cannot access any school-related information. Please contact\n"
-"            the managers of AlekSIS at your school.\n"
-"          "
+"              The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence\n"
+"              information from third-party apps, if installed, refer to the respective components below. The\n"
+"              licences are marked like this:\n"
+"            "
 msgstr ""
 "\n"
-"            Ihr Benutzerkonto ist nicht mit einer Person verknüpft. Das "
-"bedeutet, dass Sie\n"
-"        keine schulbezogenen Informationen aufrufen können. Bitte wenden Sie "
-"sich an\n"
-"        die Verwaltenden von AlekSIS an Ihrer Schule.\n"
-"          "
+"              Der Core und die offiziellen Apps von AlekSIS sind unter der EUPL, Version 1.2 oder später, lizenziert. Für Lizenzinformationen\n"
+"zu Apps von Drittanbietern, wenn installiert, siehe direkt bei der jeweiligen App weiter unten auf dieser Seite. Die Lizenzen\n"
+"sind wie folgt markiert:\n"
+"            "
 
-#: templates/core/person_full.html:34
-msgid "Contact details"
-msgstr "Kontaktdetails"
+#: templates/core/pages/about.html:45
+msgid "Free/Open Source Licence"
+msgstr "Freie/Open Source Lizenz"
 
-#: templates/core/persons_accounts.html:7
-#: templates/core/persons_accounts.html:9
-msgid "Link persons to accounts"
-msgstr "Personen mit Benutzerkonten verknüpfen"
+#: templates/core/pages/about.html:46
+msgid "Other Licence"
+msgstr "Andere Lizenz"
 
-#: templates/core/persons_accounts.html:16
+#: templates/core/pages/about.html:50
+msgid "Full licence text"
+msgstr "Kompletter Lizenztext"
+
+#: templates/core/pages/about.html:51
+msgid "More information about the EUPL"
+msgstr "Weitere Informationen über die EUPL"
+
+#: templates/core/pages/about.html:90
+#, python-format
 msgid ""
 "\n"
-"        You can use this form to assign user accounts to persons. Use the\n"
-"        dropdowns to select existing accounts; use the text fields to create "
-"new\n"
-"        accounts on-the-fly. The latter will create a new account with the\n"
-"        entered username and copy all other details from the person.\n"
-"      "
+"                    This app is licenced under %(licence)s.\n"
+"                  "
 msgstr ""
 "\n"
-"        Sie können dieses Formular nutzen, um Benutzerkonten Personen "
-"zuzuweisen. Nutzen Sie das\n"
-"    Auswahlfeld um ein existierendes Benutzerkonto auszuwählen; nutzen Sie "
-"das Textfeld, um einen neuen Benutzer zu\n"
-"    erstellen. Letzteres erstellt ein neues Benutzerkonto mit dem\n"
-"    eingegebenen Benutzernamen und kopiert alle anderen Daten der Person.\n"
-"      "
+"                    Diese App ist unter %(licence)s lizenziert.\n"
+"                  "
 
-#: templates/core/persons_accounts.html:31
-#: templates/core/persons_accounts.html:55
-msgid "Update"
-msgstr "Aktualisieren"
+#: templates/core/pages/delete.html:6
+#, python-format
+msgid "Delete %(object_name)s"
+msgstr "%(object_name)s löschen"
 
-#: templates/core/persons_accounts.html:37
-msgid "Existing account"
-msgstr "Existierendes Konto"
+#: templates/core/pages/delete.html:13
+#, python-format
+msgid ""
+"\n"
+"      Do you really want to delete the %(object_name)s \"%(object)s\"?\n"
+"    "
+msgstr ""
+"\n"
+"      Möchten Sie wirklich %(object_name)s \"%(object)s\" löschen?\n"
+"    "
 
-#: templates/core/persons_accounts.html:38
-msgid "New account"
-msgstr "Neues Konto"
+#: templates/core/pages/offline.html:6
+msgid ""
+"No internet\n"
+"    connection."
+msgstr ""
+"Keine\n"
+"    Internetverbindung."
 
-#: templates/core/system_status.html:12
+#: templates/core/pages/offline.html:10
+msgid ""
+"\n"
+"      There was an error accessing this page. You probably don't have an internet connection. Check to see if your WiFi\n"
+"      or mobile data is turned on and try again. If you think you are connected, please contact the system\n"
+"      administrators:\n"
+"    "
+msgstr ""
+"\n"
+"      Es ist ein Fehler beim Aufrufen der Seite aufgetreten. Eventuell haben Sie keine Internetverbindung. Bitte prüfen Sie, ob WLAN oder mobile Daten aktiv sind, \n"
+"      und probieren Sie es erneut. Wenn Sie der Meinung sind, dass Sie mit dem Internet verbunden sind, kontaktieren Sie bitte einen Ihrer \n"
+"      Systemadministratoren:\n"
+"    "
+
+#: templates/core/pages/progress.html:27
+msgid ""
+"\n"
+"              Without activated JavaScript the progress status can't be updated.\n"
+"            "
+msgstr ""
+"\n"
+"              Ohne aktiviertes JavaScript kann der Fortschritt leider nicht "
+"aktualisiert werden.\n"
+"            "
+
+#: templates/core/pages/progress.html:47
+#: templates/two_factor/core/otp_required.html:19
+msgid "Go back"
+msgstr "Zurück"
+
+#: templates/core/pages/system_status.html:12
 msgid "System checks"
 msgstr "Systemprüfungen"
 
-#: templates/core/system_status.html:21
+#: templates/core/pages/system_status.html:21
 msgid "Maintenance mode enabled"
 msgstr "Wartungsmodus aktiviert"
 
-#: templates/core/system_status.html:23
+#: templates/core/pages/system_status.html:23
 msgid ""
 "\n"
-"                Only admin and visitors from internal IPs can access "
-"thesite.\n"
+"                Only admin and visitors from internal IPs can access thesite.\n"
 "              "
 msgstr ""
 "\n"
-"                Nur Administratoren und Besucher von internen IP-Adressen "
-"können die Seite aufrufen.\n"
+"                Nur Administratoren und Besucher von internen IP-Adressen können die Seite aufrufen.\n"
 "              "
 
-#: templates/core/system_status.html:34
+#: templates/core/pages/system_status.html:34
 msgid "Maintenance mode disabled"
 msgstr "Wartungsmodus deaktiviert"
 
-#: templates/core/system_status.html:35
+#: templates/core/pages/system_status.html:35
 msgid "Everyone can access the site."
 msgstr "Jeder kann die Seite aufrufen."
 
-#: templates/core/system_status.html:45
+#: templates/core/pages/system_status.html:45
 msgid "Debug mode enabled"
 msgstr "Debug-Modus aktiviert"
 
-#: templates/core/system_status.html:47
+#: templates/core/pages/system_status.html:47
 msgid ""
 "\n"
-"                The web server throws back debug information on errors. Do "
-"not use in production!\n"
+"                The web server throws back debug information on errors. Do not use in production!\n"
 "              "
 msgstr ""
 "\n"
-"                Der Server gibt Debug-Informationen bei Fehlern zurück. "
-"Nicht im Produktivbetrieb nutzen!\n"
+"                Der Server gibt Debug-Informationen bei Fehlern zurück. Nicht im Produktivbetrieb nutzen!\n"
 "              "
 
-#: templates/core/system_status.html:54
+#: templates/core/pages/system_status.html:54
 msgid "Debug mode disabled"
 msgstr "Debug-Modus deaktivert"
 
-#: templates/core/system_status.html:56
+#: templates/core/pages/system_status.html:56
 msgid ""
 "\n"
-"                Debug mode is disabled. Default error pages are displayed on "
-"errors.\n"
+"                Debug mode is disabled. Default error pages are displayed on errors.\n"
 "              "
 msgstr ""
 "\n"
-"                Debug-Modus ist deaktiviert. Standard-Fehlerseiten werden "
-"bei Fehlern angezeigt.\n"
+"                Debug-Modus ist deaktiviert. Standard-Fehlerseiten werden bei Fehlern angezeigt.\n"
 "              "
 
+#: templates/core/pages/system_status.html:69
+msgid "System health checks"
+msgstr "Systemprüfungen"
+
+#: templates/core/pages/system_status.html:75
+msgid "Service"
+msgstr "Dienst"
+
+#: templates/core/pages/system_status.html:76
+#: templates/core/pages/system_status.html:115
+msgid "Status"
+msgstr "Status"
+
+#: templates/core/pages/system_status.html:77
+msgid "Time taken"
+msgstr "Dauer"
+
+#: templates/core/pages/system_status.html:96
+msgid "seconds"
+msgstr "Sekunden"
+
+#: templates/core/pages/system_status.html:107
+msgid "Celery task results"
+msgstr "Celery Task-Ergebnisse"
+
+#: templates/core/pages/system_status.html:112
+msgid "Task"
+msgstr "Task"
+
+#: templates/core/pages/system_status.html:113
+msgid "ID"
+msgstr "ID"
+
+#: templates/core/pages/system_status.html:114
+msgid "Date done"
+msgstr "Erledigungszeitpunkt"
+
+#: templates/core/partials/announcements.html:9
+#: templates/core/partials/announcements.html:36
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s\n"
+"            "
+msgstr ""
+"\n"
+"              Gültig für %(from)s\n"
+"            "
+
+#: templates/core/partials/announcements.html:13
+#, python-format
+msgid ""
+"\n"
+"              Valid from %(from)s until %(until)s\n"
+"            "
+msgstr ""
+"\n"
+"              Gültig von %(from)s bis %(until)s\n"
+"            "
+
+#: templates/core/partials/announcements.html:40
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s – %(until)s\n"
+"            "
+msgstr ""
+"\n"
+"              Gültig von %(from)s – %(until)s\n"
+"            "
+
+#: templates/core/partials/crud_events.html:10
+#, python-format
+msgid ""
+"\n"
+"              Created by %(person)s\n"
+"            "
+msgstr ""
+"\n"
+"              Erstellt von %(person)s\n"
+"            "
+
+#: templates/core/partials/crud_events.html:14
+#: templates/core/partials/crud_events.html:22
+#: templates/core/partials/crud_events.html:26
+#, python-format
+msgid ""
+"\n"
+"              Updated by %(person)s\n"
+"            "
+msgstr ""
+"\n"
+"              Aktualisiert von %(person)s\n"
+"            "
+
+#: templates/core/partials/crud_events.html:18
+#, python-format
+msgid ""
+"\n"
+"              Deleted by %(person)s\n"
+"            "
+msgstr ""
+"\n"
+"              Gelöscht von %(person)s\n"
+"            "
+
+#: templates/core/partials/language_form.html:16
+msgid "Language"
+msgstr "Sprache"
+
+#: templates/core/partials/language_form.html:28
+msgid "Select language"
+msgstr "Sprache auswählen"
+
+#: templates/core/partials/no_person.html:12
+msgid ""
+"\n"
+"            Your administrator account is not linked to any person. Therefore,\n"
+"            a dummy person has been linked to your account.\n"
+"          "
+msgstr ""
+"\n"
+"            Ihr Administratorenkonto ist mit keiner Person verknüpft. Deshalb\n"
+"            wurde Ihr Konto mit einer Dummyperson verknüpft.\n"
+"          "
+
+#: templates/core/partials/no_person.html:19
+msgid ""
+"\n"
+"            Your user account is not linked to a person. This means you\n"
+"            cannot access any school-related information. Please contact\n"
+"            the managers of AlekSIS at your school.\n"
+"          "
+msgstr ""
+"\n"
+"            Ihr Benutzerkonto ist nicht mit einer Person verknüpft. Das bedeutet, dass Sie\n"
+"        keine schulbezogenen Informationen aufrufen können. Bitte wenden Sie sich an\n"
+"        die Verwaltenden von AlekSIS an Ihrer Schule.\n"
+"          "
+
+#: templates/core/person/accounts.html:7 templates/core/person/accounts.html:9
+msgid "Link persons to accounts"
+msgstr "Personen mit Benutzerkonten verknüpfen"
+
+#: templates/core/person/accounts.html:16
+msgid ""
+"\n"
+"        You can use this form to assign user accounts to persons. Use the\n"
+"        dropdowns to select existing accounts; use the text fields to create new\n"
+"        accounts on-the-fly. The latter will create a new account with the\n"
+"        entered username and copy all other details from the person.\n"
+"      "
+msgstr ""
+"\n"
+"        Sie können dieses Formular nutzen, um Benutzerkonten Personen zuzuweisen. Nutzen Sie das\n"
+"    Auswahlfeld um ein existierendes Benutzerkonto auszuwählen; nutzen Sie das Textfeld, um einen neuen Benutzer zu\n"
+"    erstellen. Letzteres erstellt ein neues Benutzerkonto mit dem\n"
+"    eingegebenen Benutzernamen und kopiert alle anderen Daten der Person.\n"
+"      "
+
+#: templates/core/person/accounts.html:31
+#: templates/core/person/accounts.html:55
+msgid "Update"
+msgstr "Aktualisieren"
+
+#: templates/core/person/accounts.html:37
+msgid "Existing account"
+msgstr "Existierendes Konto"
+
+#: templates/core/person/accounts.html:38
+msgid "New account"
+msgstr "Neues Konto"
+
+#: templates/core/person/edit.html:11 templates/core/person/edit.html:12
+msgid "Edit person"
+msgstr "Person editieren"
+
+#: templates/core/person/full.html:42
+msgid "Contact details"
+msgstr "Kontaktdetails"
+
+#: templates/core/person/full.html:122
+msgid "Children"
+msgstr "Kinder"
+
+#: templates/core/person/list.html:17
+msgid "Create person"
+msgstr "Person erstellen"
+
+#: templates/core/person/list.html:21
+msgid "Filter persons"
+msgstr "Personen filtern"
+
+#: templates/core/person/list.html:32
+msgid "Selected persons"
+msgstr "Ausgewählte Personen"
+
+#: templates/core/school_term/create.html:6
+#: templates/core/school_term/create.html:7
+#: templates/core/school_term/list.html:14
+msgid "Create school term"
+msgstr "Schuljahr erstellen"
+
+#: templates/core/school_term/edit.html:6
+#: templates/core/school_term/edit.html:7
+msgid "Edit school term"
+msgstr "Schuljahr bearbeiten"
+
 #: templates/dynamic_preferences/form.html:9
 msgid "Site preferences"
 msgstr "Seiteneinstellungen ändern"
@@ -1188,33 +1395,6 @@ msgstr "Alle"
 msgid "Impersonate user"
 msgstr "Als Benutzer verkleiden"
 
-#: templates/offline.html:6
-msgid ""
-"No internet\n"
-"    connection."
-msgstr ""
-"Keine\n"
-"    Internetverbindung."
-
-#: templates/offline.html:10
-msgid ""
-"\n"
-"      There was an error accessing this page. You probably don't have an "
-"internet connection. Check to see if your WiFi\n"
-"      or mobile data is turned on and try again. If you think you are "
-"connected, please contact the system\n"
-"      administrators:\n"
-"    "
-msgstr ""
-"\n"
-"      Es ist ein Fehler beim Aufrufen der Seite aufgetreten. Eventuell haben "
-"Sie keine Internetverbindung. Bitte prüfen Sie, ob WLAN oder mobile Daten "
-"aktiv sind, \n"
-"      und probieren Sie es erneut. Wenn Sie der Meinung sind, dass Sie mit "
-"dem Internet verbunden sind, kontaktieren Sie bitte einen Ihrer \n"
-"      Systemadministratoren:\n"
-"    "
-
 #: templates/search/search.html:8
 msgid "Global Search"
 msgstr "Globale Suche"
@@ -1239,33 +1419,49 @@ msgstr "Bitte geben Sie einen Suchausdruck ein."
 msgid "New notification for"
 msgstr "Neue Benachrichtigung für"
 
-#: templates/templated_email/notification.email:7
-msgid "Dear"
-msgstr "Sehr geehrter"
+#: templates/templated_email/notification.email:6
+#: templates/templated_email/notification.email:27
+#, python-format
+msgid "Dear %(notification_user)s,"
+msgstr "Liebe(r) %(notification_user)s,"
 
 #: templates/templated_email/notification.email:8
+#: templates/templated_email/notification.email:29
 msgid "we got a new notification for you:"
-msgstr "Wir haben eine neue Benachrichtigung für Sie:"
+msgstr "wir haben eine neue Benachrichtigung für Sie:"
 
-#: templates/templated_email/notification.email:12
+#: templates/templated_email/notification.email:15
+#: templates/templated_email/notification.email:35
 msgid "More information"
 msgstr "Mehr Informationen"
 
-#: templates/templated_email/notification.email:16
+#: templates/templated_email/notification.email:18
 #, python-format
 msgid ""
 "\n"
-"    <p>By %(trans_sender)s at %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Your AlekSIS team</i>\n"
+"        Sent by %(trans_sender)s at %(trans_created_at)s\n"
 "    "
 msgstr ""
 "\n"
-"    <p>Von %(trans_sender)s um %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Ihr AlekSIS-Team</i>\n"
+"        Von %(trans_sender)s am %(trans_created_at)s\n"
 "    "
 
+#: templates/templated_email/notification.email:22
+#: templates/templated_email/notification.email:46
+msgid "Your AlekSIS team"
+msgstr "Ihr AlekSIS-Team"
+
+#: templates/templated_email/notification.email:40
+#, python-format
+msgid ""
+"\n"
+"            Sent by %(trans_sender)s at %(trans_created_at)s\n"
+"        "
+msgstr ""
+"\n"
+"            Von %(trans_sender)s um %(trans_created_at)s\n"
+"        "
+
 #: templates/two_factor/_base_focus.html:6
 #: templates/two_factor/core/otp_required.html:22
 #: templates/two_factor/core/setup.html:5
@@ -1288,21 +1484,16 @@ msgid ""
 "\n"
 "        Backup tokens can be used when your primary and backup\n"
 "        phone numbers aren't available. The backup tokens below can be used\n"
-"        for login verification. If you've used up all your backup tokens, "
-"you\n"
-"        can generate a new set of backup tokens. Only the backup tokens "
-"shown\n"
+"        for login verification. If you've used up all your backup tokens, you\n"
+"        can generate a new set of backup tokens. Only the backup tokens shown\n"
 "        below will be valid.\n"
 "      "
 msgstr ""
 "\n"
 "        Backup-Token können genutzt werden, wenn Ihre primären und Backup-\n"
-"        Telefonnummern nicht verfügbar sind. Die Backup-Tokens unten können "
-"für\n"
-"        die Anmeldungsverifizierung genutzt werden. Wenn Sie alle Backup-"
-"Tokens genutzt haben,\n"
-"        müssen Sie neue generieren. Nur gültige Backup-Tokens werden "
-"angezeigt.\n"
+"        Telefonnummern nicht verfügbar sind. Die Backup-Tokens unten können für\n"
+"        die Anmeldungsverifizierung genutzt werden. Wenn Sie alle Backup-Tokens genutzt haben,\n"
+"        müssen Sie neue generieren. Nur gültige Backup-Tokens werden angezeigt.\n"
 "      "
 
 #: templates/two_factor/core/backup_tokens.html:33
@@ -1328,17 +1519,18 @@ msgid "Generate Tokens"
 msgstr "Tokens generieren"
 
 #: templates/two_factor/core/login.html:16
-msgid ""
-"You have no permission to view this page. Please login with an other account."
-msgstr ""
-"Sie haben nicht die nötigen Berechtigungen, um diese Seite aufzurufen. Bitte "
-"loggen Sie sich mit einem anderen Account ein."
+msgid "You have no permission to view this page. Please login with an other account."
+msgstr "Sie haben nicht die nötigen Berechtigungen, um diese Seite aufzurufen. Bitte loggen Sie sich mit einem anderen Account ein."
 
-#: templates/two_factor/core/login.html:25
+#: templates/two_factor/core/login.html:24
 msgid "Please login to see this page."
 msgstr "Bitte melden Sie sich an, um diese Seite zu sehen."
 
-#: templates/two_factor/core/login.html:28
+#: templates/two_factor/core/login.html:30
+msgid "Login with username and password"
+msgstr "Anmeldung mit Nutzername und Passwort"
+
+#: templates/two_factor/core/login.html:40
 msgid ""
 "We are calling your phone right now, please enter the\n"
 "              digits you hear."
@@ -1346,16 +1538,15 @@ msgstr ""
 "Wir rufen Ihr Telefon jetzt an, bitte geben Sie die\n"
 "                Zahlen ein, die Sie hören."
 
-#: templates/two_factor/core/login.html:31
+#: templates/two_factor/core/login.html:43
 msgid ""
 "We sent you a text message, please enter the tokens we\n"
 "              sent."
 msgstr ""
-"Wir haben Ihnen eine Textnachricht geschickt. Bitte geben Sie die Tokens "
-"ein,\n"
+"Wir haben Ihnen eine Textnachricht geschickt. Bitte geben Sie die Tokens ein,\n"
 "              die wir Ihnen geschickt haben."
 
-#: templates/two_factor/core/login.html:34
+#: templates/two_factor/core/login.html:46
 msgid ""
 "Please enter the tokens generated by your token\n"
 "              generator."
@@ -1363,30 +1554,32 @@ msgstr ""
 "Bitte geben Sie den von Ihrem Token-Generator\n"
 "              generierten Token ein."
 
-#: templates/two_factor/core/login.html:38
+#: templates/two_factor/core/login.html:50
 msgid ""
 "Use this form for entering backup tokens for logging in.\n"
-"            These tokens have been generated for you to print and keep safe. "
-"Please\n"
+"            These tokens have been generated for you to print and keep safe. Please\n"
 "            enter one of these backup tokens to login to your account."
 msgstr ""
 "Nutzen Sie dieses Formular um Ihre Backup-Tokens zum Anmelden einzugeben.\n"
-"                Diese Tokens wurden für Sie generiert, um diese gut "
-"aufzubewahren. Bitte\n"
+"                Diese Tokens wurden für Sie generiert, um diese gut aufzubewahren. Bitte\n"
 "                geben Sie einen dieser Tokens ein, um sich einzuloggen."
 
-#: templates/two_factor/core/login.html:56
+#: templates/two_factor/core/login.html:68
 msgid "Or, alternatively, use one of your backup phones:"
 msgstr "Oder, alternativ, nutzen Sie eins Ihrer Backup-Telefone:"
 
-#: templates/two_factor/core/login.html:66
+#: templates/two_factor/core/login.html:78
 msgid "As a last resort, you can use a backup token:"
 msgstr "Als letzte Möglichkeit können Sie einen Backup-Token nutzen:"
 
-#: templates/two_factor/core/login.html:69
+#: templates/two_factor/core/login.html:81
 msgid "Use Backup Token"
 msgstr "Backup-Token nutzen"
 
+#: templates/two_factor/core/login.html:93
+msgid "Use alternative login options"
+msgstr "Alternative Anmeldemöglichkeiten nutzen"
+
 #: templates/two_factor/core/otp_required.html:9
 msgid "Permission Denied"
 msgstr "Zugriff verwehrt"
@@ -1394,13 +1587,11 @@ msgstr "Zugriff verwehrt"
 #: templates/two_factor/core/otp_required.html:10
 msgid ""
 "The page you requested, enforces users to verify using\n"
-"          two-factor authentication for security reasons. You need to enable "
-"these\n"
+"          two-factor authentication for security reasons. You need to enable these\n"
 "          security features in order to access this page."
 msgstr ""
 "Die von Ihnen gewünschte Seite erfordert aus Sicherheitsgründen\n"
-"          eine Verifizierung durch Zwei-Faktor-Authentifizierung. Sie müssen "
-"diese\n"
+"          eine Verifizierung durch Zwei-Faktor-Authentifizierung. Sie müssen diese\n"
 "          Sicherheitsfunktion aktivieren, um diese Seite aufzurufen."
 
 #: templates/two_factor/core/otp_required.html:14
@@ -1413,10 +1604,6 @@ msgstr ""
 "          Aktivieren Sie Zwei-Faktor-Authentifizierung für eine verbesserte\n"
 "          Accountsicherheit."
 
-#: templates/two_factor/core/otp_required.html:19
-msgid "Go back"
-msgstr "Zurück"
-
 #: templates/two_factor/core/phone_register.html:5
 #: templates/two_factor/core/phone_register.html:9
 msgid "Add Backup Phone"
@@ -1450,8 +1637,7 @@ msgid ""
 msgstr ""
 "\n"
 "        Sie sind dabei, Ihre Accountsicherheit auf das\n"
-"       nächste Level zu erhöhen. Bitte folgen Sie den Schritten im Wizard um "
-"die\n"
+"       nächste Level zu erhöhen. Bitte folgen Sie den Schritten im Wizard um die\n"
 "       Zwei-Faktor-Authentifizierug zu aktivieren.\n"
 "      "
 
@@ -1462,8 +1648,7 @@ msgid ""
 "      "
 msgstr ""
 "\n"
-"        Bitte wählen Sie aus, welche Authentifikationsmethode Sie nutzen "
-"wollen:\n"
+"        Bitte wählen Sie aus, welche Authentifikationsmethode Sie nutzen wollen:\n"
 "      "
 
 #: templates/two_factor/core/setup.html:23
@@ -1475,10 +1660,8 @@ msgid ""
 "      "
 msgstr ""
 "\n"
-"        Um mit dem Codegenerator zu starten, benutzen Sie bitte Ihr "
-"Smartphone,\n"
-"um diesen QR-Code zu scannen (z. B. den Google Authenticator). Dann geben "
-"Sie \n"
+"        Um mit dem Codegenerator zu starten, benutzen Sie bitte Ihr Smartphone,\n"
+"um diesen QR-Code zu scannen (z. B. den Google Authenticator). Dann geben Sie \n"
 "den in der App angezeigten Code an:\n"
 "      "
 
@@ -1491,8 +1674,7 @@ msgid ""
 msgstr ""
 "\n"
 "        Bitte geben Sie die Telefonnummer des Gerätes an,\n"
-"        an die die SMS-Nachrichten geschickt werden sollen. Diese Nummer "
-"wird im nächsten Schritt überprüft.\n"
+"        an die die SMS-Nachrichten geschickt werden sollen. Diese Nummer wird im nächsten Schritt überprüft.\n"
 "      "
 
 #: templates/two_factor/core/setup.html:41
@@ -1510,13 +1692,11 @@ msgstr ""
 #: templates/two_factor/core/setup.html:50
 msgid ""
 "\n"
-"            We are calling your phone right now, please enter the digits you "
-"hear.\n"
+"            We are calling your phone right now, please enter the digits you hear.\n"
 "          "
 msgstr ""
 "\n"
-"            Wir rufen Ihr Telefon jetzt an, bitte geben Sie die Zahlen ein, "
-"die Sie hören.\n"
+"            Wir rufen Ihr Telefon jetzt an, bitte geben Sie die Zahlen ein, die Sie hören.\n"
 "          "
 
 #: templates/two_factor/core/setup.html:56
@@ -1526,30 +1706,23 @@ msgid ""
 "          "
 msgstr ""
 "\n"
-"            Wir haben Ihnen per SMS einen Token geschickt, bitte geben Sie "
-"diesen ein.\n"
+"            Wir haben Ihnen per SMS einen Token geschickt, bitte geben Sie diesen ein.\n"
 "          "
 
 #: templates/two_factor/core/setup.html:63
 msgid ""
 "\n"
-"          We've encountered an issue with the selected authentication "
-"method. Please\n"
-"          go back and verify that you entered your information correctly, "
-"try\n"
-"          again, or use a different authentication method instead. If the "
-"issue\n"
+"          We've encountered an issue with the selected authentication method. Please\n"
+"          go back and verify that you entered your information correctly, try\n"
+"          again, or use a different authentication method instead. If the issue\n"
 "          persists, contact the site administrator.\n"
 "        "
 msgstr ""
 "\n"
-"          Mit der ausgewählten Authentifizierungsmethode ist ein Fehler "
-"aufgetreten. \n"
-"Bitte gehen Sie zurück und überprüfen, dass Sie die Informationen korrekt "
-"eingegeben haben, versuchen Sie es erneut,\n"
+"          Mit der ausgewählten Authentifizierungsmethode ist ein Fehler aufgetreten. \n"
+"Bitte gehen Sie zurück und überprüfen, dass Sie die Informationen korrekt eingegeben haben, versuchen Sie es erneut,\n"
 "oder benutzen Sie stattdessen eine andere Authentifizierungsmethode. \n"
-"Wenn der Fehler bestehen bleibt, kontaktieren Sie bitte einen der "
-"Administratoren.\n"
+"Wenn der Fehler bestehen bleibt, kontaktieren Sie bitte einen der Administratoren.\n"
 "        "
 
 #: templates/two_factor/core/setup.html:73
@@ -1574,13 +1747,11 @@ msgstr "Zwei-Faktor-Authentifizierung erfolgreich aktiviert"
 #: templates/two_factor/core/setup_complete.html:14
 msgid ""
 "\n"
-"        Congratulations, you've successfully enabled two-factor "
-"authentication.\n"
+"        Congratulations, you've successfully enabled two-factor authentication.\n"
 "      "
 msgstr ""
 "\n"
-"        Gratulation, Sie haben die Zwei-Faktor-Authentifizierung erfolgreich "
-"aktiviert.\n"
+"        Gratulation, Sie haben die Zwei-Faktor-Authentifizierung erfolgreich aktiviert.\n"
 "      "
 
 #: templates/two_factor/core/setup_complete.html:24
@@ -1597,14 +1768,12 @@ msgstr "Backup-Codes generieren"
 msgid ""
 "\n"
 "          However, it might happen that you don't have access to\n"
-"          your primary token device. To enable account recovery, generate "
-"backup codes\n"
+"          your primary token device. To enable account recovery, generate backup codes\n"
 "          or add a phone number.\n"
 "        "
 msgstr ""
 "\n"
-"          Es kann passieren, dass Sie keinen Zugriff auf Ihren "
-"Tokengenerator haben. \n"
+"          Es kann passieren, dass Sie keinen Zugriff auf Ihren Tokengenerator haben. \n"
 "Um die Wiederherstellung zu aktivieren,\n"
 "generieren Sie Backupcodes oder fügen eine Telefonnummer hinzu.\n"
 "        "
@@ -1622,12 +1791,8 @@ msgid "Disable Two-Factor Authentication"
 msgstr "Zwei-Faktor-Authentifizierung deaktiveren"
 
 #: templates/two_factor/profile/disable.html:12
-msgid ""
-"You are about to disable two-factor authentication. This weakens your "
-"account security, are you sure?"
-msgstr ""
-"Sie sind dabei, Zwei-Faktor-Authentifizierung zu deaktivieren. Das "
-"verschlechtert Ihre Kontosicherheit. Sind Sie sicher?"
+msgid "You are about to disable two-factor authentication. This weakens your account security, are you sure?"
+msgstr "Sie sind dabei, Zwei-Faktor-Authentifizierung zu deaktivieren. Das verschlechtert Ihre Kontosicherheit. Sind Sie sicher?"
 
 #: templates/two_factor/profile/disable.html:26
 msgid "Disable"
@@ -1707,8 +1872,7 @@ msgid ""
 msgstr ""
 "\n"
 "        Wir raten Ihnen jedoch dringend davon ab.\n"
-"        Sie können jedoch auch die Zwei-Faktor-Authentifizierung für Ihr "
-"Konto deaktivieren.\n"
+"        Sie können jedoch auch die Zwei-Faktor-Authentifizierung für Ihr Konto deaktivieren.\n"
 "      "
 
 #: templates/two_factor/profile/profile.html:78
@@ -1720,8 +1884,7 @@ msgid ""
 "      "
 msgstr ""
 "\n"
-"        Die Zwei-Faktor-Authentifizierung ist nicht für Ihren Account "
-"aktiviert.\n"
+"        Die Zwei-Faktor-Authentifizierung ist nicht für Ihren Account aktiviert.\n"
 "          Aktivieren Sie Zwei-Faktor-Authentifizierung für eine verbesserte\n"
 "          Accountsicherheit.\n"
 "      "
@@ -1734,30 +1897,65 @@ msgstr "E-Mail"
 msgid "SMS"
 msgstr "SMS"
 
-#: views.py:212
+#: views.py:122
+msgid "The school term has been created."
+msgstr "Das Schuljahr wurde erstellt."
+
+#: views.py:133
+msgid "The school term has been saved."
+msgstr "Das Schuljahr wurde gespeichert."
+
+#: views.py:273
 msgid "The child groups were successfully saved."
 msgstr "Die Untergruppen wurden gespeichert."
 
-#: views.py:240
+#: views.py:309
 msgid "The person has been saved."
 msgstr "Die Person wurde gespeichert."
 
-#: views.py:276
+#: views.py:346
 msgid "The group has been saved."
 msgstr "Die Gruppe wurde gespeichert."
 
-#: views.py:348
+#: views.py:434
 msgid "The announcement has been saved."
 msgstr "Die Ankündigung wurde gespeichert."
 
-#: views.py:364
+#: views.py:450
 msgid "The announcement has been deleted."
 msgstr "Ankündigung wurde gelöscht."
 
-#: views.py:435
+#: views.py:521
 msgid "The preferences have been saved successfully."
 msgstr "Die Einstellungen wurde gespeichert."
 
+#: views.py:544
+msgid "The person has been deleted."
+msgstr "Die Person wurde gelöscht."
+
+#: views.py:557
+msgid "The group has been deleted."
+msgstr "Die Gruppe wurde gelöscht."
+
+#: views.py:588
+msgid "The additional_field has been saved."
+msgstr "Das zusätzliche Feld wurde gespeichert."
+
+#: views.py:622
+msgid "The additional field has been deleted."
+msgstr "Das zusätzliche Feld wurde gelöscht."
+
+#: views.py:646
+msgid "The group type has been saved."
+msgstr "Der Gruppentyp wurde gespeichert."
+
+#: views.py:676
+msgid "The group type has been deleted."
+msgstr "Der Gruppentyp wurde gelöscht."
+
+#~ msgid "Dear"
+#~ msgstr "Sehr geehrter"
+
 #~ msgid "Two factor auth"
 #~ msgstr "Zwei-Faktor-Authentifizierung"
 
@@ -1767,9 +1965,6 @@ msgstr "Die Einstellungen wurde gespeichert."
 #~ msgid "Edit school information"
 #~ msgstr "Schulinformationen bearbeiten"
 
-#~ msgid "Edit school term"
-#~ msgstr "Schuljahr bearbeiten"
-
 #~ msgid "Addtitional field"
 #~ msgstr "Zusätzliches Feld"
 
@@ -1786,8 +1981,7 @@ msgstr "Die Einstellungen wurde gespeichert."
 #~ "     "
 #~ msgstr ""
 #~ "\n"
-#~ "      Wenn Sie der Meinung sind, dass es sich um einen Fehler in AlekSIS "
-#~ "handelt, kontaktieren Sie bitte einen Ihrer\n"
+#~ "      Wenn Sie der Meinung sind, dass es sich um einen Fehler in AlekSIS handelt, kontaktieren Sie bitte einen Ihrer\n"
 #~ "     Systemadministratoren:\n"
 #~ "     "
 
@@ -1861,9 +2055,7 @@ msgstr "Die Einstellungen wurde gespeichert."
 #~ msgstr "Markdown-Anleitung (Hilfe)"
 
 #~ msgid "You are not allowed to mark notifications from other users as read!"
-#~ msgstr ""
-#~ "Es ist Ihnen nicht erlaubt, Benachrichtigungen von anderen Benutzern als "
-#~ "gelesen zu markieren!"
+#~ msgstr "Es ist Ihnen nicht erlaubt, Benachrichtigungen von anderen Benutzern als gelesen zu markieren!"
 
 #, fuzzy
 #~| msgid "School management"
@@ -1891,24 +2083,12 @@ msgstr "Die Einstellungen wurde gespeichert."
 #~ msgid "Effective end date of term"
 #~ msgstr "Enddatum des Schuljahres"
 
-#~ msgid "School term"
-#~ msgstr "Schuljahr"
-
-#~ msgid "School terms"
-#~ msgstr "Schuljahre"
-
 #~ msgid "Edit school"
 #~ msgstr "Schule bearbeiten"
 
 #~ msgid "School management"
 #~ msgstr "Schulverwaltung"
 
-#~ msgid "The school has been saved."
-#~ msgstr "Die Schule wurde gespeichert."
-
-#~ msgid "The term has been saved."
-#~ msgstr "Das Schuljahr wurde gespeichert."
-
 #~ msgid "Reference ID of import source"
 #~ msgstr "Referenz-ID der Import-Quelle"
 
@@ -1942,8 +2122,7 @@ msgstr "Die Einstellungen wurde gespeichert."
 #~ "    "
 #~ msgstr ""
 #~ "\n"
-#~ "     Der Wartungsmodus ist aktuell aktiviert. Bitte versuchen Sie es "
-#~ "später erneut.\n"
+#~ "     Der Wartungsmodus ist aktuell aktiviert. Bitte versuchen Sie es später erneut.\n"
 #~ "    "
 
 #~ msgid "Details"
@@ -1988,9 +2167,6 @@ msgstr "Die Einstellungen wurde gespeichert."
 #~ msgid "Assorted"
 #~ msgstr "Unsortiert"
 
-#~ msgid "Language"
-#~ msgstr "Sprache"
-
 #~ msgid "Administration"
 #~ msgstr "Verwaltung"
 
diff --git a/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po b/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po
index a872c31afd29d0d617356303698963017e5381a9..9dbef6e6f74f842b0e8f25e389edf1a852cd8d99 100644
--- a/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po
+++ b/aleksis/core/locale/de_DE/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-03 10:36+0000\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,14 +17,14 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: aleksis/core/static/js/main.js:21
+#: static/js/main.js:21
 msgid "Today"
 msgstr ""
 
-#: aleksis/core/static/js/main.js:22
+#: static/js/main.js:22
 msgid "Cancel"
 msgstr ""
 
-#: aleksis/core/static/js/main.js:23
+#: static/js/main.js:23
 msgid "OK"
 msgstr ""
diff --git a/aleksis/core/locale/fr/LC_MESSAGES/django.po b/aleksis/core/locale/fr/LC_MESSAGES/django.po
index e248a116e72f4957542b94f55a3dc8d37ab24748..d800a36f8aa7db3f7279e2ddfc496e3a4f10ff8f 100644
--- a/aleksis/core/locale/fr/LC_MESSAGES/django.po
+++ b/aleksis/core/locale/fr/LC_MESSAGES/django.po
@@ -7,11 +7,10 @@ msgid ""
 msgstr ""
 "Project-Id-Version: AlekSIS (School Information System) 0.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-04 15:39+0200\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: 2020-04-27 13:03+0000\n"
 "Last-Translator: Marlene Grundey <grundema@katharineum.de>\n"
-"Language-Team: French <https://translate.edugit.org/projects/aleksis/aleksis/"
-"fr/>\n"
+"Language-Team: French <https://translate.edugit.org/projects/aleksis/aleksis/fr/>\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -19,6 +18,22 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n > 1;\n"
 "X-Generator: Weblate 4.0.1\n"
 
+#: filters.py:37 templates/core/base.html:77 templates/core/group/list.html:20
+#: templates/core/person/list.html:24 templates/search/search.html:7
+#: templates/search/search.html:22
+msgid "Search"
+msgstr ""
+
+#: filters.py:53
+msgid "Search by name"
+msgstr ""
+
+#: filters.py:65
+#, fuzzy
+#| msgid "Contact details"
+msgid "Search by contact details"
+msgstr "Détails de contact"
+
 #: forms.py:46
 msgid "You cannot set a new username when also selecting an existing user."
 msgstr ""
@@ -47,70 +62,79 @@ msgstr "Détails de contact"
 msgid "Advanced personal data"
 msgstr "Détails de contact"
 
-#: forms.py:116
+#: forms.py:114
 msgid "New user"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "Create a new account"
 msgstr ""
 
-#: forms.py:128
+#: forms.py:126 models.py:91
+msgid "School term"
+msgstr ""
+
+#: forms.py:127
 #, fuzzy
 #| msgid "Contact details"
 msgid "Common data"
 msgstr "Détails de contact"
 
-#: forms.py:129 forms.py:169 menus.py:141 models.py:54
-#: templates/core/persons.html:8 templates/core/persons.html:9
+#: forms.py:128 forms.py:170 menus.py:152 models.py:105
+#: templates/core/person/list.html:8 templates/core/person/list.html:9
 #, fuzzy
 #| msgid "Person"
 msgid "Persons"
 msgstr "Personne"
 
-#: forms.py:162 forms.py:165 models.py:31
+#: forms.py:129
+#, fuzzy
+#| msgid "Contact details"
+msgid "Additional data"
+msgstr "Détails de contact"
+
+#: forms.py:163 forms.py:166 models.py:35
 msgid "Date"
 msgstr "Date"
 
-#: forms.py:163 forms.py:166 models.py:39
+#: forms.py:164 forms.py:167 models.py:43
 msgid "Time"
 msgstr ""
 
-#: forms.py:171 menus.py:149 models.py:253 templates/core/groups.html:8
-#: templates/core/groups.html:9 templates/core/person_full.html:106
+#: forms.py:172 menus.py:160 models.py:319 templates/core/group/list.html:8
+#: templates/core/group/list.html:9 templates/core/person/full.html:136
 #, fuzzy
 #| msgid "Group"
 msgid "Groups"
 msgstr "Groupe"
 
-#: forms.py:175
+#: forms.py:176
 msgid "From when until when should the announcement be displayed?"
 msgstr ""
 
-#: forms.py:178
+#: forms.py:179
 msgid "Who should see the announcement?"
 msgstr ""
 
-#: forms.py:179
+#: forms.py:180
 msgid "Write your announcement:"
 msgstr ""
 
-#: forms.py:216
-msgid ""
-"You are not allowed to create announcements which are only valid in the past."
+#: forms.py:219
+msgid "You are not allowed to create announcements which are only valid in the past."
 msgstr ""
 
-#: forms.py:220
+#: forms.py:223
 msgid "The from date and time must be earlier then the until date and time."
 msgstr ""
 
-#: forms.py:229
+#: forms.py:232
 msgid "You need at least one recipient."
 msgstr ""
 
 #: menus.py:7 templates/two_factor/core/login.html:6
 #: templates/two_factor/core/login.html:10
-#: templates/two_factor/core/login.html:73
+#: templates/two_factor/core/login.html:86
 msgid "Login"
 msgstr ""
 
@@ -146,530 +170,586 @@ msgstr ""
 msgid "Admin"
 msgstr ""
 
-#: menus.py:75 models.py:487 templates/core/announcement/list.html:7
+#: menus.py:75 models.py:564 templates/core/announcement/list.html:7
 #: templates/core/announcement/list.html:8
 msgid "Announcements"
 msgstr ""
 
-#: menus.py:86 templates/core/data_management.html:6
-#: templates/core/data_management.html:7
+#: menus.py:86 models.py:92 templates/core/school_term/list.html:8
+#: templates/core/school_term/list.html:9
+msgid "School terms"
+msgstr ""
+
+#: menus.py:97 templates/core/management/data_management.html:6
+#: templates/core/management/data_management.html:7
 msgid "Data management"
 msgstr ""
 
-#: menus.py:94 templates/core/system_status.html:5
-#: templates/core/system_status.html:7
+#: menus.py:105 templates/core/pages/system_status.html:5
+#: templates/core/pages/system_status.html:7
 msgid "System status"
 msgstr ""
 
-#: menus.py:105
+#: menus.py:116
 msgid "Impersonation"
 msgstr ""
 
-#: menus.py:113
+#: menus.py:124
 msgid "Configuration"
 msgstr ""
 
-#: menus.py:124
+#: menus.py:135
 msgid "Backend Admin"
 msgstr ""
 
-#: menus.py:132
+#: menus.py:143
 msgid "People"
 msgstr ""
 
-#: menus.py:157
+#: menus.py:168 models.py:727 templates/core/group_type/list.html:8
+#: templates/core/group_type/list.html:9
+#, fuzzy
+#| msgid "Group"
+msgid "Group types"
+msgstr "Groupe"
+
+#: menus.py:179
 msgid "Persons and accounts"
 msgstr ""
 
-#: menus.py:168
+#: menus.py:190
 msgid "Groups and child groups"
 msgstr ""
 
-#: menus.py:183 templates/core/groups_child_groups.html:7
-#: templates/core/groups_child_groups.html:9
+#: menus.py:201 models.py:363 templates/core/additional_field/list.html:8
+#: templates/core/additional_field/list.html:9
+msgid "Additional fields"
+msgstr ""
+
+#: menus.py:216 templates/core/group/child_groups.html:7
+#: templates/core/group/child_groups.html:9
 msgid "Assign child groups to groups"
 msgstr ""
 
-#: models.py:29
+#: mixins.py:406
+msgid "Linked school term"
+msgstr ""
+
+#: models.py:33
 msgid "Boolean (Yes/No)"
 msgstr ""
 
-#: models.py:30
+#: models.py:34
 msgid "Text (one line)"
 msgstr ""
 
-#: models.py:32
+#: models.py:36
 msgid "Date and time"
 msgstr ""
 
-#: models.py:33
+#: models.py:37
 msgid "Decimal number"
 msgstr ""
 
-#: models.py:34 models.py:95
+#: models.py:38 models.py:146
 msgid "E-mail address"
 msgstr ""
 
-#: models.py:35
+#: models.py:39
 msgid "Integer"
 msgstr ""
 
-#: models.py:36
+#: models.py:40
 msgid "IP address"
 msgstr ""
 
-#: models.py:37
+#: models.py:41
 msgid "Boolean or empty (Yes/No/Neither)"
 msgstr ""
 
-#: models.py:38
+#: models.py:42
 msgid "Text (multi-line)"
 msgstr ""
 
-#: models.py:40
+#: models.py:44
 msgid "URL / Link"
 msgstr ""
 
-#: models.py:53 templates/core/persons_accounts.html:36
+#: models.py:56 models.py:700
+msgid "Name"
+msgstr ""
+
+#: models.py:58
+#, fuzzy
+#| msgid "Contact details"
+msgid "Start date"
+msgstr "Détails de contact"
+
+#: models.py:59
+msgid "End date"
+msgstr ""
+
+#: models.py:77
+msgid "The start date must be earlier than the end date."
+msgstr ""
+
+#: models.py:84
+msgid "There is already a school term for this time or a part of this time."
+msgstr ""
+
+#: models.py:104 templates/core/person/accounts.html:36
 msgid "Person"
 msgstr "Personne"
 
-#: models.py:56
+#: models.py:107
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can view address"
 msgstr "Détails de contact"
 
-#: models.py:57
+#: models.py:108
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can view contact details"
 msgstr "Détails de contact"
 
-#: models.py:58
+#: models.py:109
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can view photo"
 msgstr "Détails de contact"
 
-#: models.py:59
+#: models.py:110
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can view persons groups"
 msgstr "Détails de contact"
 
-#: models.py:60
+#: models.py:111
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can view personal details"
 msgstr "Détails de contact"
 
-#: models.py:65
+#: models.py:116
 msgid "female"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "male"
 msgstr ""
 
-#: models.py:73
+#: models.py:124
 msgid "Linked user"
 msgstr ""
 
-#: models.py:75
+#: models.py:126
 msgid "Is person active?"
 msgstr ""
 
-#: models.py:77
+#: models.py:128
 msgid "First name"
 msgstr "Prénom"
 
-#: models.py:78
+#: models.py:129
 msgid "Last name"
 msgstr "Nom de famille"
 
-#: models.py:80
+#: models.py:131
 msgid "Additional name(s)"
 msgstr ""
 
-#: models.py:84 models.py:260
+#: models.py:135 models.py:332
 #, fuzzy
 #| msgid "First name"
 msgid "Short name"
 msgstr "Prénom"
 
-#: models.py:87
+#: models.py:138
 msgid "Street"
 msgstr ""
 
-#: models.py:88
+#: models.py:139
 msgid "Street number"
 msgstr ""
 
-#: models.py:89
+#: models.py:140
 msgid "Postal code"
 msgstr ""
 
-#: models.py:90
+#: models.py:141
 msgid "Place"
 msgstr ""
 
-#: models.py:92
+#: models.py:143
 msgid "Home phone"
 msgstr ""
 
-#: models.py:93
+#: models.py:144
 msgid "Mobile phone"
 msgstr ""
 
-#: models.py:97
+#: models.py:148
 msgid "Date of birth"
 msgstr "Date d'anniversaire"
 
-#: models.py:98
+#: models.py:149
 msgid "Sex"
 msgstr "Sexe"
 
-#: models.py:100
+#: models.py:151
 msgid "Photo"
 msgstr ""
 
-#: models.py:105
+#: models.py:155 templates/core/person/full.html:129
 msgid "Guardians / Parents"
 msgstr ""
 
-#: models.py:112
+#: models.py:162
 msgid "Primary group"
 msgstr ""
 
-#: models.py:115 models.py:346 models.py:370 models.py:455 models.py:643
+#: models.py:165 models.py:423 models.py:447 models.py:532 models.py:720
+#: templates/core/person/full.html:112
 msgid "Description"
 msgstr "Description"
 
-#: models.py:233
+#: models.py:296
 msgid "Title of field"
 msgstr ""
 
-#: models.py:235
+#: models.py:298
 msgid "Type of field"
 msgstr ""
 
-#: models.py:239
+#: models.py:305
 msgid "Addtitional field for groups"
 msgstr ""
 
-#: models.py:240
+#: models.py:306
 msgid "Addtitional fields for groups"
 msgstr ""
 
-#: models.py:252
+#: models.py:318
 msgid "Group"
 msgstr "Groupe"
 
-#: models.py:254
+#: models.py:320
 msgid "Can assign child groups to groups"
 msgstr ""
 
-#: models.py:258
+#: models.py:330
 #, fuzzy
 #| msgid "Last name"
 msgid "Long name"
 msgstr "Nom de famille"
 
-#: models.py:268 templates/core/group_full.html:37
+#: models.py:340 templates/core/group/full.html:65
 msgid "Members"
 msgstr ""
 
-#: models.py:271 templates/core/group_full.html:34
+#: models.py:343 templates/core/group/full.html:62
 msgid "Owners"
 msgstr "Propriétaires"
 
-#: models.py:278
+#: models.py:350 templates/core/group/full.html:54
 msgid "Parent groups"
 msgstr ""
 
-#: models.py:286
+#: models.py:358
 msgid "Type of group"
 msgstr ""
 
-#: models.py:290
-msgid "Additional fields"
-msgstr ""
-
-#: models.py:342
+#: models.py:419
 msgid "User"
 msgstr ""
 
-#: models.py:345 models.py:369 models.py:454
+#: models.py:422 models.py:446 models.py:531
 #: templates/core/announcement/list.html:18
 msgid "Title"
 msgstr ""
 
-#: models.py:348
+#: models.py:425
 msgid "Application"
 msgstr ""
 
-#: models.py:354
+#: models.py:431
 msgid "Activity"
 msgstr ""
 
-#: models.py:355
+#: models.py:432
 msgid "Activities"
 msgstr ""
 
-#: models.py:361
+#: models.py:438
 msgid "Sender"
 msgstr ""
 
-#: models.py:366
+#: models.py:443
 msgid "Recipient"
 msgstr ""
 
-#: models.py:371 models.py:624
+#: models.py:448 models.py:701
 msgid "Link"
 msgstr ""
 
-#: models.py:373
+#: models.py:450
 msgid "Read"
 msgstr ""
 
-#: models.py:374
+#: models.py:451
 msgid "Sent"
 msgstr ""
 
-#: models.py:387
+#: models.py:464
 msgid "Notification"
 msgstr ""
 
-#: models.py:388
+#: models.py:465
 msgid "Notifications"
 msgstr ""
 
-#: models.py:456
+#: models.py:533
 msgid "Link to detailed view"
 msgstr ""
 
-#: models.py:459
+#: models.py:536
 msgid "Date and time from when to show"
 msgstr ""
 
-#: models.py:462
+#: models.py:539
 msgid "Date and time until when to show"
 msgstr ""
 
-#: models.py:486
+#: models.py:563
 msgid "Announcement"
 msgstr ""
 
-#: models.py:524
+#: models.py:601
 msgid "Announcement recipient"
 msgstr ""
 
-#: models.py:525
+#: models.py:602
 msgid "Announcement recipients"
 msgstr ""
 
-#: models.py:575
+#: models.py:652
 msgid "Widget Title"
 msgstr ""
 
-#: models.py:576
+#: models.py:653
 msgid "Activate Widget"
 msgstr ""
 
-#: models.py:594
+#: models.py:671
 msgid "Dashboard Widget"
 msgstr ""
 
-#: models.py:595
+#: models.py:672
 msgid "Dashboard Widgets"
 msgstr ""
 
-#: models.py:601
+#: models.py:678
 msgid "Menu ID"
 msgstr ""
 
-#: models.py:613
+#: models.py:690
 msgid "Custom menu"
 msgstr ""
 
-#: models.py:614
+#: models.py:691
 msgid "Custom menus"
 msgstr ""
 
-#: models.py:621
+#: models.py:698
 msgid "Menu"
 msgstr ""
 
-#: models.py:623
-msgid "Name"
-msgstr ""
-
-#: models.py:625
+#: models.py:702
 msgid "Icon"
 msgstr ""
 
-#: models.py:631
+#: models.py:708
 msgid "Custom menu item"
 msgstr ""
 
-#: models.py:632
+#: models.py:709
 msgid "Custom menu items"
 msgstr ""
 
-#: models.py:642
+#: models.py:719
 msgid "Title of type"
 msgstr ""
 
-#: models.py:646
+#: models.py:726 templates/core/group/full.html:46
 #, fuzzy
 #| msgid "Group"
 msgid "Group type"
 msgstr "Groupe"
 
-#: models.py:647
-#, fuzzy
-#| msgid "Group"
-msgid "Group types"
-msgstr "Groupe"
-
-#: models.py:656
+#: models.py:736
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can view system status"
 msgstr "Détails de contact"
 
-#: models.py:657
+#: models.py:737
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can link persons to accounts"
 msgstr "Détails de contact"
 
-#: models.py:658
+#: models.py:738
 msgid "Can manage data"
 msgstr ""
 
-#: models.py:659
+#: models.py:739
 #, fuzzy
 #| msgid "Contact details"
 msgid "Can impersonate"
 msgstr "Détails de contact"
 
-#: models.py:660
+#: models.py:740
 msgid "Can use search"
 msgstr ""
 
-#: models.py:661
+#: models.py:741
 msgid "Can change site preferences"
 msgstr ""
 
-#: models.py:662
+#: models.py:742
 msgid "Can change person preferences"
 msgstr ""
 
-#: models.py:663
+#: models.py:743
 msgid "Can change group preferences"
 msgstr ""
 
-#: preferences.py:27
+#: preferences.py:24
+msgid "Authentication"
+msgstr ""
+
+#: preferences.py:33
 msgid "Site title"
 msgstr ""
 
-#: preferences.py:36
+#: preferences.py:42
 #, fuzzy
 #| msgid "Description"
 msgid "Site description"
 msgstr "Description"
 
-#: preferences.py:45
+#: preferences.py:51
 msgid "Primary colour"
 msgstr ""
 
-#: preferences.py:54
+#: preferences.py:60
 msgid "Secondary colour"
 msgstr ""
 
-#: preferences.py:62
+#: preferences.py:68
 msgid "Logo"
 msgstr ""
 
-#: preferences.py:70
+#: preferences.py:76
 msgid "Favicon"
 msgstr ""
 
-#: preferences.py:78
+#: preferences.py:84
 msgid "PWA-Icon"
 msgstr ""
 
-#: preferences.py:87
+#: preferences.py:93
 #, fuzzy
 #| msgid "Last name"
 msgid "Mail out name"
 msgstr "Nom de famille"
 
-#: preferences.py:96
+#: preferences.py:102
 msgid "Mail out address"
 msgstr ""
 
-#: preferences.py:106
+#: preferences.py:112
 msgid "Link to privacy policy"
 msgstr ""
 
-#: preferences.py:116
+#: preferences.py:122
 msgid "Link to imprint"
 msgstr ""
 
-#: preferences.py:126
+#: preferences.py:132
 msgid "Name format for addressing"
 msgstr ""
 
-#: preferences.py:140
+#: preferences.py:146
 msgid "Channels to use for notifications"
 msgstr ""
 
-#: preferences.py:150
+#: preferences.py:156
 msgid "Regular expression to match primary group, e.g. '^Class .*'"
 msgstr ""
 
-#: preferences.py:159
+#: preferences.py:165
 msgid "Field on person to match primary group against"
 msgstr ""
 
-#: preferences.py:171
+#: preferences.py:177
 msgid "Display name of the school"
 msgstr ""
 
-#: preferences.py:180
+#: preferences.py:186
 msgid "Official name of the school, e.g. as given by supervisory authority"
 msgstr ""
 
-#: settings.py:276
+#: preferences.py:194
+msgid "Enabled custom authentication backends"
+msgstr ""
+
+#: settings.py:300
 msgid "English"
 msgstr ""
 
-#: settings.py:277
+#: settings.py:301
 msgid "German"
 msgstr ""
 
-#: settings.py:278
+#: settings.py:302
 msgid "French"
 msgstr ""
 
-#: templates/403.html:10 templates/404.html:10 templates/500.html:10
+#: settings.py:303
+msgid "Norwegian (bokmål)"
+msgstr ""
+
+#: tables.py:19 templates/core/announcement/list.html:36
+#: templates/core/group/full.html:23 templates/core/person/full.html:22
+msgid "Edit"
+msgstr ""
+
+#: tables.py:21 templates/core/announcement/list.html:22
+msgid "Actions"
+msgstr ""
+
+#: tables.py:56 tables.py:57 tables.py:71
+#: templates/core/announcement/list.html:42 templates/core/group/full.html:30
+#: templates/core/pages/delete.html:22 templates/core/person/full.html:29
+msgid "Delete"
+msgstr ""
+
+#: templates/403.html:14 templates/404.html:10 templates/500.html:10
 msgid "Error"
 msgstr ""
 
-#: templates/403.html:10
+#: templates/403.html:14
 msgid ""
 "You are not allowed to access the requested page or\n"
 "          object."
 msgstr ""
 
-#: templates/403.html:13 templates/404.html:17
+#: templates/403.html:19 templates/404.html:17
 msgid ""
 "\n"
-"            If you think this is an error in AlekSIS, please contact your "
-"site\n"
+"            If you think this is an error in AlekSIS, please contact your site\n"
 "            administrators:\n"
 "          "
 msgstr ""
@@ -697,8 +777,7 @@ msgstr ""
 #: templates/500.html:13
 msgid ""
 "\n"
-"            Your site administrators will automatically be notified about "
-"this\n"
+"            Your site administrators will automatically be notified about this\n"
 "            error. You can also contact them directly:\n"
 "          "
 msgstr ""
@@ -712,75 +791,17 @@ msgstr ""
 #: templates/503.html:13
 msgid ""
 "\n"
-"            This page is currently unavailable. If this error persists, "
-"contact your site administrators:\n"
+"            This page is currently unavailable. If this error persists, contact your site administrators:\n"
 "          "
 msgstr ""
 
-#: templates/core/about.html:6 templates/core/about.html:15
-msgid "About AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:7
-msgid "AlekSIS – The Free School Information System"
-msgstr ""
-
-#: templates/core/about.html:17
-msgid ""
-"\n"
-"              This platform is powered by AlekSIS, a web-based school "
-"information system (SIS) which can be used\n"
-"              to manage and/or publish organisational artifacts of "
-"educational institutions. AlekSIS is free software and\n"
-"              can be used by anyone.\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:25
-msgid "Website of AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:26
-msgid "Source code"
-msgstr ""
-
-#: templates/core/about.html:35
-msgid "Licence information"
-msgstr ""
-
-#: templates/core/about.html:37
-msgid ""
-"\n"
-"              The core and the official apps of AlekSIS are licenced under "
-"the EUPL, version 1.2 or later. For licence\n"
-"              information from third-party apps, if installed, refer to the "
-"respective components below. The\n"
-"              licences are marked like this:\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:45
-msgid "Free/Open Source Licence"
+#: templates/core/additional_field/edit.html:6
+#: templates/core/additional_field/edit.html:7
+msgid "Edit additional field"
 msgstr ""
 
-#: templates/core/about.html:46
-msgid "Other Licence"
-msgstr ""
-
-#: templates/core/about.html:50
-msgid "Full licence text"
-msgstr ""
-
-#: templates/core/about.html:51
-msgid "More information about the EUPL"
-msgstr ""
-
-#: templates/core/about.html:90
-#, python-format
-msgid ""
-"\n"
-"                    This app is licenced under %(licence)s.\n"
-"                  "
+#: templates/core/additional_field/list.html:14
+msgid "Create additional field"
 msgstr ""
 
 #: templates/core/announcement/form.html:10
@@ -813,163 +834,138 @@ msgstr ""
 msgid "Recipients"
 msgstr ""
 
-#: templates/core/announcement/list.html:22
-msgid "Actions"
-msgstr ""
-
-#: templates/core/announcement/list.html:36 templates/core/group_full.html:22
-#: templates/core/person_full.html:21
-msgid "Edit"
-msgstr ""
-
-#: templates/core/announcement/list.html:42
-msgid "Delete"
-msgstr ""
-
 #: templates/core/announcement/list.html:50
 msgid "There are no announcements."
 msgstr ""
 
-#: templates/core/announcements.html:9 templates/core/announcements.html:36
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:13
-#, python-format
-msgid ""
-"\n"
-"              Valid from %(from)s until %(until)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:40
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s – %(until)s\n"
-"            "
-msgstr ""
-
 #: templates/core/base.html:54
 msgid "Logged in as"
 msgstr ""
 
-#: templates/core/base.html:76 templates/search/search.html:7
-#: templates/search/search.html:22
-msgid "Search"
-msgstr ""
-
-#: templates/core/base.html:148
+#: templates/core/base.html:147
 msgid "About AlekSIS — The Free School Information System"
 msgstr ""
 
-#: templates/core/base.html:156
+#: templates/core/base.html:155
 msgid "Impress"
 msgstr ""
 
-#: templates/core/base.html:164
+#: templates/core/base.html:163
 msgid "Privacy Policy"
 msgstr ""
 
-#: templates/core/base_print.html:62
+#: templates/core/base_print.html:64
 msgid "Powered by AlekSIS"
 msgstr ""
 
-#: templates/core/edit_group.html:6 templates/core/edit_group.html:7
-msgid "Edit group"
-msgstr ""
-
-#: templates/core/edit_person.html:8 templates/core/edit_person.html:9
-msgid "Edit person"
-msgstr ""
-
-#: templates/core/group_full.html:28 templates/core/person_full.html:28
-msgid "Change preferences"
-msgstr ""
-
-#: templates/core/groups.html:14
-msgid "Create group"
-msgstr ""
-
-#: templates/core/groups_child_groups.html:18
+#: templates/core/group/child_groups.html:18
 msgid ""
 "\n"
-"          You can use this to assign child groups to groups. Please use the "
-"filters below to select groups you want to\n"
+"          You can use this to assign child groups to groups. Please use the filters below to select groups you want to\n"
 "          change and click \"Next\".\n"
 "        "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:31
+#: templates/core/group/child_groups.html:31
 msgid "Update selection"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:35
+#: templates/core/group/child_groups.html:35
 msgid "Clear all filters"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:39
+#: templates/core/group/child_groups.html:39
 msgid "Currently selected groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:52
+#: templates/core/group/child_groups.html:52
 msgid "Start assigning child groups for this groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:61
+#: templates/core/group/child_groups.html:61
 msgid ""
 "\n"
 "            Please select some groups in order to go on with assigning.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:72
+#: templates/core/group/child_groups.html:72
 msgid "Current group:"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:78
+#: templates/core/group/child_groups.html:78
 msgid "Please be careful!"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:79
+#: templates/core/group/child_groups.html:79
 msgid ""
 "\n"
-"            If you click \"Back\" or \"Next\" the current group assignments "
-"are not saved.\n"
-"            If you click \"Save\", you will overwrite all existing child "
-"group relations for this group with what you\n"
+"            If you click \"Back\" or \"Next\" the current group assignments are not saved.\n"
+"            If you click \"Save\", you will overwrite all existing child group relations for this group with what you\n"
 "            selected on this page.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:93
-#: templates/core/groups_child_groups.html:128
+#: templates/core/group/child_groups.html:93
+#: templates/core/group/child_groups.html:128
 #: templates/two_factor/_wizard_actions.html:15
 #: templates/two_factor/_wizard_actions.html:20
 msgid "Back"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:99
-#: templates/core/groups_child_groups.html:134
+#: templates/core/group/child_groups.html:99
+#: templates/core/group/child_groups.html:134
 #: templates/two_factor/_wizard_actions.html:26
 msgid "Next"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:106
-#: templates/core/groups_child_groups.html:141
-#: templates/core/save_button.html:3
+#: templates/core/group/child_groups.html:106
+#: templates/core/group/child_groups.html:141
+#: templates/core/partials/save_button.html:3
 msgid "Save"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:112
-#: templates/core/groups_child_groups.html:147
+#: templates/core/group/child_groups.html:112
+#: templates/core/group/child_groups.html:147
 msgid "Save and next"
 msgstr ""
 
+#: templates/core/group/edit.html:6 templates/core/group/edit.html:7
+msgid "Edit group"
+msgstr ""
+
+#: templates/core/group/full.html:37 templates/core/person/full.html:36
+msgid "Change preferences"
+msgstr ""
+
+#: templates/core/group/list.html:14
+msgid "Create group"
+msgstr ""
+
+#: templates/core/group/list.html:17
+msgid "Filter groups"
+msgstr ""
+
+#: templates/core/group/list.html:24 templates/core/person/list.html:28
+msgid "Clear"
+msgstr ""
+
+#: templates/core/group/list.html:28
+msgid "Selected groups"
+msgstr ""
+
+#: templates/core/group_type/edit.html:6 templates/core/group_type/edit.html:7
+#, fuzzy
+#| msgid "Group"
+msgid "Edit group type"
+msgstr "Groupe"
+
+#: templates/core/group_type/list.html:14
+#, fuzzy
+#| msgid "Group"
+msgid "Create group type"
+msgstr "Groupe"
+
 #: templates/core/index.html:4
 msgid "Home"
 msgstr ""
@@ -994,105 +990,332 @@ msgstr ""
 msgid "No notifications available yet."
 msgstr ""
 
-#: templates/core/no_person.html:12
+#: templates/core/pages/about.html:6 templates/core/pages/about.html:15
+msgid "About AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:7
+msgid "AlekSIS – The Free School Information System"
+msgstr ""
+
+#: templates/core/pages/about.html:17
 msgid ""
 "\n"
-"            Your administrator account is not linked to any person. "
-"Therefore,\n"
-"            a dummy person has been linked to your account.\n"
-"          "
+"              This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used\n"
+"              to manage and/or publish organisational artifacts of educational institutions. AlekSIS is free software and\n"
+"              can be used by anyone.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/about.html:25
+msgid "Website of AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:26
+msgid "Source code"
+msgstr ""
+
+#: templates/core/pages/about.html:35
+msgid "Licence information"
 msgstr ""
 
-#: templates/core/no_person.html:19
+#: templates/core/pages/about.html:37
 msgid ""
 "\n"
-"            Your user account is not linked to a person. This means you\n"
-"            cannot access any school-related information. Please contact\n"
-"            the managers of AlekSIS at your school.\n"
-"          "
+"              The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence\n"
+"              information from third-party apps, if installed, refer to the respective components below. The\n"
+"              licences are marked like this:\n"
+"            "
 msgstr ""
 
-#: templates/core/person_full.html:34
-msgid "Contact details"
-msgstr "Détails de contact"
+#: templates/core/pages/about.html:45
+msgid "Free/Open Source Licence"
+msgstr ""
 
-#: templates/core/persons_accounts.html:7
-#: templates/core/persons_accounts.html:9
-msgid "Link persons to accounts"
+#: templates/core/pages/about.html:46
+msgid "Other Licence"
 msgstr ""
 
-#: templates/core/persons_accounts.html:16
+#: templates/core/pages/about.html:50
+msgid "Full licence text"
+msgstr ""
+
+#: templates/core/pages/about.html:51
+msgid "More information about the EUPL"
+msgstr ""
+
+#: templates/core/pages/about.html:90
+#, python-format
 msgid ""
 "\n"
-"        You can use this form to assign user accounts to persons. Use the\n"
-"        dropdowns to select existing accounts; use the text fields to create "
-"new\n"
-"        accounts on-the-fly. The latter will create a new account with the\n"
-"        entered username and copy all other details from the person.\n"
-"      "
+"                    This app is licenced under %(licence)s.\n"
+"                  "
 msgstr ""
 
-#: templates/core/persons_accounts.html:31
-#: templates/core/persons_accounts.html:55
-msgid "Update"
+#: templates/core/pages/delete.html:6
+#, python-format
+msgid "Delete %(object_name)s"
 msgstr ""
 
-#: templates/core/persons_accounts.html:37
-msgid "Existing account"
+#: templates/core/pages/delete.html:13
+#, python-format
+msgid ""
+"\n"
+"      Do you really want to delete the %(object_name)s \"%(object)s\"?\n"
+"    "
 msgstr ""
 
-#: templates/core/persons_accounts.html:38
-msgid "New account"
+#: templates/core/pages/offline.html:6
+msgid ""
+"No internet\n"
+"    connection."
 msgstr ""
 
-#: templates/core/system_status.html:12
+#: templates/core/pages/offline.html:10
+msgid ""
+"\n"
+"      There was an error accessing this page. You probably don't have an internet connection. Check to see if your WiFi\n"
+"      or mobile data is turned on and try again. If you think you are connected, please contact the system\n"
+"      administrators:\n"
+"    "
+msgstr ""
+
+#: templates/core/pages/progress.html:27
+msgid ""
+"\n"
+"              Without activated JavaScript the progress status can't be updated.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/progress.html:47
+#: templates/two_factor/core/otp_required.html:19
+msgid "Go back"
+msgstr ""
+
+#: templates/core/pages/system_status.html:12
 msgid "System checks"
 msgstr ""
 
-#: templates/core/system_status.html:21
+#: templates/core/pages/system_status.html:21
 msgid "Maintenance mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:23
+#: templates/core/pages/system_status.html:23
 msgid ""
 "\n"
-"                Only admin and visitors from internal IPs can access "
-"thesite.\n"
+"                Only admin and visitors from internal IPs can access thesite.\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:34
+#: templates/core/pages/system_status.html:34
 msgid "Maintenance mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:35
+#: templates/core/pages/system_status.html:35
 msgid "Everyone can access the site."
 msgstr ""
 
-#: templates/core/system_status.html:45
+#: templates/core/pages/system_status.html:45
 msgid "Debug mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:47
+#: templates/core/pages/system_status.html:47
 msgid ""
 "\n"
-"                The web server throws back debug information on errors. Do "
-"not use in production!\n"
+"                The web server throws back debug information on errors. Do not use in production!\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:54
+#: templates/core/pages/system_status.html:54
 msgid "Debug mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:56
+#: templates/core/pages/system_status.html:56
 msgid ""
 "\n"
-"                Debug mode is disabled. Default error pages are displayed on "
-"errors.\n"
+"                Debug mode is disabled. Default error pages are displayed on errors.\n"
 "              "
 msgstr ""
 
+#: templates/core/pages/system_status.html:69
+msgid "System health checks"
+msgstr ""
+
+#: templates/core/pages/system_status.html:75
+msgid "Service"
+msgstr ""
+
+#: templates/core/pages/system_status.html:76
+#: templates/core/pages/system_status.html:115
+msgid "Status"
+msgstr ""
+
+#: templates/core/pages/system_status.html:77
+msgid "Time taken"
+msgstr ""
+
+#: templates/core/pages/system_status.html:96
+msgid "seconds"
+msgstr ""
+
+#: templates/core/pages/system_status.html:107
+msgid "Celery task results"
+msgstr ""
+
+#: templates/core/pages/system_status.html:112
+msgid "Task"
+msgstr ""
+
+#: templates/core/pages/system_status.html:113
+msgid "ID"
+msgstr ""
+
+#: templates/core/pages/system_status.html:114
+#, fuzzy
+#| msgid "Date"
+msgid "Date done"
+msgstr "Date"
+
+#: templates/core/partials/announcements.html:9
+#: templates/core/partials/announcements.html:36
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:13
+#, python-format
+msgid ""
+"\n"
+"              Valid from %(from)s until %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:40
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s – %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:10
+#, python-format
+msgid ""
+"\n"
+"              Created by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:14
+#: templates/core/partials/crud_events.html:22
+#: templates/core/partials/crud_events.html:26
+#, python-format
+msgid ""
+"\n"
+"              Updated by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:18
+#, python-format
+msgid ""
+"\n"
+"              Deleted by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/language_form.html:16
+msgid "Language"
+msgstr ""
+
+#: templates/core/partials/language_form.html:28
+msgid "Select language"
+msgstr ""
+
+#: templates/core/partials/no_person.html:12
+msgid ""
+"\n"
+"            Your administrator account is not linked to any person. Therefore,\n"
+"            a dummy person has been linked to your account.\n"
+"          "
+msgstr ""
+
+#: templates/core/partials/no_person.html:19
+msgid ""
+"\n"
+"            Your user account is not linked to a person. This means you\n"
+"            cannot access any school-related information. Please contact\n"
+"            the managers of AlekSIS at your school.\n"
+"          "
+msgstr ""
+
+#: templates/core/person/accounts.html:7 templates/core/person/accounts.html:9
+msgid "Link persons to accounts"
+msgstr ""
+
+#: templates/core/person/accounts.html:16
+msgid ""
+"\n"
+"        You can use this form to assign user accounts to persons. Use the\n"
+"        dropdowns to select existing accounts; use the text fields to create new\n"
+"        accounts on-the-fly. The latter will create a new account with the\n"
+"        entered username and copy all other details from the person.\n"
+"      "
+msgstr ""
+
+#: templates/core/person/accounts.html:31
+#: templates/core/person/accounts.html:55
+msgid "Update"
+msgstr ""
+
+#: templates/core/person/accounts.html:37
+msgid "Existing account"
+msgstr ""
+
+#: templates/core/person/accounts.html:38
+msgid "New account"
+msgstr ""
+
+#: templates/core/person/edit.html:11 templates/core/person/edit.html:12
+msgid "Edit person"
+msgstr ""
+
+#: templates/core/person/full.html:42
+msgid "Contact details"
+msgstr "Détails de contact"
+
+#: templates/core/person/full.html:122
+msgid "Children"
+msgstr ""
+
+#: templates/core/person/list.html:17
+#, fuzzy
+#| msgid "Contact details"
+msgid "Create person"
+msgstr "Détails de contact"
+
+#: templates/core/person/list.html:21
+msgid "Filter persons"
+msgstr ""
+
+#: templates/core/person/list.html:32
+msgid "Selected persons"
+msgstr ""
+
+#: templates/core/school_term/create.html:6
+#: templates/core/school_term/create.html:7
+#: templates/core/school_term/list.html:14
+msgid "Create school term"
+msgstr ""
+
+#: templates/core/school_term/edit.html:6
+#: templates/core/school_term/edit.html:7
+msgid "Edit school term"
+msgstr ""
+
 #: templates/dynamic_preferences/form.html:9
 msgid "Site preferences"
 msgstr ""
@@ -1118,23 +1341,6 @@ msgstr ""
 msgid "Impersonate user"
 msgstr ""
 
-#: templates/offline.html:6
-msgid ""
-"No internet\n"
-"    connection."
-msgstr ""
-
-#: templates/offline.html:10
-msgid ""
-"\n"
-"      There was an error accessing this page. You probably don't have an "
-"internet connection. Check to see if your WiFi\n"
-"      or mobile data is turned on and try again. If you think you are "
-"connected, please contact the system\n"
-"      administrators:\n"
-"    "
-msgstr ""
-
 #: templates/search/search.html:8
 msgid "Global Search"
 msgstr ""
@@ -1159,28 +1365,43 @@ msgstr ""
 msgid "New notification for"
 msgstr ""
 
-#: templates/templated_email/notification.email:7
-msgid "Dear"
+#: templates/templated_email/notification.email:6
+#: templates/templated_email/notification.email:27
+#, python-format
+msgid "Dear %(notification_user)s,"
 msgstr ""
 
 #: templates/templated_email/notification.email:8
+#: templates/templated_email/notification.email:29
 msgid "we got a new notification for you:"
 msgstr ""
 
-#: templates/templated_email/notification.email:12
+#: templates/templated_email/notification.email:15
+#: templates/templated_email/notification.email:35
 msgid "More information"
 msgstr ""
 
-#: templates/templated_email/notification.email:16
+#: templates/templated_email/notification.email:18
 #, python-format
 msgid ""
 "\n"
-"    <p>By %(trans_sender)s at %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Your AlekSIS team</i>\n"
+"        Sent by %(trans_sender)s at %(trans_created_at)s\n"
 "    "
 msgstr ""
 
+#: templates/templated_email/notification.email:22
+#: templates/templated_email/notification.email:46
+msgid "Your AlekSIS team"
+msgstr ""
+
+#: templates/templated_email/notification.email:40
+#, python-format
+msgid ""
+"\n"
+"            Sent by %(trans_sender)s at %(trans_created_at)s\n"
+"        "
+msgstr ""
+
 #: templates/two_factor/_base_focus.html:6
 #: templates/two_factor/core/otp_required.html:22
 #: templates/two_factor/core/setup.html:5
@@ -1203,10 +1424,8 @@ msgid ""
 "\n"
 "        Backup tokens can be used when your primary and backup\n"
 "        phone numbers aren't available. The backup tokens below can be used\n"
-"        for login verification. If you've used up all your backup tokens, "
-"you\n"
-"        can generate a new set of backup tokens. Only the backup tokens "
-"shown\n"
+"        for login verification. If you've used up all your backup tokens, you\n"
+"        can generate a new set of backup tokens. Only the backup tokens shown\n"
 "        below will be valid.\n"
 "      "
 msgstr ""
@@ -1231,52 +1450,58 @@ msgid "Generate Tokens"
 msgstr ""
 
 #: templates/two_factor/core/login.html:16
-msgid ""
-"You have no permission to view this page. Please login with an other account."
+msgid "You have no permission to view this page. Please login with an other account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:25
+#: templates/two_factor/core/login.html:24
 msgid "Please login to see this page."
 msgstr ""
 
-#: templates/two_factor/core/login.html:28
+#: templates/two_factor/core/login.html:30
+msgid "Login with username and password"
+msgstr ""
+
+#: templates/two_factor/core/login.html:40
 msgid ""
 "We are calling your phone right now, please enter the\n"
 "              digits you hear."
 msgstr ""
 
-#: templates/two_factor/core/login.html:31
+#: templates/two_factor/core/login.html:43
 msgid ""
 "We sent you a text message, please enter the tokens we\n"
 "              sent."
 msgstr ""
 
-#: templates/two_factor/core/login.html:34
+#: templates/two_factor/core/login.html:46
 msgid ""
 "Please enter the tokens generated by your token\n"
 "              generator."
 msgstr ""
 
-#: templates/two_factor/core/login.html:38
+#: templates/two_factor/core/login.html:50
 msgid ""
 "Use this form for entering backup tokens for logging in.\n"
-"            These tokens have been generated for you to print and keep safe. "
-"Please\n"
+"            These tokens have been generated for you to print and keep safe. Please\n"
 "            enter one of these backup tokens to login to your account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:56
+#: templates/two_factor/core/login.html:68
 msgid "Or, alternatively, use one of your backup phones:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:66
+#: templates/two_factor/core/login.html:78
 msgid "As a last resort, you can use a backup token:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:69
+#: templates/two_factor/core/login.html:81
 msgid "Use Backup Token"
 msgstr ""
 
+#: templates/two_factor/core/login.html:93
+msgid "Use alternative login options"
+msgstr ""
+
 #: templates/two_factor/core/otp_required.html:9
 msgid "Permission Denied"
 msgstr ""
@@ -1284,8 +1509,7 @@ msgstr ""
 #: templates/two_factor/core/otp_required.html:10
 msgid ""
 "The page you requested, enforces users to verify using\n"
-"          two-factor authentication for security reasons. You need to enable "
-"these\n"
+"          two-factor authentication for security reasons. You need to enable these\n"
 "          security features in order to access this page."
 msgstr ""
 
@@ -1296,10 +1520,6 @@ msgid ""
 "          security."
 msgstr ""
 
-#: templates/two_factor/core/otp_required.html:19
-msgid "Go back"
-msgstr ""
-
 #: templates/two_factor/core/phone_register.html:5
 #: templates/two_factor/core/phone_register.html:9
 msgid "Add Backup Phone"
@@ -1362,8 +1582,7 @@ msgstr ""
 #: templates/two_factor/core/setup.html:50
 msgid ""
 "\n"
-"            We are calling your phone right now, please enter the digits you "
-"hear.\n"
+"            We are calling your phone right now, please enter the digits you hear.\n"
 "          "
 msgstr ""
 
@@ -1377,12 +1596,9 @@ msgstr ""
 #: templates/two_factor/core/setup.html:63
 msgid ""
 "\n"
-"          We've encountered an issue with the selected authentication "
-"method. Please\n"
-"          go back and verify that you entered your information correctly, "
-"try\n"
-"          again, or use a different authentication method instead. If the "
-"issue\n"
+"          We've encountered an issue with the selected authentication method. Please\n"
+"          go back and verify that you entered your information correctly, try\n"
+"          again, or use a different authentication method instead. If the issue\n"
 "          persists, contact the site administrator.\n"
 "        "
 msgstr ""
@@ -1404,8 +1620,7 @@ msgstr ""
 #: templates/two_factor/core/setup_complete.html:14
 msgid ""
 "\n"
-"        Congratulations, you've successfully enabled two-factor "
-"authentication.\n"
+"        Congratulations, you've successfully enabled two-factor authentication.\n"
 "      "
 msgstr ""
 
@@ -1423,8 +1638,7 @@ msgstr ""
 msgid ""
 "\n"
 "          However, it might happen that you don't have access to\n"
-"          your primary token device. To enable account recovery, generate "
-"backup codes\n"
+"          your primary token device. To enable account recovery, generate backup codes\n"
 "          or add a phone number.\n"
 "        "
 msgstr ""
@@ -1442,9 +1656,7 @@ msgid "Disable Two-Factor Authentication"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:12
-msgid ""
-"You are about to disable two-factor authentication. This weakens your "
-"account security, are you sure?"
+msgid "You are about to disable two-factor authentication. This weakens your account security, are you sure?"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:26
@@ -1531,26 +1743,58 @@ msgstr ""
 msgid "SMS"
 msgstr ""
 
-#: views.py:212
+#: views.py:122
+msgid "The school term has been created."
+msgstr ""
+
+#: views.py:133
+msgid "The school term has been saved."
+msgstr ""
+
+#: views.py:273
 msgid "The child groups were successfully saved."
 msgstr ""
 
-#: views.py:240
+#: views.py:309
 msgid "The person has been saved."
 msgstr ""
 
-#: views.py:276
+#: views.py:346
 msgid "The group has been saved."
 msgstr ""
 
-#: views.py:348
+#: views.py:434
 msgid "The announcement has been saved."
 msgstr ""
 
-#: views.py:364
+#: views.py:450
 msgid "The announcement has been deleted."
 msgstr ""
 
-#: views.py:435
+#: views.py:521
 msgid "The preferences have been saved successfully."
 msgstr ""
+
+#: views.py:544
+msgid "The person has been deleted."
+msgstr ""
+
+#: views.py:557
+msgid "The group has been deleted."
+msgstr ""
+
+#: views.py:588
+msgid "The additional_field has been saved."
+msgstr ""
+
+#: views.py:622
+msgid "The additional field has been deleted."
+msgstr ""
+
+#: views.py:646
+msgid "The group type has been saved."
+msgstr ""
+
+#: views.py:676
+msgid "The group type has been deleted."
+msgstr ""
diff --git a/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po b/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po
index 417efd1fc19835a2763ca93f09e98863c9d77c61..62da02ce6b9e58455b9ed6547a5d1380b2b062ac 100644
--- a/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po
+++ b/aleksis/core/locale/fr/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-03 10:36+0000\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,14 +18,14 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 
-#: aleksis/core/static/js/main.js:21
+#: static/js/main.js:21
 msgid "Today"
 msgstr ""
 
-#: aleksis/core/static/js/main.js:22
+#: static/js/main.js:22
 msgid "Cancel"
 msgstr ""
 
-#: aleksis/core/static/js/main.js:23
+#: static/js/main.js:23
 msgid "OK"
 msgstr ""
diff --git a/aleksis/core/locale/la/LC_MESSAGES/django.po b/aleksis/core/locale/la/LC_MESSAGES/django.po
index ea6778d9a100251312966073db19d4a1cf7002e3..0fe692359d53218a555763890f363f7c9ed9e382 100644
--- a/aleksis/core/locale/la/LC_MESSAGES/django.po
+++ b/aleksis/core/locale/la/LC_MESSAGES/django.po
@@ -7,11 +7,10 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-04 15:39+0200\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: 2020-04-27 13:03+0000\n"
 "Last-Translator: Julian <leuckerj@gmail.com>\n"
-"Language-Team: Latin <https://translate.edugit.org/projects/aleksis/aleksis/"
-"la/>\n"
+"Language-Team: Latin <https://translate.edugit.org/projects/aleksis/aleksis/la/>\n"
 "Language: la\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -19,6 +18,24 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Generator: Weblate 4.0.1\n"
 
+#: filters.py:37 templates/core/base.html:77 templates/core/group/list.html:20
+#: templates/core/person/list.html:24 templates/search/search.html:7
+#: templates/search/search.html:22
+msgid "Search"
+msgstr ""
+
+#: filters.py:53
+#, fuzzy
+#| msgid "Short name"
+msgid "Search by name"
+msgstr "Breve nomen"
+
+#: filters.py:65
+#, fuzzy
+#| msgid "E-mail address"
+msgid "Search by contact details"
+msgstr "Inscriptio electronica"
+
 #: forms.py:46
 msgid "You cannot set a new username when also selecting an existing user."
 msgstr ""
@@ -45,68 +62,77 @@ msgstr ""
 msgid "Advanced personal data"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "New user"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 #, fuzzy
 #| msgid "Persons and accounts"
 msgid "Create a new account"
 msgstr "Personae et computi"
 
-#: forms.py:128
+#: forms.py:126 models.py:91
+msgid "School term"
+msgstr "Anus scolae"
+
+#: forms.py:127
 #, fuzzy
 #| msgid "Data management"
 msgid "Common data"
 msgstr "Adminstratio datarum"
 
-#: forms.py:129 forms.py:169 menus.py:141 models.py:54
-#: templates/core/persons.html:8 templates/core/persons.html:9
+#: forms.py:128 forms.py:170 menus.py:152 models.py:105
+#: templates/core/person/list.html:8 templates/core/person/list.html:9
 msgid "Persons"
 msgstr "personae"
 
-#: forms.py:162 forms.py:165 models.py:31
+#: forms.py:129
+#, fuzzy
+#| msgid "Additional name(s)"
+msgid "Additional data"
+msgstr "addita nomines"
+
+#: forms.py:163 forms.py:166 models.py:35
 msgid "Date"
 msgstr "dies"
 
-#: forms.py:163 forms.py:166 models.py:39
+#: forms.py:164 forms.py:167 models.py:43
 msgid "Time"
 msgstr "tempus"
 
-#: forms.py:171 menus.py:149 models.py:253 templates/core/groups.html:8
-#: templates/core/groups.html:9 templates/core/person_full.html:106
+#: forms.py:172 menus.py:160 models.py:319 templates/core/group/list.html:8
+#: templates/core/group/list.html:9 templates/core/person/full.html:136
 msgid "Groups"
 msgstr "Greges"
 
-#: forms.py:175
+#: forms.py:176
 msgid "From when until when should the announcement be displayed?"
 msgstr ""
 
-#: forms.py:178
+#: forms.py:179
 msgid "Who should see the announcement?"
 msgstr "Quis nuntium videatne?"
 
-#: forms.py:179
+#: forms.py:180
 msgid "Write your announcement:"
 msgstr "Scribe nuntium:"
 
-#: forms.py:216
-msgid ""
-"You are not allowed to create announcements which are only valid in the past."
+#: forms.py:219
+msgid "You are not allowed to create announcements which are only valid in the past."
 msgstr ""
 
-#: forms.py:220
+#: forms.py:223
 msgid "The from date and time must be earlier then the until date and time."
 msgstr ""
 
-#: forms.py:229
+#: forms.py:232
 msgid "You need at least one recipient."
 msgstr ""
 
 #: menus.py:7 templates/two_factor/core/login.html:6
 #: templates/two_factor/core/login.html:10
-#: templates/two_factor/core/login.html:73
+#: templates/two_factor/core/login.html:86
 msgid "Login"
 msgstr "nomen profiteri"
 
@@ -142,560 +168,620 @@ msgstr ""
 msgid "Admin"
 msgstr "Administratio"
 
-#: menus.py:75 models.py:487 templates/core/announcement/list.html:7
+#: menus.py:75 models.py:564 templates/core/announcement/list.html:7
 #: templates/core/announcement/list.html:8
 msgid "Announcements"
 msgstr "Nuntii"
 
-#: menus.py:86 templates/core/data_management.html:6
-#: templates/core/data_management.html:7
+#: menus.py:86 models.py:92 templates/core/school_term/list.html:8
+#: templates/core/school_term/list.html:9
+msgid "School terms"
+msgstr "ani scolae"
+
+#: menus.py:97 templates/core/management/data_management.html:6
+#: templates/core/management/data_management.html:7
 msgid "Data management"
 msgstr "Adminstratio datarum"
 
-#: menus.py:94 templates/core/system_status.html:5
-#: templates/core/system_status.html:7
+#: menus.py:105 templates/core/pages/system_status.html:5
+#: templates/core/pages/system_status.html:7
 msgid "System status"
 msgstr "Status systemae"
 
-#: menus.py:105
+#: menus.py:116
 msgid "Impersonation"
 msgstr "Simulare aliquem"
 
-#: menus.py:113
+#: menus.py:124
 #, fuzzy
 #| msgid "Notification"
 msgid "Configuration"
 msgstr "Nuntius"
 
-#: menus.py:124
+#: menus.py:135
 msgid "Backend Admin"
 msgstr ""
 
-#: menus.py:132
+#: menus.py:143
 msgid "People"
 msgstr "Personae"
 
-#: menus.py:157
+#: menus.py:168 models.py:727 templates/core/group_type/list.html:8
+#: templates/core/group_type/list.html:9
+#, fuzzy
+#| msgid "Groups"
+msgid "Group types"
+msgstr "Greges"
+
+#: menus.py:179
 msgid "Persons and accounts"
 msgstr "Personae et computi"
 
-#: menus.py:168
+#: menus.py:190
 msgid "Groups and child groups"
 msgstr ""
 
-#: menus.py:183 templates/core/groups_child_groups.html:7
-#: templates/core/groups_child_groups.html:9
+#: menus.py:201 models.py:363 templates/core/additional_field/list.html:8
+#: templates/core/additional_field/list.html:9
+#, fuzzy
+#| msgid "Additional name(s)"
+msgid "Additional fields"
+msgstr "addita nomines"
+
+#: menus.py:216 templates/core/group/child_groups.html:7
+#: templates/core/group/child_groups.html:9
 msgid "Assign child groups to groups"
 msgstr ""
 
-#: models.py:29
+#: mixins.py:406
+#, fuzzy
+#| msgid "Edit school term"
+msgid "Linked school term"
+msgstr "Muta anum scolae"
+
+#: models.py:33
 msgid "Boolean (Yes/No)"
 msgstr ""
 
-#: models.py:30
+#: models.py:34
 msgid "Text (one line)"
 msgstr ""
 
-#: models.py:32
+#: models.py:36
 msgid "Date and time"
 msgstr ""
 
-#: models.py:33
+#: models.py:37
 msgid "Decimal number"
 msgstr ""
 
-#: models.py:34 models.py:95
+#: models.py:38 models.py:146
 msgid "E-mail address"
 msgstr "Inscriptio electronica"
 
-#: models.py:35
+#: models.py:39
 msgid "Integer"
 msgstr ""
 
-#: models.py:36
+#: models.py:40
 #, fuzzy
 #| msgid "E-mail address"
 msgid "IP address"
 msgstr "Inscriptio electronica"
 
-#: models.py:37
+#: models.py:41
 msgid "Boolean or empty (Yes/No/Neither)"
 msgstr ""
 
-#: models.py:38
+#: models.py:42
 msgid "Text (multi-line)"
 msgstr ""
 
-#: models.py:40
+#: models.py:44
 msgid "URL / Link"
 msgstr ""
 
-#: models.py:53 templates/core/persons_accounts.html:36
+#: models.py:56 models.py:700
+msgid "Name"
+msgstr "Nomen"
+
+#: models.py:58
+msgid "Start date"
+msgstr ""
+
+#: models.py:59
+msgid "End date"
+msgstr ""
+
+#: models.py:77
+msgid "The start date must be earlier than the end date."
+msgstr ""
+
+#: models.py:84
+msgid "There is already a school term for this time or a part of this time."
+msgstr ""
+
+#: models.py:104 templates/core/person/accounts.html:36
 msgid "Person"
 msgstr "Persona"
 
-#: models.py:56
+#: models.py:107
 #, fuzzy
 #| msgid "E-mail address"
 msgid "Can view address"
 msgstr "Inscriptio electronica"
 
-#: models.py:57
+#: models.py:108
 #, fuzzy
 #| msgid "E-mail address"
 msgid "Can view contact details"
 msgstr "Inscriptio electronica"
 
-#: models.py:58
+#: models.py:109
 #, fuzzy
 #| msgid "E-mail address"
 msgid "Can view photo"
 msgstr "Inscriptio electronica"
 
-#: models.py:59
+#: models.py:110
 #, fuzzy
 #| msgid "Persons and accounts"
 msgid "Can view persons groups"
 msgstr "Personae et computi"
 
-#: models.py:60
+#: models.py:111
 #, fuzzy
 #| msgid "Stop impersonation"
 msgid "Can view personal details"
 msgstr "Simulandum aliquem finire"
 
-#: models.py:65
+#: models.py:116
 msgid "female"
 msgstr "femininum"
 
-#: models.py:65
+#: models.py:116
 msgid "male"
 msgstr "maskulinum"
 
-#: models.py:73
+#: models.py:124
 msgid "Linked user"
 msgstr ""
 
-#: models.py:75
+#: models.py:126
 #, fuzzy
 #| msgid "Impersonation"
 msgid "Is person active?"
 msgstr "Simulare aliquem"
 
-#: models.py:77
+#: models.py:128
 msgid "First name"
 msgstr "Primus nomen"
 
-#: models.py:78
+#: models.py:129
 msgid "Last name"
 msgstr "Secondus nomen"
 
-#: models.py:80
+#: models.py:131
 msgid "Additional name(s)"
 msgstr "addita nomines"
 
-#: models.py:84 models.py:260
+#: models.py:135 models.py:332
 msgid "Short name"
 msgstr "Breve nomen"
 
-#: models.py:87
+#: models.py:138
 msgid "Street"
 msgstr "Via"
 
-#: models.py:88
+#: models.py:139
 msgid "Street number"
 msgstr "Numerus domini"
 
-#: models.py:89
+#: models.py:140
 msgid "Postal code"
 msgstr "Numerus directorius"
 
-#: models.py:90
+#: models.py:141
 msgid "Place"
 msgstr "Urbs"
 
-#: models.py:92
+#: models.py:143
 msgid "Home phone"
 msgstr "Numerus telephoni domi"
 
-#: models.py:93
+#: models.py:144
 msgid "Mobile phone"
 msgstr "Numerus telephoni mobilis"
 
-#: models.py:97
+#: models.py:148
 msgid "Date of birth"
 msgstr "Dies natalis"
 
-#: models.py:98
+#: models.py:149
 msgid "Sex"
 msgstr "Genus"
 
-#: models.py:100
+#: models.py:151
 msgid "Photo"
 msgstr "Photographia"
 
-#: models.py:105
+#: models.py:155 templates/core/person/full.html:129
 msgid "Guardians / Parents"
 msgstr "Parentes"
 
-#: models.py:112
+#: models.py:162
 msgid "Primary group"
 msgstr ""
 
-#: models.py:115 models.py:346 models.py:370 models.py:455 models.py:643
+#: models.py:165 models.py:423 models.py:447 models.py:532 models.py:720
+#: templates/core/person/full.html:112
 msgid "Description"
 msgstr "Descriptio"
 
-#: models.py:233
+#: models.py:296
 msgid "Title of field"
 msgstr ""
 
-#: models.py:235
+#: models.py:298
 msgid "Type of field"
 msgstr ""
 
-#: models.py:239
+#: models.py:305
 #, fuzzy
 #| msgid "Additional name(s)"
 msgid "Addtitional field for groups"
 msgstr "addita nomines"
 
-#: models.py:240
+#: models.py:306
 #, fuzzy
 #| msgid "Additional name(s)"
 msgid "Addtitional fields for groups"
 msgstr "addita nomines"
 
-#: models.py:252
+#: models.py:318
 msgid "Group"
 msgstr "Grex"
 
-#: models.py:254
+#: models.py:320
 msgid "Can assign child groups to groups"
 msgstr ""
 
-#: models.py:258
+#: models.py:330
 #, fuzzy
 #| msgid "Last name"
 msgid "Long name"
 msgstr "Secondus nomen"
 
-#: models.py:268 templates/core/group_full.html:37
+#: models.py:340 templates/core/group/full.html:65
 msgid "Members"
 msgstr ""
 
-#: models.py:271 templates/core/group_full.html:34
+#: models.py:343 templates/core/group/full.html:62
 msgid "Owners"
 msgstr ""
 
-#: models.py:278
+#: models.py:350 templates/core/group/full.html:54
 msgid "Parent groups"
 msgstr ""
 
-#: models.py:286
+#: models.py:358
 msgid "Type of group"
 msgstr ""
 
-#: models.py:290
-#, fuzzy
-#| msgid "Additional name(s)"
-msgid "Additional fields"
-msgstr "addita nomines"
-
-#: models.py:342
+#: models.py:419
 msgid "User"
 msgstr ""
 
-#: models.py:345 models.py:369 models.py:454
+#: models.py:422 models.py:446 models.py:531
 #: templates/core/announcement/list.html:18
 msgid "Title"
 msgstr "Titulus"
 
-#: models.py:348
+#: models.py:425
 msgid "Application"
 msgstr ""
 
-#: models.py:354
+#: models.py:431
 msgid "Activity"
 msgstr ""
 
-#: models.py:355
+#: models.py:432
 msgid "Activities"
 msgstr ""
 
-#: models.py:361
+#: models.py:438
 msgid "Sender"
 msgstr "Mittens"
 
-#: models.py:366
+#: models.py:443
 msgid "Recipient"
 msgstr ""
 
-#: models.py:371 models.py:624
+#: models.py:448 models.py:701
 msgid "Link"
 msgstr ""
 
-#: models.py:373
+#: models.py:450
 msgid "Read"
 msgstr ""
 
-#: models.py:374
+#: models.py:451
 msgid "Sent"
 msgstr ""
 
-#: models.py:387
+#: models.py:464
 #, fuzzy
 #| msgid "Notifications"
 msgid "Notification"
 msgstr "Nuntii"
 
-#: models.py:388
+#: models.py:465
 msgid "Notifications"
 msgstr "Nuntii"
 
-#: models.py:456
+#: models.py:533
 msgid "Link to detailed view"
 msgstr ""
 
-#: models.py:459
+#: models.py:536
 msgid "Date and time from when to show"
 msgstr ""
 
-#: models.py:462
+#: models.py:539
 msgid "Date and time until when to show"
 msgstr ""
 
-#: models.py:486
+#: models.py:563
 #, fuzzy
 #| msgid "Announcements"
 msgid "Announcement"
 msgstr "Nuntii"
 
-#: models.py:524
+#: models.py:601
 #, fuzzy
 #| msgid "Announcements"
 msgid "Announcement recipient"
 msgstr "Nuntii"
 
-#: models.py:525
+#: models.py:602
 #, fuzzy
 #| msgid "Announcements"
 msgid "Announcement recipients"
 msgstr "Nuntii"
 
-#: models.py:575
+#: models.py:652
 #, fuzzy
 #| msgid "Site title"
 msgid "Widget Title"
 msgstr "Titulus paginae"
 
-#: models.py:576
+#: models.py:653
 msgid "Activate Widget"
 msgstr ""
 
-#: models.py:594
+#: models.py:671
 #, fuzzy
 #| msgid "Dashboard"
 msgid "Dashboard Widget"
 msgstr "Forum"
 
-#: models.py:595
+#: models.py:672
 #, fuzzy
 #| msgid "Dashboard"
 msgid "Dashboard Widgets"
 msgstr "Forum"
 
-#: models.py:601
+#: models.py:678
 msgid "Menu ID"
 msgstr ""
 
-#: models.py:613
+#: models.py:690
 msgid "Custom menu"
 msgstr ""
 
-#: models.py:614
+#: models.py:691
 msgid "Custom menus"
 msgstr ""
 
-#: models.py:621
+#: models.py:698
 msgid "Menu"
 msgstr ""
 
-#: models.py:623
-msgid "Name"
-msgstr "Nomen"
-
-#: models.py:625
+#: models.py:702
 msgid "Icon"
 msgstr "Nota"
 
-#: models.py:631
+#: models.py:708
 msgid "Custom menu item"
 msgstr ""
 
-#: models.py:632
+#: models.py:709
 msgid "Custom menu items"
 msgstr ""
 
-#: models.py:642
+#: models.py:719
 msgid "Title of type"
 msgstr ""
 
-#: models.py:646
+#: models.py:726 templates/core/group/full.html:46
 #, fuzzy
 #| msgid "Group"
 msgid "Group type"
 msgstr "Grex"
 
-#: models.py:647
-#, fuzzy
-#| msgid "Groups"
-msgid "Group types"
-msgstr "Greges"
-
-#: models.py:656
+#: models.py:736
 #, fuzzy
 #| msgid "System status"
 msgid "Can view system status"
 msgstr "Status systemae"
 
-#: models.py:657
+#: models.py:737
 #, fuzzy
 #| msgid "Persons and accounts"
 msgid "Can link persons to accounts"
 msgstr "Personae et computi"
 
-#: models.py:658
+#: models.py:738
 #, fuzzy
 #| msgid "Data management"
 msgid "Can manage data"
 msgstr "Adminstratio datarum"
 
-#: models.py:659
+#: models.py:739
 #, fuzzy
 #| msgid "Stop impersonation"
 msgid "Can impersonate"
 msgstr "Simulandum aliquem finire"
 
-#: models.py:660
+#: models.py:740
 msgid "Can use search"
 msgstr ""
 
-#: models.py:661
+#: models.py:741
 msgid "Can change site preferences"
 msgstr ""
 
-#: models.py:662
+#: models.py:742
 msgid "Can change person preferences"
 msgstr ""
 
-#: models.py:663
+#: models.py:743
 msgid "Can change group preferences"
 msgstr ""
 
-#: preferences.py:27
+#: preferences.py:24
+#, fuzzy
+#| msgid "Notifications"
+msgid "Authentication"
+msgstr "Nuntii"
+
+#: preferences.py:33
 msgid "Site title"
 msgstr "Titulus paginae"
 
-#: preferences.py:36
+#: preferences.py:42
 msgid "Site description"
 msgstr "Descriptio paginae"
 
-#: preferences.py:45
+#: preferences.py:51
 msgid "Primary colour"
 msgstr ""
 
-#: preferences.py:54
+#: preferences.py:60
 msgid "Secondary colour"
 msgstr ""
 
-#: preferences.py:62
+#: preferences.py:68
 #, fuzzy
 #| msgid "Logout"
 msgid "Logo"
 msgstr "nomen retractare"
 
-#: preferences.py:70
+#: preferences.py:76
 msgid "Favicon"
 msgstr ""
 
-#: preferences.py:78
+#: preferences.py:84
 #, fuzzy
 #| msgid "Icon"
 msgid "PWA-Icon"
 msgstr "Nota"
 
-#: preferences.py:87
+#: preferences.py:93
 #, fuzzy
 #| msgid "Last name"
 msgid "Mail out name"
 msgstr "Secondus nomen"
 
-#: preferences.py:96
+#: preferences.py:102
 #, fuzzy
 #| msgid "E-mail address"
 msgid "Mail out address"
 msgstr "Inscriptio electronica"
 
-#: preferences.py:106
+#: preferences.py:112
 msgid "Link to privacy policy"
 msgstr ""
 
-#: preferences.py:116
+#: preferences.py:122
 msgid "Link to imprint"
 msgstr ""
 
-#: preferences.py:126
+#: preferences.py:132
 msgid "Name format for addressing"
 msgstr ""
 
-#: preferences.py:140
+#: preferences.py:146
 msgid "Channels to use for notifications"
 msgstr ""
 
-#: preferences.py:150
+#: preferences.py:156
 msgid "Regular expression to match primary group, e.g. '^Class .*'"
 msgstr ""
 
-#: preferences.py:159
+#: preferences.py:165
 msgid "Field on person to match primary group against"
 msgstr ""
 
-#: preferences.py:171
+#: preferences.py:177
 msgid "Display name of the school"
 msgstr ""
 
-#: preferences.py:180
+#: preferences.py:186
 msgid "Official name of the school, e.g. as given by supervisory authority"
 msgstr "Officialis nomen scolae, e. g."
 
-#: settings.py:276
+#: preferences.py:194
+msgid "Enabled custom authentication backends"
+msgstr ""
+
+#: settings.py:300
 msgid "English"
 msgstr "Britannicus"
 
-#: settings.py:277
+#: settings.py:301
 msgid "German"
 msgstr "Germanus"
 
-#: settings.py:278
+#: settings.py:302
 msgid "French"
 msgstr ""
 
-#: templates/403.html:10 templates/404.html:10 templates/500.html:10
+#: settings.py:303
+msgid "Norwegian (bokmål)"
+msgstr ""
+
+#: tables.py:19 templates/core/announcement/list.html:36
+#: templates/core/group/full.html:23 templates/core/person/full.html:22
+msgid "Edit"
+msgstr ""
+
+#: tables.py:21 templates/core/announcement/list.html:22
+#, fuzzy
+#| msgid "Notifications"
+msgid "Actions"
+msgstr "Nuntii"
+
+#: tables.py:56 tables.py:57 tables.py:71
+#: templates/core/announcement/list.html:42 templates/core/group/full.html:30
+#: templates/core/pages/delete.html:22 templates/core/person/full.html:29
+msgid "Delete"
+msgstr ""
+
+#: templates/403.html:14 templates/404.html:10 templates/500.html:10
 msgid "Error"
 msgstr ""
 
-#: templates/403.html:10
+#: templates/403.html:14
 msgid ""
 "You are not allowed to access the requested page or\n"
 "          object."
 msgstr ""
 
-#: templates/403.html:13 templates/404.html:17
+#: templates/403.html:19 templates/404.html:17
 msgid ""
 "\n"
-"            If you think this is an error in AlekSIS, please contact your "
-"site\n"
+"            If you think this is an error in AlekSIS, please contact your site\n"
 "            administrators:\n"
 "          "
 msgstr ""
@@ -723,8 +809,7 @@ msgstr ""
 #: templates/500.html:13
 msgid ""
 "\n"
-"            Your site administrators will automatically be notified about "
-"this\n"
+"            Your site administrators will automatically be notified about this\n"
 "            error. You can also contact them directly:\n"
 "          "
 msgstr ""
@@ -738,80 +823,22 @@ msgstr ""
 #: templates/503.html:13
 msgid ""
 "\n"
-"            This page is currently unavailable. If this error persists, "
-"contact your site administrators:\n"
+"            This page is currently unavailable. If this error persists, contact your site administrators:\n"
 "          "
 msgstr ""
 
-#: templates/core/about.html:6 templates/core/about.html:15
-msgid "About AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:7
-msgid "AlekSIS – The Free School Information System"
-msgstr ""
-
-#: templates/core/about.html:17
-msgid ""
-"\n"
-"              This platform is powered by AlekSIS, a web-based school "
-"information system (SIS) which can be used\n"
-"              to manage and/or publish organisational artifacts of "
-"educational institutions. AlekSIS is free software and\n"
-"              can be used by anyone.\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:25
-msgid "Website of AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:26
-msgid "Source code"
-msgstr ""
-
-#: templates/core/about.html:35
+#: templates/core/additional_field/edit.html:6
+#: templates/core/additional_field/edit.html:7
 #, fuzzy
-#| msgid "Edit school information"
-msgid "Licence information"
-msgstr "Muta informationes scolae"
-
-#: templates/core/about.html:37
-msgid ""
-"\n"
-"              The core and the official apps of AlekSIS are licenced under "
-"the EUPL, version 1.2 or later. For licence\n"
-"              information from third-party apps, if installed, refer to the "
-"respective components below. The\n"
-"              licences are marked like this:\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:45
-msgid "Free/Open Source Licence"
-msgstr ""
-
-#: templates/core/about.html:46
-msgid "Other Licence"
-msgstr ""
-
-#: templates/core/about.html:50
-msgid "Full licence text"
-msgstr ""
+#| msgid "Additional name(s)"
+msgid "Edit additional field"
+msgstr "addita nomines"
 
-#: templates/core/about.html:51
+#: templates/core/additional_field/list.html:14
 #, fuzzy
-#| msgid "Edit school information"
-msgid "More information about the EUPL"
-msgstr "Muta informationes scolae"
-
-#: templates/core/about.html:90
-#, python-format
-msgid ""
-"\n"
-"                    This app is licenced under %(licence)s.\n"
-"                  "
-msgstr ""
+#| msgid "Additional name(s)"
+msgid "Create additional field"
+msgstr "addita nomines"
 
 #: templates/core/announcement/form.html:10
 #: templates/core/announcement/form.html:17
@@ -851,167 +878,140 @@ msgstr ""
 msgid "Recipients"
 msgstr ""
 
-#: templates/core/announcement/list.html:22
-#, fuzzy
-#| msgid "Notifications"
-msgid "Actions"
-msgstr "Nuntii"
-
-#: templates/core/announcement/list.html:36 templates/core/group_full.html:22
-#: templates/core/person_full.html:21
-msgid "Edit"
-msgstr ""
-
-#: templates/core/announcement/list.html:42
-msgid "Delete"
-msgstr ""
-
 #: templates/core/announcement/list.html:50
 #, fuzzy
 #| msgid "Write your announcement:"
 msgid "There are no announcements."
 msgstr "Scribe nuntium:"
 
-#: templates/core/announcements.html:9 templates/core/announcements.html:36
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:13
-#, python-format
-msgid ""
-"\n"
-"              Valid from %(from)s until %(until)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:40
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s – %(until)s\n"
-"            "
-msgstr ""
-
 #: templates/core/base.html:54
 msgid "Logged in as"
 msgstr ""
 
-#: templates/core/base.html:76 templates/search/search.html:7
-#: templates/search/search.html:22
-msgid "Search"
-msgstr ""
-
-#: templates/core/base.html:148
+#: templates/core/base.html:147
 msgid "About AlekSIS — The Free School Information System"
 msgstr ""
 
-#: templates/core/base.html:156
+#: templates/core/base.html:155
 msgid "Impress"
 msgstr ""
 
-#: templates/core/base.html:164
+#: templates/core/base.html:163
 msgid "Privacy Policy"
 msgstr ""
 
-#: templates/core/base_print.html:62
+#: templates/core/base_print.html:64
 msgid "Powered by AlekSIS"
 msgstr ""
 
-#: templates/core/edit_group.html:6 templates/core/edit_group.html:7
-msgid "Edit group"
-msgstr ""
-
-#: templates/core/edit_person.html:8 templates/core/edit_person.html:9
-msgid "Edit person"
-msgstr ""
-
-#: templates/core/group_full.html:28 templates/core/person_full.html:28
-msgid "Change preferences"
-msgstr ""
-
-#: templates/core/groups.html:14
-msgid "Create group"
-msgstr ""
-
-#: templates/core/groups_child_groups.html:18
+#: templates/core/group/child_groups.html:18
 msgid ""
 "\n"
-"          You can use this to assign child groups to groups. Please use the "
-"filters below to select groups you want to\n"
+"          You can use this to assign child groups to groups. Please use the filters below to select groups you want to\n"
 "          change and click \"Next\".\n"
 "        "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:31
+#: templates/core/group/child_groups.html:31
 msgid "Update selection"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:35
+#: templates/core/group/child_groups.html:35
 msgid "Clear all filters"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:39
+#: templates/core/group/child_groups.html:39
 msgid "Currently selected groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:52
+#: templates/core/group/child_groups.html:52
 msgid "Start assigning child groups for this groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:61
+#: templates/core/group/child_groups.html:61
 msgid ""
 "\n"
 "            Please select some groups in order to go on with assigning.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:72
+#: templates/core/group/child_groups.html:72
 msgid "Current group:"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:78
+#: templates/core/group/child_groups.html:78
 msgid "Please be careful!"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:79
+#: templates/core/group/child_groups.html:79
 msgid ""
 "\n"
-"            If you click \"Back\" or \"Next\" the current group assignments "
-"are not saved.\n"
-"            If you click \"Save\", you will overwrite all existing child "
-"group relations for this group with what you\n"
+"            If you click \"Back\" or \"Next\" the current group assignments are not saved.\n"
+"            If you click \"Save\", you will overwrite all existing child group relations for this group with what you\n"
 "            selected on this page.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:93
-#: templates/core/groups_child_groups.html:128
+#: templates/core/group/child_groups.html:93
+#: templates/core/group/child_groups.html:128
 #: templates/two_factor/_wizard_actions.html:15
 #: templates/two_factor/_wizard_actions.html:20
 msgid "Back"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:99
-#: templates/core/groups_child_groups.html:134
+#: templates/core/group/child_groups.html:99
+#: templates/core/group/child_groups.html:134
 #: templates/two_factor/_wizard_actions.html:26
 msgid "Next"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:106
-#: templates/core/groups_child_groups.html:141
-#: templates/core/save_button.html:3
+#: templates/core/group/child_groups.html:106
+#: templates/core/group/child_groups.html:141
+#: templates/core/partials/save_button.html:3
 msgid "Save"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:112
-#: templates/core/groups_child_groups.html:147
+#: templates/core/group/child_groups.html:112
+#: templates/core/group/child_groups.html:147
 msgid "Save and next"
 msgstr ""
 
+#: templates/core/group/edit.html:6 templates/core/group/edit.html:7
+msgid "Edit group"
+msgstr ""
+
+#: templates/core/group/full.html:37 templates/core/person/full.html:36
+msgid "Change preferences"
+msgstr ""
+
+#: templates/core/group/list.html:14
+msgid "Create group"
+msgstr ""
+
+#: templates/core/group/list.html:17
+msgid "Filter groups"
+msgstr ""
+
+#: templates/core/group/list.html:24 templates/core/person/list.html:28
+msgid "Clear"
+msgstr ""
+
+#: templates/core/group/list.html:28
+msgid "Selected groups"
+msgstr ""
+
+#: templates/core/group_type/edit.html:6 templates/core/group_type/edit.html:7
+#, fuzzy
+#| msgid "Group"
+msgid "Edit group type"
+msgstr "Grex"
+
+#: templates/core/group_type/list.html:14
+#, fuzzy
+#| msgid "Group"
+msgid "Create group type"
+msgstr "Grex"
+
 #: templates/core/index.html:4
 msgid "Home"
 msgstr ""
@@ -1040,109 +1040,346 @@ msgstr "Muta informationes scolae"
 msgid "No notifications available yet."
 msgstr ""
 
-#: templates/core/no_person.html:12
+#: templates/core/pages/about.html:6 templates/core/pages/about.html:15
+msgid "About AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:7
+msgid "AlekSIS – The Free School Information System"
+msgstr ""
+
+#: templates/core/pages/about.html:17
 msgid ""
 "\n"
-"            Your administrator account is not linked to any person. "
-"Therefore,\n"
-"            a dummy person has been linked to your account.\n"
-"          "
+"              This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used\n"
+"              to manage and/or publish organisational artifacts of educational institutions. AlekSIS is free software and\n"
+"              can be used by anyone.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/about.html:25
+msgid "Website of AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:26
+msgid "Source code"
 msgstr ""
 
-#: templates/core/no_person.html:19
+#: templates/core/pages/about.html:35
+#, fuzzy
+#| msgid "Edit school information"
+msgid "Licence information"
+msgstr "Muta informationes scolae"
+
+#: templates/core/pages/about.html:37
 msgid ""
 "\n"
-"            Your user account is not linked to a person. This means you\n"
-"            cannot access any school-related information. Please contact\n"
-"            the managers of AlekSIS at your school.\n"
-"          "
+"              The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence\n"
+"              information from third-party apps, if installed, refer to the respective components below. The\n"
+"              licences are marked like this:\n"
+"            "
 msgstr ""
 
-#: templates/core/person_full.html:34
-msgid "Contact details"
+#: templates/core/pages/about.html:45
+msgid "Free/Open Source Licence"
 msgstr ""
 
-#: templates/core/persons_accounts.html:7
-#: templates/core/persons_accounts.html:9
+#: templates/core/pages/about.html:46
+msgid "Other Licence"
+msgstr ""
+
+#: templates/core/pages/about.html:50
+msgid "Full licence text"
+msgstr ""
+
+#: templates/core/pages/about.html:51
 #, fuzzy
-#| msgid "Persons and accounts"
-msgid "Link persons to accounts"
-msgstr "Personae et computi"
+#| msgid "Edit school information"
+msgid "More information about the EUPL"
+msgstr "Muta informationes scolae"
 
-#: templates/core/persons_accounts.html:16
+#: templates/core/pages/about.html:90
+#, python-format
 msgid ""
 "\n"
-"        You can use this form to assign user accounts to persons. Use the\n"
-"        dropdowns to select existing accounts; use the text fields to create "
-"new\n"
-"        accounts on-the-fly. The latter will create a new account with the\n"
-"        entered username and copy all other details from the person.\n"
-"      "
+"                    This app is licenced under %(licence)s.\n"
+"                  "
 msgstr ""
 
-#: templates/core/persons_accounts.html:31
-#: templates/core/persons_accounts.html:55
-msgid "Update"
+#: templates/core/pages/delete.html:6
+#, python-format
+msgid "Delete %(object_name)s"
 msgstr ""
 
-#: templates/core/persons_accounts.html:37
-msgid "Existing account"
+#: templates/core/pages/delete.html:13
+#, python-format
+msgid ""
+"\n"
+"      Do you really want to delete the %(object_name)s \"%(object)s\"?\n"
+"    "
 msgstr ""
 
-#: templates/core/persons_accounts.html:38
-msgid "New account"
+#: templates/core/pages/offline.html:6
+msgid ""
+"No internet\n"
+"    connection."
 msgstr ""
 
-#: templates/core/system_status.html:12
+#: templates/core/pages/offline.html:10
+msgid ""
+"\n"
+"      There was an error accessing this page. You probably don't have an internet connection. Check to see if your WiFi\n"
+"      or mobile data is turned on and try again. If you think you are connected, please contact the system\n"
+"      administrators:\n"
+"    "
+msgstr ""
+
+#: templates/core/pages/progress.html:27
+msgid ""
+"\n"
+"              Without activated JavaScript the progress status can't be updated.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/progress.html:47
+#: templates/two_factor/core/otp_required.html:19
+msgid "Go back"
+msgstr ""
+
+#: templates/core/pages/system_status.html:12
 #, fuzzy
 #| msgid "System status"
 msgid "System checks"
 msgstr "Status systemae"
 
-#: templates/core/system_status.html:21
+#: templates/core/pages/system_status.html:21
 msgid "Maintenance mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:23
+#: templates/core/pages/system_status.html:23
 msgid ""
 "\n"
-"                Only admin and visitors from internal IPs can access "
-"thesite.\n"
+"                Only admin and visitors from internal IPs can access thesite.\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:34
+#: templates/core/pages/system_status.html:34
 msgid "Maintenance mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:35
+#: templates/core/pages/system_status.html:35
 msgid "Everyone can access the site."
 msgstr ""
 
-#: templates/core/system_status.html:45
+#: templates/core/pages/system_status.html:45
 msgid "Debug mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:47
+#: templates/core/pages/system_status.html:47
 msgid ""
 "\n"
-"                The web server throws back debug information on errors. Do "
-"not use in production!\n"
+"                The web server throws back debug information on errors. Do not use in production!\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:54
+#: templates/core/pages/system_status.html:54
 msgid "Debug mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:56
+#: templates/core/pages/system_status.html:56
 msgid ""
 "\n"
-"                Debug mode is disabled. Default error pages are displayed on "
-"errors.\n"
+"                Debug mode is disabled. Default error pages are displayed on errors.\n"
 "              "
 msgstr ""
 
+#: templates/core/pages/system_status.html:69
+#, fuzzy
+#| msgid "System status"
+msgid "System health checks"
+msgstr "Status systemae"
+
+#: templates/core/pages/system_status.html:75
+msgid "Service"
+msgstr ""
+
+#: templates/core/pages/system_status.html:76
+#: templates/core/pages/system_status.html:115
+#, fuzzy
+#| msgid "System status"
+msgid "Status"
+msgstr "Status systemae"
+
+#: templates/core/pages/system_status.html:77
+msgid "Time taken"
+msgstr ""
+
+#: templates/core/pages/system_status.html:96
+msgid "seconds"
+msgstr ""
+
+#: templates/core/pages/system_status.html:107
+msgid "Celery task results"
+msgstr ""
+
+#: templates/core/pages/system_status.html:112
+msgid "Task"
+msgstr ""
+
+#: templates/core/pages/system_status.html:113
+msgid "ID"
+msgstr ""
+
+#: templates/core/pages/system_status.html:114
+#, fuzzy
+#| msgid "Date"
+msgid "Date done"
+msgstr "dies"
+
+#: templates/core/partials/announcements.html:9
+#: templates/core/partials/announcements.html:36
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:13
+#, python-format
+msgid ""
+"\n"
+"              Valid from %(from)s until %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:40
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s – %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:10
+#, python-format
+msgid ""
+"\n"
+"              Created by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:14
+#: templates/core/partials/crud_events.html:22
+#: templates/core/partials/crud_events.html:26
+#, python-format
+msgid ""
+"\n"
+"              Updated by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:18
+#, python-format
+msgid ""
+"\n"
+"              Deleted by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/language_form.html:16
+msgid "Language"
+msgstr ""
+
+#: templates/core/partials/language_form.html:28
+msgid "Select language"
+msgstr ""
+
+#: templates/core/partials/no_person.html:12
+msgid ""
+"\n"
+"            Your administrator account is not linked to any person. Therefore,\n"
+"            a dummy person has been linked to your account.\n"
+"          "
+msgstr ""
+
+#: templates/core/partials/no_person.html:19
+msgid ""
+"\n"
+"            Your user account is not linked to a person. This means you\n"
+"            cannot access any school-related information. Please contact\n"
+"            the managers of AlekSIS at your school.\n"
+"          "
+msgstr ""
+
+#: templates/core/person/accounts.html:7 templates/core/person/accounts.html:9
+#, fuzzy
+#| msgid "Persons and accounts"
+msgid "Link persons to accounts"
+msgstr "Personae et computi"
+
+#: templates/core/person/accounts.html:16
+msgid ""
+"\n"
+"        You can use this form to assign user accounts to persons. Use the\n"
+"        dropdowns to select existing accounts; use the text fields to create new\n"
+"        accounts on-the-fly. The latter will create a new account with the\n"
+"        entered username and copy all other details from the person.\n"
+"      "
+msgstr ""
+
+#: templates/core/person/accounts.html:31
+#: templates/core/person/accounts.html:55
+msgid "Update"
+msgstr ""
+
+#: templates/core/person/accounts.html:37
+msgid "Existing account"
+msgstr ""
+
+#: templates/core/person/accounts.html:38
+msgid "New account"
+msgstr ""
+
+#: templates/core/person/edit.html:11 templates/core/person/edit.html:12
+msgid "Edit person"
+msgstr ""
+
+#: templates/core/person/full.html:42
+msgid "Contact details"
+msgstr ""
+
+#: templates/core/person/full.html:122
+msgid "Children"
+msgstr ""
+
+#: templates/core/person/list.html:17
+#, fuzzy
+#| msgid "Stop impersonation"
+msgid "Create person"
+msgstr "Simulandum aliquem finire"
+
+#: templates/core/person/list.html:21
+msgid "Filter persons"
+msgstr ""
+
+#: templates/core/person/list.html:32
+msgid "Selected persons"
+msgstr ""
+
+#: templates/core/school_term/create.html:6
+#: templates/core/school_term/create.html:7
+#: templates/core/school_term/list.html:14
+#, fuzzy
+#| msgid "Edit school term"
+msgid "Create school term"
+msgstr "Muta anum scolae"
+
+#: templates/core/school_term/edit.html:6
+#: templates/core/school_term/edit.html:7
+msgid "Edit school term"
+msgstr "Muta anum scolae"
+
 #: templates/dynamic_preferences/form.html:9
 msgid "Site preferences"
 msgstr ""
@@ -1170,23 +1407,6 @@ msgstr ""
 msgid "Impersonate user"
 msgstr "Simulare aliquem"
 
-#: templates/offline.html:6
-msgid ""
-"No internet\n"
-"    connection."
-msgstr ""
-
-#: templates/offline.html:10
-msgid ""
-"\n"
-"      There was an error accessing this page. You probably don't have an "
-"internet connection. Check to see if your WiFi\n"
-"      or mobile data is turned on and try again. If you think you are "
-"connected, please contact the system\n"
-"      administrators:\n"
-"    "
-msgstr ""
-
 #: templates/search/search.html:8
 msgid "Global Search"
 msgstr ""
@@ -1213,30 +1433,48 @@ msgstr ""
 msgid "New notification for"
 msgstr "Nuntius"
 
-#: templates/templated_email/notification.email:7
-msgid "Dear"
-msgstr ""
+#: templates/templated_email/notification.email:6
+#: templates/templated_email/notification.email:27
+#, fuzzy, python-format
+#| msgid "Notifications"
+msgid "Dear %(notification_user)s,"
+msgstr "Nuntii"
 
 #: templates/templated_email/notification.email:8
+#: templates/templated_email/notification.email:29
+#, fuzzy
+#| msgid "Notification"
 msgid "we got a new notification for you:"
-msgstr ""
+msgstr "Nuntius"
 
-#: templates/templated_email/notification.email:12
+#: templates/templated_email/notification.email:15
+#: templates/templated_email/notification.email:35
 #, fuzzy
 #| msgid "Edit school information"
 msgid "More information"
 msgstr "Muta informationes scolae"
 
-#: templates/templated_email/notification.email:16
+#: templates/templated_email/notification.email:18
 #, python-format
 msgid ""
 "\n"
-"    <p>By %(trans_sender)s at %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Your AlekSIS team</i>\n"
+"        Sent by %(trans_sender)s at %(trans_created_at)s\n"
 "    "
 msgstr ""
 
+#: templates/templated_email/notification.email:22
+#: templates/templated_email/notification.email:46
+msgid "Your AlekSIS team"
+msgstr ""
+
+#: templates/templated_email/notification.email:40
+#, python-format
+msgid ""
+"\n"
+"            Sent by %(trans_sender)s at %(trans_created_at)s\n"
+"        "
+msgstr ""
+
 #: templates/two_factor/_base_focus.html:6
 #: templates/two_factor/core/otp_required.html:22
 #: templates/two_factor/core/setup.html:5
@@ -1259,10 +1497,8 @@ msgid ""
 "\n"
 "        Backup tokens can be used when your primary and backup\n"
 "        phone numbers aren't available. The backup tokens below can be used\n"
-"        for login verification. If you've used up all your backup tokens, "
-"you\n"
-"        can generate a new set of backup tokens. Only the backup tokens "
-"shown\n"
+"        for login verification. If you've used up all your backup tokens, you\n"
+"        can generate a new set of backup tokens. Only the backup tokens shown\n"
 "        below will be valid.\n"
 "      "
 msgstr ""
@@ -1287,52 +1523,58 @@ msgid "Generate Tokens"
 msgstr ""
 
 #: templates/two_factor/core/login.html:16
-msgid ""
-"You have no permission to view this page. Please login with an other account."
+msgid "You have no permission to view this page. Please login with an other account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:25
+#: templates/two_factor/core/login.html:24
 msgid "Please login to see this page."
 msgstr ""
 
-#: templates/two_factor/core/login.html:28
+#: templates/two_factor/core/login.html:30
+msgid "Login with username and password"
+msgstr ""
+
+#: templates/two_factor/core/login.html:40
 msgid ""
 "We are calling your phone right now, please enter the\n"
 "              digits you hear."
 msgstr ""
 
-#: templates/two_factor/core/login.html:31
+#: templates/two_factor/core/login.html:43
 msgid ""
 "We sent you a text message, please enter the tokens we\n"
 "              sent."
 msgstr ""
 
-#: templates/two_factor/core/login.html:34
+#: templates/two_factor/core/login.html:46
 msgid ""
 "Please enter the tokens generated by your token\n"
 "              generator."
 msgstr ""
 
-#: templates/two_factor/core/login.html:38
+#: templates/two_factor/core/login.html:50
 msgid ""
 "Use this form for entering backup tokens for logging in.\n"
-"            These tokens have been generated for you to print and keep safe. "
-"Please\n"
+"            These tokens have been generated for you to print and keep safe. Please\n"
 "            enter one of these backup tokens to login to your account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:56
+#: templates/two_factor/core/login.html:68
 msgid "Or, alternatively, use one of your backup phones:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:66
+#: templates/two_factor/core/login.html:78
 msgid "As a last resort, you can use a backup token:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:69
+#: templates/two_factor/core/login.html:81
 msgid "Use Backup Token"
 msgstr ""
 
+#: templates/two_factor/core/login.html:93
+msgid "Use alternative login options"
+msgstr ""
+
 #: templates/two_factor/core/otp_required.html:9
 msgid "Permission Denied"
 msgstr ""
@@ -1340,8 +1582,7 @@ msgstr ""
 #: templates/two_factor/core/otp_required.html:10
 msgid ""
 "The page you requested, enforces users to verify using\n"
-"          two-factor authentication for security reasons. You need to enable "
-"these\n"
+"          two-factor authentication for security reasons. You need to enable these\n"
 "          security features in order to access this page."
 msgstr ""
 
@@ -1352,10 +1593,6 @@ msgid ""
 "          security."
 msgstr ""
 
-#: templates/two_factor/core/otp_required.html:19
-msgid "Go back"
-msgstr ""
-
 #: templates/two_factor/core/phone_register.html:5
 #: templates/two_factor/core/phone_register.html:9
 msgid "Add Backup Phone"
@@ -1418,8 +1655,7 @@ msgstr ""
 #: templates/two_factor/core/setup.html:50
 msgid ""
 "\n"
-"            We are calling your phone right now, please enter the digits you "
-"hear.\n"
+"            We are calling your phone right now, please enter the digits you hear.\n"
 "          "
 msgstr ""
 
@@ -1433,12 +1669,9 @@ msgstr ""
 #: templates/two_factor/core/setup.html:63
 msgid ""
 "\n"
-"          We've encountered an issue with the selected authentication "
-"method. Please\n"
-"          go back and verify that you entered your information correctly, "
-"try\n"
-"          again, or use a different authentication method instead. If the "
-"issue\n"
+"          We've encountered an issue with the selected authentication method. Please\n"
+"          go back and verify that you entered your information correctly, try\n"
+"          again, or use a different authentication method instead. If the issue\n"
 "          persists, contact the site administrator.\n"
 "        "
 msgstr ""
@@ -1460,8 +1693,7 @@ msgstr ""
 #: templates/two_factor/core/setup_complete.html:14
 msgid ""
 "\n"
-"        Congratulations, you've successfully enabled two-factor "
-"authentication.\n"
+"        Congratulations, you've successfully enabled two-factor authentication.\n"
 "      "
 msgstr ""
 
@@ -1479,8 +1711,7 @@ msgstr ""
 msgid ""
 "\n"
 "          However, it might happen that you don't have access to\n"
-"          your primary token device. To enable account recovery, generate "
-"backup codes\n"
+"          your primary token device. To enable account recovery, generate backup codes\n"
 "          or add a phone number.\n"
 "        "
 msgstr ""
@@ -1498,9 +1729,7 @@ msgid "Disable Two-Factor Authentication"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:12
-msgid ""
-"You are about to disable two-factor authentication. This weakens your "
-"account security, are you sure?"
+msgid "You are about to disable two-factor authentication. This weakens your account security, are you sure?"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:26
@@ -1587,34 +1816,61 @@ msgstr ""
 msgid "SMS"
 msgstr ""
 
-#: views.py:212
+#: views.py:122
+msgid "The school term has been created."
+msgstr ""
+
+#: views.py:133
+msgid "The school term has been saved."
+msgstr ""
+
+#: views.py:273
 msgid "The child groups were successfully saved."
 msgstr ""
 
-#: views.py:240
+#: views.py:309
 msgid "The person has been saved."
 msgstr ""
 
-#: views.py:276
+#: views.py:346
 msgid "The group has been saved."
 msgstr ""
 
-#: views.py:348
+#: views.py:434
 msgid "The announcement has been saved."
 msgstr ""
 
-#: views.py:364
+#: views.py:450
 msgid "The announcement has been deleted."
 msgstr ""
 
-#: views.py:435
+#: views.py:521
 msgid "The preferences have been saved successfully."
 msgstr ""
 
-#, fuzzy
-#~| msgid "Short name"
-#~ msgid "School name"
-#~ msgstr "Breve nomen"
+#: views.py:544
+msgid "The person has been deleted."
+msgstr ""
+
+#: views.py:557
+msgid "The group has been deleted."
+msgstr ""
+
+#: views.py:588
+msgid "The additional_field has been saved."
+msgstr ""
+
+#: views.py:622
+msgid "The additional field has been deleted."
+msgstr ""
+
+#: views.py:646
+msgid "The group type has been saved."
+msgstr ""
+
+#: views.py:676
+msgid "The group type has been deleted."
+msgstr ""
 
 #~ msgid "School logo"
 #~ msgstr "Imago scolae"
@@ -1625,9 +1881,6 @@ msgstr ""
 #~ msgid "Edit school information"
 #~ msgstr "Muta informationes scolae"
 
-#~ msgid "Edit school term"
-#~ msgstr "Muta anum scolae"
-
 #~ msgid "Official name"
 #~ msgstr "Officialis nomen"
 
@@ -1636,9 +1889,3 @@ msgstr ""
 
 #~ msgid "Schools"
 #~ msgstr "Scholae"
-
-#~ msgid "School term"
-#~ msgstr "Anus scolae"
-
-#~ msgid "School terms"
-#~ msgstr "ani scolae"
diff --git a/aleksis/core/locale/la/LC_MESSAGES/djangojs.po b/aleksis/core/locale/la/LC_MESSAGES/djangojs.po
index 21309c0096e0f1ec402dfa7c4e2f8604b96e2466..9dbef6e6f74f842b0e8f25e389edf1a852cd8d99 100644
--- a/aleksis/core/locale/la/LC_MESSAGES/djangojs.po
+++ b/aleksis/core/locale/la/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-04-28 13:31+0000\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/aleksis/core/locale/nb_NO/LC_MESSAGES/django.po b/aleksis/core/locale/nb_NO/LC_MESSAGES/django.po
index 3e169fa0130f90c88bfaba22972f8bf0a7163a7f..6cfc5ee7e1a2e39ea35727fd66d5bd22d8e8b235 100644
--- a/aleksis/core/locale/nb_NO/LC_MESSAGES/django.po
+++ b/aleksis/core/locale/nb_NO/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: AlekSIS (School Information System) 0.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-04 15:39+0200\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,6 +17,20 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+#: filters.py:37 templates/core/base.html:77 templates/core/group/list.html:20
+#: templates/core/person/list.html:24 templates/search/search.html:7
+#: templates/search/search.html:22
+msgid "Search"
+msgstr ""
+
+#: filters.py:53
+msgid "Search by name"
+msgstr ""
+
+#: filters.py:65
+msgid "Search by contact details"
+msgstr ""
+
 #: forms.py:46
 msgid "You cannot set a new username when also selecting an existing user."
 msgstr ""
@@ -41,64 +55,71 @@ msgstr ""
 msgid "Advanced personal data"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "New user"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "Create a new account"
 msgstr ""
 
-#: forms.py:128
+#: forms.py:126 models.py:91
+msgid "School term"
+msgstr ""
+
+#: forms.py:127
 msgid "Common data"
 msgstr ""
 
-#: forms.py:129 forms.py:169 menus.py:141 models.py:54
-#: templates/core/persons.html:8 templates/core/persons.html:9
+#: forms.py:128 forms.py:170 menus.py:152 models.py:105
+#: templates/core/person/list.html:8 templates/core/person/list.html:9
 msgid "Persons"
 msgstr ""
 
-#: forms.py:162 forms.py:165 models.py:31
+#: forms.py:129
+msgid "Additional data"
+msgstr ""
+
+#: forms.py:163 forms.py:166 models.py:35
 msgid "Date"
 msgstr ""
 
-#: forms.py:163 forms.py:166 models.py:39
+#: forms.py:164 forms.py:167 models.py:43
 msgid "Time"
 msgstr ""
 
-#: forms.py:171 menus.py:149 models.py:253 templates/core/groups.html:8
-#: templates/core/groups.html:9 templates/core/person_full.html:106
+#: forms.py:172 menus.py:160 models.py:319 templates/core/group/list.html:8
+#: templates/core/group/list.html:9 templates/core/person/full.html:136
 msgid "Groups"
 msgstr ""
 
-#: forms.py:175
+#: forms.py:176
 msgid "From when until when should the announcement be displayed?"
 msgstr ""
 
-#: forms.py:178
+#: forms.py:179
 msgid "Who should see the announcement?"
 msgstr ""
 
-#: forms.py:179
+#: forms.py:180
 msgid "Write your announcement:"
 msgstr ""
 
-#: forms.py:216
-msgid ""
-"You are not allowed to create announcements which are only valid in the past."
+#: forms.py:219
+msgid "You are not allowed to create announcements which are only valid in the past."
 msgstr ""
 
-#: forms.py:220
+#: forms.py:223
 msgid "The from date and time must be earlier then the until date and time."
 msgstr ""
 
-#: forms.py:229
+#: forms.py:232
 msgid "You need at least one recipient."
 msgstr ""
 
 #: menus.py:7 templates/two_factor/core/login.html:6
 #: templates/two_factor/core/login.html:10
-#: templates/two_factor/core/login.html:73
+#: templates/two_factor/core/login.html:86
 msgid "Login"
 msgstr ""
 
@@ -134,502 +155,556 @@ msgstr ""
 msgid "Admin"
 msgstr ""
 
-#: menus.py:75 models.py:487 templates/core/announcement/list.html:7
+#: menus.py:75 models.py:564 templates/core/announcement/list.html:7
 #: templates/core/announcement/list.html:8
 msgid "Announcements"
 msgstr ""
 
-#: menus.py:86 templates/core/data_management.html:6
-#: templates/core/data_management.html:7
+#: menus.py:86 models.py:92 templates/core/school_term/list.html:8
+#: templates/core/school_term/list.html:9
+msgid "School terms"
+msgstr ""
+
+#: menus.py:97 templates/core/management/data_management.html:6
+#: templates/core/management/data_management.html:7
 msgid "Data management"
 msgstr ""
 
-#: menus.py:94 templates/core/system_status.html:5
-#: templates/core/system_status.html:7
+#: menus.py:105 templates/core/pages/system_status.html:5
+#: templates/core/pages/system_status.html:7
 msgid "System status"
 msgstr ""
 
-#: menus.py:105
+#: menus.py:116
 msgid "Impersonation"
 msgstr ""
 
-#: menus.py:113
+#: menus.py:124
 msgid "Configuration"
 msgstr ""
 
-#: menus.py:124
+#: menus.py:135
 msgid "Backend Admin"
 msgstr ""
 
-#: menus.py:132
+#: menus.py:143
 msgid "People"
 msgstr ""
 
-#: menus.py:157
+#: menus.py:168 models.py:727 templates/core/group_type/list.html:8
+#: templates/core/group_type/list.html:9
+msgid "Group types"
+msgstr ""
+
+#: menus.py:179
 msgid "Persons and accounts"
 msgstr ""
 
-#: menus.py:168
+#: menus.py:190
 msgid "Groups and child groups"
 msgstr ""
 
-#: menus.py:183 templates/core/groups_child_groups.html:7
-#: templates/core/groups_child_groups.html:9
+#: menus.py:201 models.py:363 templates/core/additional_field/list.html:8
+#: templates/core/additional_field/list.html:9
+msgid "Additional fields"
+msgstr ""
+
+#: menus.py:216 templates/core/group/child_groups.html:7
+#: templates/core/group/child_groups.html:9
 msgid "Assign child groups to groups"
 msgstr ""
 
-#: models.py:29
+#: mixins.py:406
+msgid "Linked school term"
+msgstr ""
+
+#: models.py:33
 msgid "Boolean (Yes/No)"
 msgstr ""
 
-#: models.py:30
+#: models.py:34
 msgid "Text (one line)"
 msgstr ""
 
-#: models.py:32
+#: models.py:36
 msgid "Date and time"
 msgstr ""
 
-#: models.py:33
+#: models.py:37
 msgid "Decimal number"
 msgstr ""
 
-#: models.py:34 models.py:95
+#: models.py:38 models.py:146
 msgid "E-mail address"
 msgstr ""
 
-#: models.py:35
+#: models.py:39
 msgid "Integer"
 msgstr ""
 
-#: models.py:36
+#: models.py:40
 msgid "IP address"
 msgstr ""
 
-#: models.py:37
+#: models.py:41
 msgid "Boolean or empty (Yes/No/Neither)"
 msgstr ""
 
-#: models.py:38
+#: models.py:42
 msgid "Text (multi-line)"
 msgstr ""
 
-#: models.py:40
+#: models.py:44
 msgid "URL / Link"
 msgstr ""
 
-#: models.py:53 templates/core/persons_accounts.html:36
+#: models.py:56 models.py:700
+msgid "Name"
+msgstr ""
+
+#: models.py:58
+msgid "Start date"
+msgstr ""
+
+#: models.py:59
+msgid "End date"
+msgstr ""
+
+#: models.py:77
+msgid "The start date must be earlier than the end date."
+msgstr ""
+
+#: models.py:84
+msgid "There is already a school term for this time or a part of this time."
+msgstr ""
+
+#: models.py:104 templates/core/person/accounts.html:36
 msgid "Person"
 msgstr ""
 
-#: models.py:56
+#: models.py:107
 msgid "Can view address"
 msgstr ""
 
-#: models.py:57
+#: models.py:108
 msgid "Can view contact details"
 msgstr ""
 
-#: models.py:58
+#: models.py:109
 msgid "Can view photo"
 msgstr ""
 
-#: models.py:59
+#: models.py:110
 msgid "Can view persons groups"
 msgstr ""
 
-#: models.py:60
+#: models.py:111
 msgid "Can view personal details"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "female"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "male"
 msgstr ""
 
-#: models.py:73
+#: models.py:124
 msgid "Linked user"
 msgstr ""
 
-#: models.py:75
+#: models.py:126
 msgid "Is person active?"
 msgstr ""
 
-#: models.py:77
+#: models.py:128
 msgid "First name"
 msgstr ""
 
-#: models.py:78
+#: models.py:129
 msgid "Last name"
 msgstr ""
 
-#: models.py:80
+#: models.py:131
 msgid "Additional name(s)"
 msgstr ""
 
-#: models.py:84 models.py:260
+#: models.py:135 models.py:332
 msgid "Short name"
 msgstr ""
 
-#: models.py:87
+#: models.py:138
 msgid "Street"
 msgstr ""
 
-#: models.py:88
+#: models.py:139
 msgid "Street number"
 msgstr ""
 
-#: models.py:89
+#: models.py:140
 msgid "Postal code"
 msgstr ""
 
-#: models.py:90
+#: models.py:141
 msgid "Place"
 msgstr ""
 
-#: models.py:92
+#: models.py:143
 msgid "Home phone"
 msgstr ""
 
-#: models.py:93
+#: models.py:144
 msgid "Mobile phone"
 msgstr ""
 
-#: models.py:97
+#: models.py:148
 msgid "Date of birth"
 msgstr ""
 
-#: models.py:98
+#: models.py:149
 msgid "Sex"
 msgstr ""
 
-#: models.py:100
+#: models.py:151
 msgid "Photo"
 msgstr ""
 
-#: models.py:105
+#: models.py:155 templates/core/person/full.html:129
 msgid "Guardians / Parents"
 msgstr ""
 
-#: models.py:112
+#: models.py:162
 msgid "Primary group"
 msgstr ""
 
-#: models.py:115 models.py:346 models.py:370 models.py:455 models.py:643
+#: models.py:165 models.py:423 models.py:447 models.py:532 models.py:720
+#: templates/core/person/full.html:112
 msgid "Description"
 msgstr ""
 
-#: models.py:233
+#: models.py:296
 msgid "Title of field"
 msgstr ""
 
-#: models.py:235
+#: models.py:298
 msgid "Type of field"
 msgstr ""
 
-#: models.py:239
+#: models.py:305
 msgid "Addtitional field for groups"
 msgstr ""
 
-#: models.py:240
+#: models.py:306
 msgid "Addtitional fields for groups"
 msgstr ""
 
-#: models.py:252
+#: models.py:318
 msgid "Group"
 msgstr ""
 
-#: models.py:254
+#: models.py:320
 msgid "Can assign child groups to groups"
 msgstr ""
 
-#: models.py:258
+#: models.py:330
 msgid "Long name"
 msgstr ""
 
-#: models.py:268 templates/core/group_full.html:37
+#: models.py:340 templates/core/group/full.html:65
 msgid "Members"
 msgstr ""
 
-#: models.py:271 templates/core/group_full.html:34
+#: models.py:343 templates/core/group/full.html:62
 msgid "Owners"
 msgstr ""
 
-#: models.py:278
+#: models.py:350 templates/core/group/full.html:54
 msgid "Parent groups"
 msgstr ""
 
-#: models.py:286
+#: models.py:358
 msgid "Type of group"
 msgstr ""
 
-#: models.py:290
-msgid "Additional fields"
-msgstr ""
-
-#: models.py:342
+#: models.py:419
 msgid "User"
 msgstr ""
 
-#: models.py:345 models.py:369 models.py:454
+#: models.py:422 models.py:446 models.py:531
 #: templates/core/announcement/list.html:18
 msgid "Title"
 msgstr ""
 
-#: models.py:348
+#: models.py:425
 msgid "Application"
 msgstr ""
 
-#: models.py:354
+#: models.py:431
 msgid "Activity"
 msgstr ""
 
-#: models.py:355
+#: models.py:432
 msgid "Activities"
 msgstr ""
 
-#: models.py:361
+#: models.py:438
 msgid "Sender"
 msgstr ""
 
-#: models.py:366
+#: models.py:443
 msgid "Recipient"
 msgstr ""
 
-#: models.py:371 models.py:624
+#: models.py:448 models.py:701
 msgid "Link"
 msgstr ""
 
-#: models.py:373
+#: models.py:450
 msgid "Read"
 msgstr ""
 
-#: models.py:374
+#: models.py:451
 msgid "Sent"
 msgstr ""
 
-#: models.py:387
+#: models.py:464
 msgid "Notification"
 msgstr ""
 
-#: models.py:388
+#: models.py:465
 msgid "Notifications"
 msgstr ""
 
-#: models.py:456
+#: models.py:533
 msgid "Link to detailed view"
 msgstr ""
 
-#: models.py:459
+#: models.py:536
 msgid "Date and time from when to show"
 msgstr ""
 
-#: models.py:462
+#: models.py:539
 msgid "Date and time until when to show"
 msgstr ""
 
-#: models.py:486
+#: models.py:563
 msgid "Announcement"
 msgstr ""
 
-#: models.py:524
+#: models.py:601
 msgid "Announcement recipient"
 msgstr ""
 
-#: models.py:525
+#: models.py:602
 msgid "Announcement recipients"
 msgstr ""
 
-#: models.py:575
+#: models.py:652
 msgid "Widget Title"
 msgstr ""
 
-#: models.py:576
+#: models.py:653
 msgid "Activate Widget"
 msgstr ""
 
-#: models.py:594
+#: models.py:671
 msgid "Dashboard Widget"
 msgstr ""
 
-#: models.py:595
+#: models.py:672
 msgid "Dashboard Widgets"
 msgstr ""
 
-#: models.py:601
+#: models.py:678
 msgid "Menu ID"
 msgstr ""
 
-#: models.py:613
+#: models.py:690
 msgid "Custom menu"
 msgstr ""
 
-#: models.py:614
+#: models.py:691
 msgid "Custom menus"
 msgstr ""
 
-#: models.py:621
+#: models.py:698
 msgid "Menu"
 msgstr ""
 
-#: models.py:623
-msgid "Name"
-msgstr ""
-
-#: models.py:625
+#: models.py:702
 msgid "Icon"
 msgstr ""
 
-#: models.py:631
+#: models.py:708
 msgid "Custom menu item"
 msgstr ""
 
-#: models.py:632
+#: models.py:709
 msgid "Custom menu items"
 msgstr ""
 
-#: models.py:642
+#: models.py:719
 msgid "Title of type"
 msgstr ""
 
-#: models.py:646
+#: models.py:726 templates/core/group/full.html:46
 msgid "Group type"
 msgstr ""
 
-#: models.py:647
-msgid "Group types"
-msgstr ""
-
-#: models.py:656
+#: models.py:736
 msgid "Can view system status"
 msgstr ""
 
-#: models.py:657
+#: models.py:737
 msgid "Can link persons to accounts"
 msgstr ""
 
-#: models.py:658
+#: models.py:738
 msgid "Can manage data"
 msgstr ""
 
-#: models.py:659
+#: models.py:739
 msgid "Can impersonate"
 msgstr ""
 
-#: models.py:660
+#: models.py:740
 msgid "Can use search"
 msgstr ""
 
-#: models.py:661
+#: models.py:741
 msgid "Can change site preferences"
 msgstr ""
 
-#: models.py:662
+#: models.py:742
 msgid "Can change person preferences"
 msgstr ""
 
-#: models.py:663
+#: models.py:743
 msgid "Can change group preferences"
 msgstr ""
 
-#: preferences.py:27
+#: preferences.py:24
+msgid "Authentication"
+msgstr ""
+
+#: preferences.py:33
 msgid "Site title"
 msgstr ""
 
-#: preferences.py:36
+#: preferences.py:42
 msgid "Site description"
 msgstr ""
 
-#: preferences.py:45
+#: preferences.py:51
 msgid "Primary colour"
 msgstr ""
 
-#: preferences.py:54
+#: preferences.py:60
 msgid "Secondary colour"
 msgstr ""
 
-#: preferences.py:62
+#: preferences.py:68
 msgid "Logo"
 msgstr ""
 
-#: preferences.py:70
+#: preferences.py:76
 msgid "Favicon"
 msgstr ""
 
-#: preferences.py:78
+#: preferences.py:84
 msgid "PWA-Icon"
 msgstr ""
 
-#: preferences.py:87
+#: preferences.py:93
 msgid "Mail out name"
 msgstr ""
 
-#: preferences.py:96
+#: preferences.py:102
 msgid "Mail out address"
 msgstr ""
 
-#: preferences.py:106
+#: preferences.py:112
 msgid "Link to privacy policy"
 msgstr ""
 
-#: preferences.py:116
+#: preferences.py:122
 msgid "Link to imprint"
 msgstr ""
 
-#: preferences.py:126
+#: preferences.py:132
 msgid "Name format for addressing"
 msgstr ""
 
-#: preferences.py:140
+#: preferences.py:146
 msgid "Channels to use for notifications"
 msgstr ""
 
-#: preferences.py:150
+#: preferences.py:156
 msgid "Regular expression to match primary group, e.g. '^Class .*'"
 msgstr ""
 
-#: preferences.py:159
+#: preferences.py:165
 msgid "Field on person to match primary group against"
 msgstr ""
 
-#: preferences.py:171
+#: preferences.py:177
 msgid "Display name of the school"
 msgstr ""
 
-#: preferences.py:180
+#: preferences.py:186
 msgid "Official name of the school, e.g. as given by supervisory authority"
 msgstr ""
 
-#: settings.py:276
+#: preferences.py:194
+msgid "Enabled custom authentication backends"
+msgstr ""
+
+#: settings.py:300
 msgid "English"
 msgstr ""
 
-#: settings.py:277
+#: settings.py:301
 msgid "German"
 msgstr ""
 
-#: settings.py:278
+#: settings.py:302
 msgid "French"
 msgstr ""
 
-#: templates/403.html:10 templates/404.html:10 templates/500.html:10
+#: settings.py:303
+msgid "Norwegian (bokmål)"
+msgstr "Norsk (bokmål)"
+
+#: tables.py:19 templates/core/announcement/list.html:36
+#: templates/core/group/full.html:23 templates/core/person/full.html:22
+msgid "Edit"
+msgstr ""
+
+#: tables.py:21 templates/core/announcement/list.html:22
+msgid "Actions"
+msgstr ""
+
+#: tables.py:56 tables.py:57 tables.py:71
+#: templates/core/announcement/list.html:42 templates/core/group/full.html:30
+#: templates/core/pages/delete.html:22 templates/core/person/full.html:29
+msgid "Delete"
+msgstr ""
+
+#: templates/403.html:14 templates/404.html:10 templates/500.html:10
 msgid "Error"
 msgstr ""
 
-#: templates/403.html:10
+#: templates/403.html:14
 msgid ""
 "You are not allowed to access the requested page or\n"
 "          object."
 msgstr ""
 
-#: templates/403.html:13 templates/404.html:17
+#: templates/403.html:19 templates/404.html:17
 msgid ""
 "\n"
-"            If you think this is an error in AlekSIS, please contact your "
-"site\n"
+"            If you think this is an error in AlekSIS, please contact your site\n"
 "            administrators:\n"
 "          "
 msgstr ""
@@ -657,8 +732,7 @@ msgstr ""
 #: templates/500.html:13
 msgid ""
 "\n"
-"            Your site administrators will automatically be notified about "
-"this\n"
+"            Your site administrators will automatically be notified about this\n"
 "            error. You can also contact them directly:\n"
 "          "
 msgstr ""
@@ -672,75 +746,17 @@ msgstr ""
 #: templates/503.html:13
 msgid ""
 "\n"
-"            This page is currently unavailable. If this error persists, "
-"contact your site administrators:\n"
+"            This page is currently unavailable. If this error persists, contact your site administrators:\n"
 "          "
 msgstr ""
 
-#: templates/core/about.html:6 templates/core/about.html:15
-msgid "About AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:7
-msgid "AlekSIS – The Free School Information System"
-msgstr ""
-
-#: templates/core/about.html:17
-msgid ""
-"\n"
-"              This platform is powered by AlekSIS, a web-based school "
-"information system (SIS) which can be used\n"
-"              to manage and/or publish organisational artifacts of "
-"educational institutions. AlekSIS is free software and\n"
-"              can be used by anyone.\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:25
-msgid "Website of AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:26
-msgid "Source code"
-msgstr ""
-
-#: templates/core/about.html:35
-msgid "Licence information"
-msgstr ""
-
-#: templates/core/about.html:37
-msgid ""
-"\n"
-"              The core and the official apps of AlekSIS are licenced under "
-"the EUPL, version 1.2 or later. For licence\n"
-"              information from third-party apps, if installed, refer to the "
-"respective components below. The\n"
-"              licences are marked like this:\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:45
-msgid "Free/Open Source Licence"
+#: templates/core/additional_field/edit.html:6
+#: templates/core/additional_field/edit.html:7
+msgid "Edit additional field"
 msgstr ""
 
-#: templates/core/about.html:46
-msgid "Other Licence"
-msgstr ""
-
-#: templates/core/about.html:50
-msgid "Full licence text"
-msgstr ""
-
-#: templates/core/about.html:51
-msgid "More information about the EUPL"
-msgstr ""
-
-#: templates/core/about.html:90
-#, python-format
-msgid ""
-"\n"
-"                    This app is licenced under %(licence)s.\n"
-"                  "
+#: templates/core/additional_field/list.html:14
+msgid "Create additional field"
 msgstr ""
 
 #: templates/core/announcement/form.html:10
@@ -773,163 +789,134 @@ msgstr ""
 msgid "Recipients"
 msgstr ""
 
-#: templates/core/announcement/list.html:22
-msgid "Actions"
-msgstr ""
-
-#: templates/core/announcement/list.html:36 templates/core/group_full.html:22
-#: templates/core/person_full.html:21
-msgid "Edit"
-msgstr ""
-
-#: templates/core/announcement/list.html:42
-msgid "Delete"
-msgstr ""
-
 #: templates/core/announcement/list.html:50
 msgid "There are no announcements."
 msgstr ""
 
-#: templates/core/announcements.html:9 templates/core/announcements.html:36
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:13
-#, python-format
-msgid ""
-"\n"
-"              Valid from %(from)s until %(until)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:40
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s – %(until)s\n"
-"            "
-msgstr ""
-
 #: templates/core/base.html:54
 msgid "Logged in as"
 msgstr ""
 
-#: templates/core/base.html:76 templates/search/search.html:7
-#: templates/search/search.html:22
-msgid "Search"
-msgstr ""
-
-#: templates/core/base.html:148
+#: templates/core/base.html:147
 msgid "About AlekSIS — The Free School Information System"
 msgstr ""
 
-#: templates/core/base.html:156
+#: templates/core/base.html:155
 msgid "Impress"
 msgstr ""
 
-#: templates/core/base.html:164
+#: templates/core/base.html:163
 msgid "Privacy Policy"
 msgstr ""
 
-#: templates/core/base_print.html:62
+#: templates/core/base_print.html:64
 msgid "Powered by AlekSIS"
 msgstr ""
 
-#: templates/core/edit_group.html:6 templates/core/edit_group.html:7
-msgid "Edit group"
-msgstr ""
-
-#: templates/core/edit_person.html:8 templates/core/edit_person.html:9
-msgid "Edit person"
-msgstr ""
-
-#: templates/core/group_full.html:28 templates/core/person_full.html:28
-msgid "Change preferences"
-msgstr ""
-
-#: templates/core/groups.html:14
-msgid "Create group"
-msgstr ""
-
-#: templates/core/groups_child_groups.html:18
+#: templates/core/group/child_groups.html:18
 msgid ""
 "\n"
-"          You can use this to assign child groups to groups. Please use the "
-"filters below to select groups you want to\n"
+"          You can use this to assign child groups to groups. Please use the filters below to select groups you want to\n"
 "          change and click \"Next\".\n"
 "        "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:31
+#: templates/core/group/child_groups.html:31
 msgid "Update selection"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:35
+#: templates/core/group/child_groups.html:35
 msgid "Clear all filters"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:39
+#: templates/core/group/child_groups.html:39
 msgid "Currently selected groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:52
+#: templates/core/group/child_groups.html:52
 msgid "Start assigning child groups for this groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:61
+#: templates/core/group/child_groups.html:61
 msgid ""
 "\n"
 "            Please select some groups in order to go on with assigning.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:72
+#: templates/core/group/child_groups.html:72
 msgid "Current group:"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:78
+#: templates/core/group/child_groups.html:78
 msgid "Please be careful!"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:79
+#: templates/core/group/child_groups.html:79
 msgid ""
 "\n"
-"            If you click \"Back\" or \"Next\" the current group assignments "
-"are not saved.\n"
-"            If you click \"Save\", you will overwrite all existing child "
-"group relations for this group with what you\n"
+"            If you click \"Back\" or \"Next\" the current group assignments are not saved.\n"
+"            If you click \"Save\", you will overwrite all existing child group relations for this group with what you\n"
 "            selected on this page.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:93
-#: templates/core/groups_child_groups.html:128
+#: templates/core/group/child_groups.html:93
+#: templates/core/group/child_groups.html:128
 #: templates/two_factor/_wizard_actions.html:15
 #: templates/two_factor/_wizard_actions.html:20
 msgid "Back"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:99
-#: templates/core/groups_child_groups.html:134
+#: templates/core/group/child_groups.html:99
+#: templates/core/group/child_groups.html:134
 #: templates/two_factor/_wizard_actions.html:26
 msgid "Next"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:106
-#: templates/core/groups_child_groups.html:141
-#: templates/core/save_button.html:3
+#: templates/core/group/child_groups.html:106
+#: templates/core/group/child_groups.html:141
+#: templates/core/partials/save_button.html:3
 msgid "Save"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:112
-#: templates/core/groups_child_groups.html:147
+#: templates/core/group/child_groups.html:112
+#: templates/core/group/child_groups.html:147
 msgid "Save and next"
 msgstr ""
 
+#: templates/core/group/edit.html:6 templates/core/group/edit.html:7
+msgid "Edit group"
+msgstr ""
+
+#: templates/core/group/full.html:37 templates/core/person/full.html:36
+msgid "Change preferences"
+msgstr ""
+
+#: templates/core/group/list.html:14
+msgid "Create group"
+msgstr ""
+
+#: templates/core/group/list.html:17
+msgid "Filter groups"
+msgstr ""
+
+#: templates/core/group/list.html:24 templates/core/person/list.html:28
+msgid "Clear"
+msgstr ""
+
+#: templates/core/group/list.html:28
+msgid "Selected groups"
+msgstr ""
+
+#: templates/core/group_type/edit.html:6 templates/core/group_type/edit.html:7
+msgid "Edit group type"
+msgstr ""
+
+#: templates/core/group_type/list.html:14
+msgid "Create group type"
+msgstr ""
+
 #: templates/core/index.html:4
 msgid "Home"
 msgstr ""
@@ -954,105 +941,328 @@ msgstr ""
 msgid "No notifications available yet."
 msgstr ""
 
-#: templates/core/no_person.html:12
+#: templates/core/pages/about.html:6 templates/core/pages/about.html:15
+msgid "About AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:7
+msgid "AlekSIS – The Free School Information System"
+msgstr ""
+
+#: templates/core/pages/about.html:17
 msgid ""
 "\n"
-"            Your administrator account is not linked to any person. "
-"Therefore,\n"
-"            a dummy person has been linked to your account.\n"
-"          "
+"              This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used\n"
+"              to manage and/or publish organisational artifacts of educational institutions. AlekSIS is free software and\n"
+"              can be used by anyone.\n"
+"            "
 msgstr ""
 
-#: templates/core/no_person.html:19
+#: templates/core/pages/about.html:25
+msgid "Website of AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:26
+msgid "Source code"
+msgstr ""
+
+#: templates/core/pages/about.html:35
+msgid "Licence information"
+msgstr ""
+
+#: templates/core/pages/about.html:37
 msgid ""
 "\n"
-"            Your user account is not linked to a person. This means you\n"
-"            cannot access any school-related information. Please contact\n"
-"            the managers of AlekSIS at your school.\n"
-"          "
+"              The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence\n"
+"              information from third-party apps, if installed, refer to the respective components below. The\n"
+"              licences are marked like this:\n"
+"            "
 msgstr ""
 
-#: templates/core/person_full.html:34
-msgid "Contact details"
+#: templates/core/pages/about.html:45
+msgid "Free/Open Source Licence"
 msgstr ""
 
-#: templates/core/persons_accounts.html:7
-#: templates/core/persons_accounts.html:9
-msgid "Link persons to accounts"
+#: templates/core/pages/about.html:46
+msgid "Other Licence"
+msgstr ""
+
+#: templates/core/pages/about.html:50
+msgid "Full licence text"
+msgstr ""
+
+#: templates/core/pages/about.html:51
+msgid "More information about the EUPL"
 msgstr ""
 
-#: templates/core/persons_accounts.html:16
+#: templates/core/pages/about.html:90
+#, python-format
 msgid ""
 "\n"
-"        You can use this form to assign user accounts to persons. Use the\n"
-"        dropdowns to select existing accounts; use the text fields to create "
-"new\n"
-"        accounts on-the-fly. The latter will create a new account with the\n"
-"        entered username and copy all other details from the person.\n"
-"      "
+"                    This app is licenced under %(licence)s.\n"
+"                  "
 msgstr ""
 
-#: templates/core/persons_accounts.html:31
-#: templates/core/persons_accounts.html:55
-msgid "Update"
+#: templates/core/pages/delete.html:6
+#, python-format
+msgid "Delete %(object_name)s"
 msgstr ""
 
-#: templates/core/persons_accounts.html:37
-msgid "Existing account"
+#: templates/core/pages/delete.html:13
+#, python-format
+msgid ""
+"\n"
+"      Do you really want to delete the %(object_name)s \"%(object)s\"?\n"
+"    "
 msgstr ""
 
-#: templates/core/persons_accounts.html:38
-msgid "New account"
+#: templates/core/pages/offline.html:6
+msgid ""
+"No internet\n"
+"    connection."
+msgstr ""
+
+#: templates/core/pages/offline.html:10
+msgid ""
+"\n"
+"      There was an error accessing this page. You probably don't have an internet connection. Check to see if your WiFi\n"
+"      or mobile data is turned on and try again. If you think you are connected, please contact the system\n"
+"      administrators:\n"
+"    "
+msgstr ""
+
+#: templates/core/pages/progress.html:27
+msgid ""
+"\n"
+"              Without activated JavaScript the progress status can't be updated.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/progress.html:47
+#: templates/two_factor/core/otp_required.html:19
+msgid "Go back"
 msgstr ""
 
-#: templates/core/system_status.html:12
+#: templates/core/pages/system_status.html:12
 msgid "System checks"
 msgstr ""
 
-#: templates/core/system_status.html:21
+#: templates/core/pages/system_status.html:21
 msgid "Maintenance mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:23
+#: templates/core/pages/system_status.html:23
 msgid ""
 "\n"
-"                Only admin and visitors from internal IPs can access "
-"thesite.\n"
+"                Only admin and visitors from internal IPs can access thesite.\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:34
+#: templates/core/pages/system_status.html:34
 msgid "Maintenance mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:35
+#: templates/core/pages/system_status.html:35
 msgid "Everyone can access the site."
 msgstr ""
 
-#: templates/core/system_status.html:45
+#: templates/core/pages/system_status.html:45
 msgid "Debug mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:47
+#: templates/core/pages/system_status.html:47
 msgid ""
 "\n"
-"                The web server throws back debug information on errors. Do "
-"not use in production!\n"
+"                The web server throws back debug information on errors. Do not use in production!\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:54
+#: templates/core/pages/system_status.html:54
 msgid "Debug mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:56
+#: templates/core/pages/system_status.html:56
 msgid ""
 "\n"
-"                Debug mode is disabled. Default error pages are displayed on "
-"errors.\n"
+"                Debug mode is disabled. Default error pages are displayed on errors.\n"
 "              "
 msgstr ""
 
+#: templates/core/pages/system_status.html:69
+msgid "System health checks"
+msgstr ""
+
+#: templates/core/pages/system_status.html:75
+msgid "Service"
+msgstr ""
+
+#: templates/core/pages/system_status.html:76
+#: templates/core/pages/system_status.html:115
+msgid "Status"
+msgstr ""
+
+#: templates/core/pages/system_status.html:77
+msgid "Time taken"
+msgstr ""
+
+#: templates/core/pages/system_status.html:96
+msgid "seconds"
+msgstr ""
+
+#: templates/core/pages/system_status.html:107
+msgid "Celery task results"
+msgstr ""
+
+#: templates/core/pages/system_status.html:112
+msgid "Task"
+msgstr ""
+
+#: templates/core/pages/system_status.html:113
+msgid "ID"
+msgstr ""
+
+#: templates/core/pages/system_status.html:114
+msgid "Date done"
+msgstr ""
+
+#: templates/core/partials/announcements.html:9
+#: templates/core/partials/announcements.html:36
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:13
+#, python-format
+msgid ""
+"\n"
+"              Valid from %(from)s until %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:40
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s – %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:10
+#, python-format
+msgid ""
+"\n"
+"              Created by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:14
+#: templates/core/partials/crud_events.html:22
+#: templates/core/partials/crud_events.html:26
+#, python-format
+msgid ""
+"\n"
+"              Updated by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:18
+#, python-format
+msgid ""
+"\n"
+"              Deleted by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/language_form.html:16
+msgid "Language"
+msgstr ""
+
+#: templates/core/partials/language_form.html:28
+msgid "Select language"
+msgstr ""
+
+#: templates/core/partials/no_person.html:12
+msgid ""
+"\n"
+"            Your administrator account is not linked to any person. Therefore,\n"
+"            a dummy person has been linked to your account.\n"
+"          "
+msgstr ""
+
+#: templates/core/partials/no_person.html:19
+msgid ""
+"\n"
+"            Your user account is not linked to a person. This means you\n"
+"            cannot access any school-related information. Please contact\n"
+"            the managers of AlekSIS at your school.\n"
+"          "
+msgstr ""
+
+#: templates/core/person/accounts.html:7 templates/core/person/accounts.html:9
+msgid "Link persons to accounts"
+msgstr ""
+
+#: templates/core/person/accounts.html:16
+msgid ""
+"\n"
+"        You can use this form to assign user accounts to persons. Use the\n"
+"        dropdowns to select existing accounts; use the text fields to create new\n"
+"        accounts on-the-fly. The latter will create a new account with the\n"
+"        entered username and copy all other details from the person.\n"
+"      "
+msgstr ""
+
+#: templates/core/person/accounts.html:31
+#: templates/core/person/accounts.html:55
+msgid "Update"
+msgstr ""
+
+#: templates/core/person/accounts.html:37
+msgid "Existing account"
+msgstr ""
+
+#: templates/core/person/accounts.html:38
+msgid "New account"
+msgstr ""
+
+#: templates/core/person/edit.html:11 templates/core/person/edit.html:12
+msgid "Edit person"
+msgstr ""
+
+#: templates/core/person/full.html:42
+msgid "Contact details"
+msgstr ""
+
+#: templates/core/person/full.html:122
+msgid "Children"
+msgstr ""
+
+#: templates/core/person/list.html:17
+msgid "Create person"
+msgstr ""
+
+#: templates/core/person/list.html:21
+msgid "Filter persons"
+msgstr ""
+
+#: templates/core/person/list.html:32
+msgid "Selected persons"
+msgstr ""
+
+#: templates/core/school_term/create.html:6
+#: templates/core/school_term/create.html:7
+#: templates/core/school_term/list.html:14
+msgid "Create school term"
+msgstr ""
+
+#: templates/core/school_term/edit.html:6
+#: templates/core/school_term/edit.html:7
+msgid "Edit school term"
+msgstr ""
+
 #: templates/dynamic_preferences/form.html:9
 msgid "Site preferences"
 msgstr ""
@@ -1078,23 +1288,6 @@ msgstr ""
 msgid "Impersonate user"
 msgstr ""
 
-#: templates/offline.html:6
-msgid ""
-"No internet\n"
-"    connection."
-msgstr ""
-
-#: templates/offline.html:10
-msgid ""
-"\n"
-"      There was an error accessing this page. You probably don't have an "
-"internet connection. Check to see if your WiFi\n"
-"      or mobile data is turned on and try again. If you think you are "
-"connected, please contact the system\n"
-"      administrators:\n"
-"    "
-msgstr ""
-
 #: templates/search/search.html:8
 msgid "Global Search"
 msgstr ""
@@ -1119,28 +1312,43 @@ msgstr ""
 msgid "New notification for"
 msgstr ""
 
-#: templates/templated_email/notification.email:7
-msgid "Dear"
+#: templates/templated_email/notification.email:6
+#: templates/templated_email/notification.email:27
+#, python-format
+msgid "Dear %(notification_user)s,"
 msgstr ""
 
 #: templates/templated_email/notification.email:8
+#: templates/templated_email/notification.email:29
 msgid "we got a new notification for you:"
 msgstr ""
 
-#: templates/templated_email/notification.email:12
+#: templates/templated_email/notification.email:15
+#: templates/templated_email/notification.email:35
 msgid "More information"
 msgstr ""
 
-#: templates/templated_email/notification.email:16
+#: templates/templated_email/notification.email:18
 #, python-format
 msgid ""
 "\n"
-"    <p>By %(trans_sender)s at %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Your AlekSIS team</i>\n"
+"        Sent by %(trans_sender)s at %(trans_created_at)s\n"
 "    "
 msgstr ""
 
+#: templates/templated_email/notification.email:22
+#: templates/templated_email/notification.email:46
+msgid "Your AlekSIS team"
+msgstr ""
+
+#: templates/templated_email/notification.email:40
+#, python-format
+msgid ""
+"\n"
+"            Sent by %(trans_sender)s at %(trans_created_at)s\n"
+"        "
+msgstr ""
+
 #: templates/two_factor/_base_focus.html:6
 #: templates/two_factor/core/otp_required.html:22
 #: templates/two_factor/core/setup.html:5
@@ -1163,10 +1371,8 @@ msgid ""
 "\n"
 "        Backup tokens can be used when your primary and backup\n"
 "        phone numbers aren't available. The backup tokens below can be used\n"
-"        for login verification. If you've used up all your backup tokens, "
-"you\n"
-"        can generate a new set of backup tokens. Only the backup tokens "
-"shown\n"
+"        for login verification. If you've used up all your backup tokens, you\n"
+"        can generate a new set of backup tokens. Only the backup tokens shown\n"
 "        below will be valid.\n"
 "      "
 msgstr ""
@@ -1191,52 +1397,58 @@ msgid "Generate Tokens"
 msgstr ""
 
 #: templates/two_factor/core/login.html:16
-msgid ""
-"You have no permission to view this page. Please login with an other account."
+msgid "You have no permission to view this page. Please login with an other account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:25
+#: templates/two_factor/core/login.html:24
 msgid "Please login to see this page."
 msgstr ""
 
-#: templates/two_factor/core/login.html:28
+#: templates/two_factor/core/login.html:30
+msgid "Login with username and password"
+msgstr ""
+
+#: templates/two_factor/core/login.html:40
 msgid ""
 "We are calling your phone right now, please enter the\n"
 "              digits you hear."
 msgstr ""
 
-#: templates/two_factor/core/login.html:31
+#: templates/two_factor/core/login.html:43
 msgid ""
 "We sent you a text message, please enter the tokens we\n"
 "              sent."
 msgstr ""
 
-#: templates/two_factor/core/login.html:34
+#: templates/two_factor/core/login.html:46
 msgid ""
 "Please enter the tokens generated by your token\n"
 "              generator."
 msgstr ""
 
-#: templates/two_factor/core/login.html:38
+#: templates/two_factor/core/login.html:50
 msgid ""
 "Use this form for entering backup tokens for logging in.\n"
-"            These tokens have been generated for you to print and keep safe. "
-"Please\n"
+"            These tokens have been generated for you to print and keep safe. Please\n"
 "            enter one of these backup tokens to login to your account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:56
+#: templates/two_factor/core/login.html:68
 msgid "Or, alternatively, use one of your backup phones:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:66
+#: templates/two_factor/core/login.html:78
 msgid "As a last resort, you can use a backup token:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:69
+#: templates/two_factor/core/login.html:81
 msgid "Use Backup Token"
 msgstr ""
 
+#: templates/two_factor/core/login.html:93
+msgid "Use alternative login options"
+msgstr ""
+
 #: templates/two_factor/core/otp_required.html:9
 msgid "Permission Denied"
 msgstr ""
@@ -1244,8 +1456,7 @@ msgstr ""
 #: templates/two_factor/core/otp_required.html:10
 msgid ""
 "The page you requested, enforces users to verify using\n"
-"          two-factor authentication for security reasons. You need to enable "
-"these\n"
+"          two-factor authentication for security reasons. You need to enable these\n"
 "          security features in order to access this page."
 msgstr ""
 
@@ -1256,10 +1467,6 @@ msgid ""
 "          security."
 msgstr ""
 
-#: templates/two_factor/core/otp_required.html:19
-msgid "Go back"
-msgstr ""
-
 #: templates/two_factor/core/phone_register.html:5
 #: templates/two_factor/core/phone_register.html:9
 msgid "Add Backup Phone"
@@ -1322,8 +1529,7 @@ msgstr ""
 #: templates/two_factor/core/setup.html:50
 msgid ""
 "\n"
-"            We are calling your phone right now, please enter the digits you "
-"hear.\n"
+"            We are calling your phone right now, please enter the digits you hear.\n"
 "          "
 msgstr ""
 
@@ -1337,12 +1543,9 @@ msgstr ""
 #: templates/two_factor/core/setup.html:63
 msgid ""
 "\n"
-"          We've encountered an issue with the selected authentication "
-"method. Please\n"
-"          go back and verify that you entered your information correctly, "
-"try\n"
-"          again, or use a different authentication method instead. If the "
-"issue\n"
+"          We've encountered an issue with the selected authentication method. Please\n"
+"          go back and verify that you entered your information correctly, try\n"
+"          again, or use a different authentication method instead. If the issue\n"
 "          persists, contact the site administrator.\n"
 "        "
 msgstr ""
@@ -1364,8 +1567,7 @@ msgstr ""
 #: templates/two_factor/core/setup_complete.html:14
 msgid ""
 "\n"
-"        Congratulations, you've successfully enabled two-factor "
-"authentication.\n"
+"        Congratulations, you've successfully enabled two-factor authentication.\n"
 "      "
 msgstr ""
 
@@ -1383,8 +1585,7 @@ msgstr ""
 msgid ""
 "\n"
 "          However, it might happen that you don't have access to\n"
-"          your primary token device. To enable account recovery, generate "
-"backup codes\n"
+"          your primary token device. To enable account recovery, generate backup codes\n"
 "          or add a phone number.\n"
 "        "
 msgstr ""
@@ -1402,9 +1603,7 @@ msgid "Disable Two-Factor Authentication"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:12
-msgid ""
-"You are about to disable two-factor authentication. This weakens your "
-"account security, are you sure?"
+msgid "You are about to disable two-factor authentication. This weakens your account security, are you sure?"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:26
@@ -1491,26 +1690,58 @@ msgstr ""
 msgid "SMS"
 msgstr ""
 
-#: views.py:212
+#: views.py:122
+msgid "The school term has been created."
+msgstr ""
+
+#: views.py:133
+msgid "The school term has been saved."
+msgstr ""
+
+#: views.py:273
 msgid "The child groups were successfully saved."
 msgstr ""
 
-#: views.py:240
+#: views.py:309
 msgid "The person has been saved."
 msgstr ""
 
-#: views.py:276
+#: views.py:346
 msgid "The group has been saved."
 msgstr ""
 
-#: views.py:348
+#: views.py:434
 msgid "The announcement has been saved."
 msgstr ""
 
-#: views.py:364
+#: views.py:450
 msgid "The announcement has been deleted."
 msgstr ""
 
-#: views.py:435
+#: views.py:521
 msgid "The preferences have been saved successfully."
 msgstr ""
+
+#: views.py:544
+msgid "The person has been deleted."
+msgstr ""
+
+#: views.py:557
+msgid "The group has been deleted."
+msgstr ""
+
+#: views.py:588
+msgid "The additional_field has been saved."
+msgstr ""
+
+#: views.py:622
+msgid "The additional field has been deleted."
+msgstr ""
+
+#: views.py:646
+msgid "The group type has been saved."
+msgstr ""
+
+#: views.py:676
+msgid "The group type has been deleted."
+msgstr ""
diff --git a/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po b/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po
index 21309c0096e0f1ec402dfa7c4e2f8604b96e2466..9dbef6e6f74f842b0e8f25e389edf1a852cd8d99 100644
--- a/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po
+++ b/aleksis/core/locale/nb_NO/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-04-28 13:31+0000\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/aleksis/core/locale/tr_TR/LC_MESSAGES/django.po b/aleksis/core/locale/tr_TR/LC_MESSAGES/django.po
index 3e169fa0130f90c88bfaba22972f8bf0a7163a7f..d1efaccfa330d6f6989f9baf39bca163cd3cadf2 100644
--- a/aleksis/core/locale/tr_TR/LC_MESSAGES/django.po
+++ b/aleksis/core/locale/tr_TR/LC_MESSAGES/django.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: AlekSIS (School Information System) 0.1\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-05-04 15:39+0200\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,6 +17,20 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+#: filters.py:37 templates/core/base.html:77 templates/core/group/list.html:20
+#: templates/core/person/list.html:24 templates/search/search.html:7
+#: templates/search/search.html:22
+msgid "Search"
+msgstr ""
+
+#: filters.py:53
+msgid "Search by name"
+msgstr ""
+
+#: filters.py:65
+msgid "Search by contact details"
+msgstr ""
+
 #: forms.py:46
 msgid "You cannot set a new username when also selecting an existing user."
 msgstr ""
@@ -41,64 +55,71 @@ msgstr ""
 msgid "Advanced personal data"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "New user"
 msgstr ""
 
-#: forms.py:116
+#: forms.py:114
 msgid "Create a new account"
 msgstr ""
 
-#: forms.py:128
+#: forms.py:126 models.py:91
+msgid "School term"
+msgstr ""
+
+#: forms.py:127
 msgid "Common data"
 msgstr ""
 
-#: forms.py:129 forms.py:169 menus.py:141 models.py:54
-#: templates/core/persons.html:8 templates/core/persons.html:9
+#: forms.py:128 forms.py:170 menus.py:152 models.py:105
+#: templates/core/person/list.html:8 templates/core/person/list.html:9
 msgid "Persons"
 msgstr ""
 
-#: forms.py:162 forms.py:165 models.py:31
+#: forms.py:129
+msgid "Additional data"
+msgstr ""
+
+#: forms.py:163 forms.py:166 models.py:35
 msgid "Date"
 msgstr ""
 
-#: forms.py:163 forms.py:166 models.py:39
+#: forms.py:164 forms.py:167 models.py:43
 msgid "Time"
 msgstr ""
 
-#: forms.py:171 menus.py:149 models.py:253 templates/core/groups.html:8
-#: templates/core/groups.html:9 templates/core/person_full.html:106
+#: forms.py:172 menus.py:160 models.py:319 templates/core/group/list.html:8
+#: templates/core/group/list.html:9 templates/core/person/full.html:136
 msgid "Groups"
 msgstr ""
 
-#: forms.py:175
+#: forms.py:176
 msgid "From when until when should the announcement be displayed?"
 msgstr ""
 
-#: forms.py:178
+#: forms.py:179
 msgid "Who should see the announcement?"
 msgstr ""
 
-#: forms.py:179
+#: forms.py:180
 msgid "Write your announcement:"
 msgstr ""
 
-#: forms.py:216
-msgid ""
-"You are not allowed to create announcements which are only valid in the past."
+#: forms.py:219
+msgid "You are not allowed to create announcements which are only valid in the past."
 msgstr ""
 
-#: forms.py:220
+#: forms.py:223
 msgid "The from date and time must be earlier then the until date and time."
 msgstr ""
 
-#: forms.py:229
+#: forms.py:232
 msgid "You need at least one recipient."
 msgstr ""
 
 #: menus.py:7 templates/two_factor/core/login.html:6
 #: templates/two_factor/core/login.html:10
-#: templates/two_factor/core/login.html:73
+#: templates/two_factor/core/login.html:86
 msgid "Login"
 msgstr ""
 
@@ -134,502 +155,556 @@ msgstr ""
 msgid "Admin"
 msgstr ""
 
-#: menus.py:75 models.py:487 templates/core/announcement/list.html:7
+#: menus.py:75 models.py:564 templates/core/announcement/list.html:7
 #: templates/core/announcement/list.html:8
 msgid "Announcements"
 msgstr ""
 
-#: menus.py:86 templates/core/data_management.html:6
-#: templates/core/data_management.html:7
+#: menus.py:86 models.py:92 templates/core/school_term/list.html:8
+#: templates/core/school_term/list.html:9
+msgid "School terms"
+msgstr ""
+
+#: menus.py:97 templates/core/management/data_management.html:6
+#: templates/core/management/data_management.html:7
 msgid "Data management"
 msgstr ""
 
-#: menus.py:94 templates/core/system_status.html:5
-#: templates/core/system_status.html:7
+#: menus.py:105 templates/core/pages/system_status.html:5
+#: templates/core/pages/system_status.html:7
 msgid "System status"
 msgstr ""
 
-#: menus.py:105
+#: menus.py:116
 msgid "Impersonation"
 msgstr ""
 
-#: menus.py:113
+#: menus.py:124
 msgid "Configuration"
 msgstr ""
 
-#: menus.py:124
+#: menus.py:135
 msgid "Backend Admin"
 msgstr ""
 
-#: menus.py:132
+#: menus.py:143
 msgid "People"
 msgstr ""
 
-#: menus.py:157
+#: menus.py:168 models.py:727 templates/core/group_type/list.html:8
+#: templates/core/group_type/list.html:9
+msgid "Group types"
+msgstr ""
+
+#: menus.py:179
 msgid "Persons and accounts"
 msgstr ""
 
-#: menus.py:168
+#: menus.py:190
 msgid "Groups and child groups"
 msgstr ""
 
-#: menus.py:183 templates/core/groups_child_groups.html:7
-#: templates/core/groups_child_groups.html:9
+#: menus.py:201 models.py:363 templates/core/additional_field/list.html:8
+#: templates/core/additional_field/list.html:9
+msgid "Additional fields"
+msgstr ""
+
+#: menus.py:216 templates/core/group/child_groups.html:7
+#: templates/core/group/child_groups.html:9
 msgid "Assign child groups to groups"
 msgstr ""
 
-#: models.py:29
+#: mixins.py:406
+msgid "Linked school term"
+msgstr ""
+
+#: models.py:33
 msgid "Boolean (Yes/No)"
 msgstr ""
 
-#: models.py:30
+#: models.py:34
 msgid "Text (one line)"
 msgstr ""
 
-#: models.py:32
+#: models.py:36
 msgid "Date and time"
 msgstr ""
 
-#: models.py:33
+#: models.py:37
 msgid "Decimal number"
 msgstr ""
 
-#: models.py:34 models.py:95
+#: models.py:38 models.py:146
 msgid "E-mail address"
 msgstr ""
 
-#: models.py:35
+#: models.py:39
 msgid "Integer"
 msgstr ""
 
-#: models.py:36
+#: models.py:40
 msgid "IP address"
 msgstr ""
 
-#: models.py:37
+#: models.py:41
 msgid "Boolean or empty (Yes/No/Neither)"
 msgstr ""
 
-#: models.py:38
+#: models.py:42
 msgid "Text (multi-line)"
 msgstr ""
 
-#: models.py:40
+#: models.py:44
 msgid "URL / Link"
 msgstr ""
 
-#: models.py:53 templates/core/persons_accounts.html:36
+#: models.py:56 models.py:700
+msgid "Name"
+msgstr ""
+
+#: models.py:58
+msgid "Start date"
+msgstr ""
+
+#: models.py:59
+msgid "End date"
+msgstr ""
+
+#: models.py:77
+msgid "The start date must be earlier than the end date."
+msgstr ""
+
+#: models.py:84
+msgid "There is already a school term for this time or a part of this time."
+msgstr ""
+
+#: models.py:104 templates/core/person/accounts.html:36
 msgid "Person"
 msgstr ""
 
-#: models.py:56
+#: models.py:107
 msgid "Can view address"
 msgstr ""
 
-#: models.py:57
+#: models.py:108
 msgid "Can view contact details"
 msgstr ""
 
-#: models.py:58
+#: models.py:109
 msgid "Can view photo"
 msgstr ""
 
-#: models.py:59
+#: models.py:110
 msgid "Can view persons groups"
 msgstr ""
 
-#: models.py:60
+#: models.py:111
 msgid "Can view personal details"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "female"
 msgstr ""
 
-#: models.py:65
+#: models.py:116
 msgid "male"
 msgstr ""
 
-#: models.py:73
+#: models.py:124
 msgid "Linked user"
 msgstr ""
 
-#: models.py:75
+#: models.py:126
 msgid "Is person active?"
 msgstr ""
 
-#: models.py:77
+#: models.py:128
 msgid "First name"
 msgstr ""
 
-#: models.py:78
+#: models.py:129
 msgid "Last name"
 msgstr ""
 
-#: models.py:80
+#: models.py:131
 msgid "Additional name(s)"
 msgstr ""
 
-#: models.py:84 models.py:260
+#: models.py:135 models.py:332
 msgid "Short name"
 msgstr ""
 
-#: models.py:87
+#: models.py:138
 msgid "Street"
 msgstr ""
 
-#: models.py:88
+#: models.py:139
 msgid "Street number"
 msgstr ""
 
-#: models.py:89
+#: models.py:140
 msgid "Postal code"
 msgstr ""
 
-#: models.py:90
+#: models.py:141
 msgid "Place"
 msgstr ""
 
-#: models.py:92
+#: models.py:143
 msgid "Home phone"
 msgstr ""
 
-#: models.py:93
+#: models.py:144
 msgid "Mobile phone"
 msgstr ""
 
-#: models.py:97
+#: models.py:148
 msgid "Date of birth"
 msgstr ""
 
-#: models.py:98
+#: models.py:149
 msgid "Sex"
 msgstr ""
 
-#: models.py:100
+#: models.py:151
 msgid "Photo"
 msgstr ""
 
-#: models.py:105
+#: models.py:155 templates/core/person/full.html:129
 msgid "Guardians / Parents"
 msgstr ""
 
-#: models.py:112
+#: models.py:162
 msgid "Primary group"
 msgstr ""
 
-#: models.py:115 models.py:346 models.py:370 models.py:455 models.py:643
+#: models.py:165 models.py:423 models.py:447 models.py:532 models.py:720
+#: templates/core/person/full.html:112
 msgid "Description"
 msgstr ""
 
-#: models.py:233
+#: models.py:296
 msgid "Title of field"
 msgstr ""
 
-#: models.py:235
+#: models.py:298
 msgid "Type of field"
 msgstr ""
 
-#: models.py:239
+#: models.py:305
 msgid "Addtitional field for groups"
 msgstr ""
 
-#: models.py:240
+#: models.py:306
 msgid "Addtitional fields for groups"
 msgstr ""
 
-#: models.py:252
+#: models.py:318
 msgid "Group"
 msgstr ""
 
-#: models.py:254
+#: models.py:320
 msgid "Can assign child groups to groups"
 msgstr ""
 
-#: models.py:258
+#: models.py:330
 msgid "Long name"
 msgstr ""
 
-#: models.py:268 templates/core/group_full.html:37
+#: models.py:340 templates/core/group/full.html:65
 msgid "Members"
 msgstr ""
 
-#: models.py:271 templates/core/group_full.html:34
+#: models.py:343 templates/core/group/full.html:62
 msgid "Owners"
 msgstr ""
 
-#: models.py:278
+#: models.py:350 templates/core/group/full.html:54
 msgid "Parent groups"
 msgstr ""
 
-#: models.py:286
+#: models.py:358
 msgid "Type of group"
 msgstr ""
 
-#: models.py:290
-msgid "Additional fields"
-msgstr ""
-
-#: models.py:342
+#: models.py:419
 msgid "User"
 msgstr ""
 
-#: models.py:345 models.py:369 models.py:454
+#: models.py:422 models.py:446 models.py:531
 #: templates/core/announcement/list.html:18
 msgid "Title"
 msgstr ""
 
-#: models.py:348
+#: models.py:425
 msgid "Application"
 msgstr ""
 
-#: models.py:354
+#: models.py:431
 msgid "Activity"
 msgstr ""
 
-#: models.py:355
+#: models.py:432
 msgid "Activities"
 msgstr ""
 
-#: models.py:361
+#: models.py:438
 msgid "Sender"
 msgstr ""
 
-#: models.py:366
+#: models.py:443
 msgid "Recipient"
 msgstr ""
 
-#: models.py:371 models.py:624
+#: models.py:448 models.py:701
 msgid "Link"
 msgstr ""
 
-#: models.py:373
+#: models.py:450
 msgid "Read"
 msgstr ""
 
-#: models.py:374
+#: models.py:451
 msgid "Sent"
 msgstr ""
 
-#: models.py:387
+#: models.py:464
 msgid "Notification"
 msgstr ""
 
-#: models.py:388
+#: models.py:465
 msgid "Notifications"
 msgstr ""
 
-#: models.py:456
+#: models.py:533
 msgid "Link to detailed view"
 msgstr ""
 
-#: models.py:459
+#: models.py:536
 msgid "Date and time from when to show"
 msgstr ""
 
-#: models.py:462
+#: models.py:539
 msgid "Date and time until when to show"
 msgstr ""
 
-#: models.py:486
+#: models.py:563
 msgid "Announcement"
 msgstr ""
 
-#: models.py:524
+#: models.py:601
 msgid "Announcement recipient"
 msgstr ""
 
-#: models.py:525
+#: models.py:602
 msgid "Announcement recipients"
 msgstr ""
 
-#: models.py:575
+#: models.py:652
 msgid "Widget Title"
 msgstr ""
 
-#: models.py:576
+#: models.py:653
 msgid "Activate Widget"
 msgstr ""
 
-#: models.py:594
+#: models.py:671
 msgid "Dashboard Widget"
 msgstr ""
 
-#: models.py:595
+#: models.py:672
 msgid "Dashboard Widgets"
 msgstr ""
 
-#: models.py:601
+#: models.py:678
 msgid "Menu ID"
 msgstr ""
 
-#: models.py:613
+#: models.py:690
 msgid "Custom menu"
 msgstr ""
 
-#: models.py:614
+#: models.py:691
 msgid "Custom menus"
 msgstr ""
 
-#: models.py:621
+#: models.py:698
 msgid "Menu"
 msgstr ""
 
-#: models.py:623
-msgid "Name"
-msgstr ""
-
-#: models.py:625
+#: models.py:702
 msgid "Icon"
 msgstr ""
 
-#: models.py:631
+#: models.py:708
 msgid "Custom menu item"
 msgstr ""
 
-#: models.py:632
+#: models.py:709
 msgid "Custom menu items"
 msgstr ""
 
-#: models.py:642
+#: models.py:719
 msgid "Title of type"
 msgstr ""
 
-#: models.py:646
+#: models.py:726 templates/core/group/full.html:46
 msgid "Group type"
 msgstr ""
 
-#: models.py:647
-msgid "Group types"
-msgstr ""
-
-#: models.py:656
+#: models.py:736
 msgid "Can view system status"
 msgstr ""
 
-#: models.py:657
+#: models.py:737
 msgid "Can link persons to accounts"
 msgstr ""
 
-#: models.py:658
+#: models.py:738
 msgid "Can manage data"
 msgstr ""
 
-#: models.py:659
+#: models.py:739
 msgid "Can impersonate"
 msgstr ""
 
-#: models.py:660
+#: models.py:740
 msgid "Can use search"
 msgstr ""
 
-#: models.py:661
+#: models.py:741
 msgid "Can change site preferences"
 msgstr ""
 
-#: models.py:662
+#: models.py:742
 msgid "Can change person preferences"
 msgstr ""
 
-#: models.py:663
+#: models.py:743
 msgid "Can change group preferences"
 msgstr ""
 
-#: preferences.py:27
+#: preferences.py:24
+msgid "Authentication"
+msgstr ""
+
+#: preferences.py:33
 msgid "Site title"
 msgstr ""
 
-#: preferences.py:36
+#: preferences.py:42
 msgid "Site description"
 msgstr ""
 
-#: preferences.py:45
+#: preferences.py:51
 msgid "Primary colour"
 msgstr ""
 
-#: preferences.py:54
+#: preferences.py:60
 msgid "Secondary colour"
 msgstr ""
 
-#: preferences.py:62
+#: preferences.py:68
 msgid "Logo"
 msgstr ""
 
-#: preferences.py:70
+#: preferences.py:76
 msgid "Favicon"
 msgstr ""
 
-#: preferences.py:78
+#: preferences.py:84
 msgid "PWA-Icon"
 msgstr ""
 
-#: preferences.py:87
+#: preferences.py:93
 msgid "Mail out name"
 msgstr ""
 
-#: preferences.py:96
+#: preferences.py:102
 msgid "Mail out address"
 msgstr ""
 
-#: preferences.py:106
+#: preferences.py:112
 msgid "Link to privacy policy"
 msgstr ""
 
-#: preferences.py:116
+#: preferences.py:122
 msgid "Link to imprint"
 msgstr ""
 
-#: preferences.py:126
+#: preferences.py:132
 msgid "Name format for addressing"
 msgstr ""
 
-#: preferences.py:140
+#: preferences.py:146
 msgid "Channels to use for notifications"
 msgstr ""
 
-#: preferences.py:150
+#: preferences.py:156
 msgid "Regular expression to match primary group, e.g. '^Class .*'"
 msgstr ""
 
-#: preferences.py:159
+#: preferences.py:165
 msgid "Field on person to match primary group against"
 msgstr ""
 
-#: preferences.py:171
+#: preferences.py:177
 msgid "Display name of the school"
 msgstr ""
 
-#: preferences.py:180
+#: preferences.py:186
 msgid "Official name of the school, e.g. as given by supervisory authority"
 msgstr ""
 
-#: settings.py:276
+#: preferences.py:194
+msgid "Enabled custom authentication backends"
+msgstr ""
+
+#: settings.py:300
 msgid "English"
 msgstr ""
 
-#: settings.py:277
+#: settings.py:301
 msgid "German"
 msgstr ""
 
-#: settings.py:278
+#: settings.py:302
 msgid "French"
 msgstr ""
 
-#: templates/403.html:10 templates/404.html:10 templates/500.html:10
+#: settings.py:303
+msgid "Norwegian (bokmål)"
+msgstr ""
+
+#: tables.py:19 templates/core/announcement/list.html:36
+#: templates/core/group/full.html:23 templates/core/person/full.html:22
+msgid "Edit"
+msgstr ""
+
+#: tables.py:21 templates/core/announcement/list.html:22
+msgid "Actions"
+msgstr ""
+
+#: tables.py:56 tables.py:57 tables.py:71
+#: templates/core/announcement/list.html:42 templates/core/group/full.html:30
+#: templates/core/pages/delete.html:22 templates/core/person/full.html:29
+msgid "Delete"
+msgstr ""
+
+#: templates/403.html:14 templates/404.html:10 templates/500.html:10
 msgid "Error"
 msgstr ""
 
-#: templates/403.html:10
+#: templates/403.html:14
 msgid ""
 "You are not allowed to access the requested page or\n"
 "          object."
 msgstr ""
 
-#: templates/403.html:13 templates/404.html:17
+#: templates/403.html:19 templates/404.html:17
 msgid ""
 "\n"
-"            If you think this is an error in AlekSIS, please contact your "
-"site\n"
+"            If you think this is an error in AlekSIS, please contact your site\n"
 "            administrators:\n"
 "          "
 msgstr ""
@@ -657,8 +732,7 @@ msgstr ""
 #: templates/500.html:13
 msgid ""
 "\n"
-"            Your site administrators will automatically be notified about "
-"this\n"
+"            Your site administrators will automatically be notified about this\n"
 "            error. You can also contact them directly:\n"
 "          "
 msgstr ""
@@ -672,75 +746,17 @@ msgstr ""
 #: templates/503.html:13
 msgid ""
 "\n"
-"            This page is currently unavailable. If this error persists, "
-"contact your site administrators:\n"
+"            This page is currently unavailable. If this error persists, contact your site administrators:\n"
 "          "
 msgstr ""
 
-#: templates/core/about.html:6 templates/core/about.html:15
-msgid "About AlekSIS"
-msgstr ""
-
-#: templates/core/about.html:7
-msgid "AlekSIS – The Free School Information System"
-msgstr ""
-
-#: templates/core/about.html:17
-msgid ""
-"\n"
-"              This platform is powered by AlekSIS, a web-based school "
-"information system (SIS) which can be used\n"
-"              to manage and/or publish organisational artifacts of "
-"educational institutions. AlekSIS is free software and\n"
-"              can be used by anyone.\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:25
-msgid "Website of AlekSIS"
+#: templates/core/additional_field/edit.html:6
+#: templates/core/additional_field/edit.html:7
+msgid "Edit additional field"
 msgstr ""
 
-#: templates/core/about.html:26
-msgid "Source code"
-msgstr ""
-
-#: templates/core/about.html:35
-msgid "Licence information"
-msgstr ""
-
-#: templates/core/about.html:37
-msgid ""
-"\n"
-"              The core and the official apps of AlekSIS are licenced under "
-"the EUPL, version 1.2 or later. For licence\n"
-"              information from third-party apps, if installed, refer to the "
-"respective components below. The\n"
-"              licences are marked like this:\n"
-"            "
-msgstr ""
-
-#: templates/core/about.html:45
-msgid "Free/Open Source Licence"
-msgstr ""
-
-#: templates/core/about.html:46
-msgid "Other Licence"
-msgstr ""
-
-#: templates/core/about.html:50
-msgid "Full licence text"
-msgstr ""
-
-#: templates/core/about.html:51
-msgid "More information about the EUPL"
-msgstr ""
-
-#: templates/core/about.html:90
-#, python-format
-msgid ""
-"\n"
-"                    This app is licenced under %(licence)s.\n"
-"                  "
+#: templates/core/additional_field/list.html:14
+msgid "Create additional field"
 msgstr ""
 
 #: templates/core/announcement/form.html:10
@@ -773,163 +789,134 @@ msgstr ""
 msgid "Recipients"
 msgstr ""
 
-#: templates/core/announcement/list.html:22
-msgid "Actions"
-msgstr ""
-
-#: templates/core/announcement/list.html:36 templates/core/group_full.html:22
-#: templates/core/person_full.html:21
-msgid "Edit"
-msgstr ""
-
-#: templates/core/announcement/list.html:42
-msgid "Delete"
-msgstr ""
-
 #: templates/core/announcement/list.html:50
 msgid "There are no announcements."
 msgstr ""
 
-#: templates/core/announcements.html:9 templates/core/announcements.html:36
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:13
-#, python-format
-msgid ""
-"\n"
-"              Valid from %(from)s until %(until)s\n"
-"            "
-msgstr ""
-
-#: templates/core/announcements.html:40
-#, python-format
-msgid ""
-"\n"
-"              Valid for %(from)s – %(until)s\n"
-"            "
-msgstr ""
-
 #: templates/core/base.html:54
 msgid "Logged in as"
 msgstr ""
 
-#: templates/core/base.html:76 templates/search/search.html:7
-#: templates/search/search.html:22
-msgid "Search"
-msgstr ""
-
-#: templates/core/base.html:148
+#: templates/core/base.html:147
 msgid "About AlekSIS — The Free School Information System"
 msgstr ""
 
-#: templates/core/base.html:156
+#: templates/core/base.html:155
 msgid "Impress"
 msgstr ""
 
-#: templates/core/base.html:164
+#: templates/core/base.html:163
 msgid "Privacy Policy"
 msgstr ""
 
-#: templates/core/base_print.html:62
+#: templates/core/base_print.html:64
 msgid "Powered by AlekSIS"
 msgstr ""
 
-#: templates/core/edit_group.html:6 templates/core/edit_group.html:7
-msgid "Edit group"
-msgstr ""
-
-#: templates/core/edit_person.html:8 templates/core/edit_person.html:9
-msgid "Edit person"
-msgstr ""
-
-#: templates/core/group_full.html:28 templates/core/person_full.html:28
-msgid "Change preferences"
-msgstr ""
-
-#: templates/core/groups.html:14
-msgid "Create group"
-msgstr ""
-
-#: templates/core/groups_child_groups.html:18
+#: templates/core/group/child_groups.html:18
 msgid ""
 "\n"
-"          You can use this to assign child groups to groups. Please use the "
-"filters below to select groups you want to\n"
+"          You can use this to assign child groups to groups. Please use the filters below to select groups you want to\n"
 "          change and click \"Next\".\n"
 "        "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:31
+#: templates/core/group/child_groups.html:31
 msgid "Update selection"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:35
+#: templates/core/group/child_groups.html:35
 msgid "Clear all filters"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:39
+#: templates/core/group/child_groups.html:39
 msgid "Currently selected groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:52
+#: templates/core/group/child_groups.html:52
 msgid "Start assigning child groups for this groups"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:61
+#: templates/core/group/child_groups.html:61
 msgid ""
 "\n"
 "            Please select some groups in order to go on with assigning.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:72
+#: templates/core/group/child_groups.html:72
 msgid "Current group:"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:78
+#: templates/core/group/child_groups.html:78
 msgid "Please be careful!"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:79
+#: templates/core/group/child_groups.html:79
 msgid ""
 "\n"
-"            If you click \"Back\" or \"Next\" the current group assignments "
-"are not saved.\n"
-"            If you click \"Save\", you will overwrite all existing child "
-"group relations for this group with what you\n"
+"            If you click \"Back\" or \"Next\" the current group assignments are not saved.\n"
+"            If you click \"Save\", you will overwrite all existing child group relations for this group with what you\n"
 "            selected on this page.\n"
 "          "
 msgstr ""
 
-#: templates/core/groups_child_groups.html:93
-#: templates/core/groups_child_groups.html:128
+#: templates/core/group/child_groups.html:93
+#: templates/core/group/child_groups.html:128
 #: templates/two_factor/_wizard_actions.html:15
 #: templates/two_factor/_wizard_actions.html:20
 msgid "Back"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:99
-#: templates/core/groups_child_groups.html:134
+#: templates/core/group/child_groups.html:99
+#: templates/core/group/child_groups.html:134
 #: templates/two_factor/_wizard_actions.html:26
 msgid "Next"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:106
-#: templates/core/groups_child_groups.html:141
-#: templates/core/save_button.html:3
+#: templates/core/group/child_groups.html:106
+#: templates/core/group/child_groups.html:141
+#: templates/core/partials/save_button.html:3
 msgid "Save"
 msgstr ""
 
-#: templates/core/groups_child_groups.html:112
-#: templates/core/groups_child_groups.html:147
+#: templates/core/group/child_groups.html:112
+#: templates/core/group/child_groups.html:147
 msgid "Save and next"
 msgstr ""
 
+#: templates/core/group/edit.html:6 templates/core/group/edit.html:7
+msgid "Edit group"
+msgstr ""
+
+#: templates/core/group/full.html:37 templates/core/person/full.html:36
+msgid "Change preferences"
+msgstr ""
+
+#: templates/core/group/list.html:14
+msgid "Create group"
+msgstr ""
+
+#: templates/core/group/list.html:17
+msgid "Filter groups"
+msgstr ""
+
+#: templates/core/group/list.html:24 templates/core/person/list.html:28
+msgid "Clear"
+msgstr ""
+
+#: templates/core/group/list.html:28
+msgid "Selected groups"
+msgstr ""
+
+#: templates/core/group_type/edit.html:6 templates/core/group_type/edit.html:7
+msgid "Edit group type"
+msgstr ""
+
+#: templates/core/group_type/list.html:14
+msgid "Create group type"
+msgstr ""
+
 #: templates/core/index.html:4
 msgid "Home"
 msgstr ""
@@ -954,105 +941,328 @@ msgstr ""
 msgid "No notifications available yet."
 msgstr ""
 
-#: templates/core/no_person.html:12
+#: templates/core/pages/about.html:6 templates/core/pages/about.html:15
+msgid "About AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:7
+msgid "AlekSIS – The Free School Information System"
+msgstr ""
+
+#: templates/core/pages/about.html:17
 msgid ""
 "\n"
-"            Your administrator account is not linked to any person. "
-"Therefore,\n"
-"            a dummy person has been linked to your account.\n"
-"          "
+"              This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used\n"
+"              to manage and/or publish organisational artifacts of educational institutions. AlekSIS is free software and\n"
+"              can be used by anyone.\n"
+"            "
 msgstr ""
 
-#: templates/core/no_person.html:19
+#: templates/core/pages/about.html:25
+msgid "Website of AlekSIS"
+msgstr ""
+
+#: templates/core/pages/about.html:26
+msgid "Source code"
+msgstr ""
+
+#: templates/core/pages/about.html:35
+msgid "Licence information"
+msgstr ""
+
+#: templates/core/pages/about.html:37
 msgid ""
 "\n"
-"            Your user account is not linked to a person. This means you\n"
-"            cannot access any school-related information. Please contact\n"
-"            the managers of AlekSIS at your school.\n"
-"          "
+"              The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence\n"
+"              information from third-party apps, if installed, refer to the respective components below. The\n"
+"              licences are marked like this:\n"
+"            "
 msgstr ""
 
-#: templates/core/person_full.html:34
-msgid "Contact details"
+#: templates/core/pages/about.html:45
+msgid "Free/Open Source Licence"
 msgstr ""
 
-#: templates/core/persons_accounts.html:7
-#: templates/core/persons_accounts.html:9
-msgid "Link persons to accounts"
+#: templates/core/pages/about.html:46
+msgid "Other Licence"
+msgstr ""
+
+#: templates/core/pages/about.html:50
+msgid "Full licence text"
+msgstr ""
+
+#: templates/core/pages/about.html:51
+msgid "More information about the EUPL"
 msgstr ""
 
-#: templates/core/persons_accounts.html:16
+#: templates/core/pages/about.html:90
+#, python-format
 msgid ""
 "\n"
-"        You can use this form to assign user accounts to persons. Use the\n"
-"        dropdowns to select existing accounts; use the text fields to create "
-"new\n"
-"        accounts on-the-fly. The latter will create a new account with the\n"
-"        entered username and copy all other details from the person.\n"
-"      "
+"                    This app is licenced under %(licence)s.\n"
+"                  "
 msgstr ""
 
-#: templates/core/persons_accounts.html:31
-#: templates/core/persons_accounts.html:55
-msgid "Update"
+#: templates/core/pages/delete.html:6
+#, python-format
+msgid "Delete %(object_name)s"
 msgstr ""
 
-#: templates/core/persons_accounts.html:37
-msgid "Existing account"
+#: templates/core/pages/delete.html:13
+#, python-format
+msgid ""
+"\n"
+"      Do you really want to delete the %(object_name)s \"%(object)s\"?\n"
+"    "
 msgstr ""
 
-#: templates/core/persons_accounts.html:38
-msgid "New account"
+#: templates/core/pages/offline.html:6
+msgid ""
+"No internet\n"
+"    connection."
+msgstr ""
+
+#: templates/core/pages/offline.html:10
+msgid ""
+"\n"
+"      There was an error accessing this page. You probably don't have an internet connection. Check to see if your WiFi\n"
+"      or mobile data is turned on and try again. If you think you are connected, please contact the system\n"
+"      administrators:\n"
+"    "
+msgstr ""
+
+#: templates/core/pages/progress.html:27
+msgid ""
+"\n"
+"              Without activated JavaScript the progress status can't be updated.\n"
+"            "
+msgstr ""
+
+#: templates/core/pages/progress.html:47
+#: templates/two_factor/core/otp_required.html:19
+msgid "Go back"
 msgstr ""
 
-#: templates/core/system_status.html:12
+#: templates/core/pages/system_status.html:12
 msgid "System checks"
 msgstr ""
 
-#: templates/core/system_status.html:21
+#: templates/core/pages/system_status.html:21
 msgid "Maintenance mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:23
+#: templates/core/pages/system_status.html:23
 msgid ""
 "\n"
-"                Only admin and visitors from internal IPs can access "
-"thesite.\n"
+"                Only admin and visitors from internal IPs can access thesite.\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:34
+#: templates/core/pages/system_status.html:34
 msgid "Maintenance mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:35
+#: templates/core/pages/system_status.html:35
 msgid "Everyone can access the site."
 msgstr ""
 
-#: templates/core/system_status.html:45
+#: templates/core/pages/system_status.html:45
 msgid "Debug mode enabled"
 msgstr ""
 
-#: templates/core/system_status.html:47
+#: templates/core/pages/system_status.html:47
 msgid ""
 "\n"
-"                The web server throws back debug information on errors. Do "
-"not use in production!\n"
+"                The web server throws back debug information on errors. Do not use in production!\n"
 "              "
 msgstr ""
 
-#: templates/core/system_status.html:54
+#: templates/core/pages/system_status.html:54
 msgid "Debug mode disabled"
 msgstr ""
 
-#: templates/core/system_status.html:56
+#: templates/core/pages/system_status.html:56
 msgid ""
 "\n"
-"                Debug mode is disabled. Default error pages are displayed on "
-"errors.\n"
+"                Debug mode is disabled. Default error pages are displayed on errors.\n"
 "              "
 msgstr ""
 
+#: templates/core/pages/system_status.html:69
+msgid "System health checks"
+msgstr ""
+
+#: templates/core/pages/system_status.html:75
+msgid "Service"
+msgstr ""
+
+#: templates/core/pages/system_status.html:76
+#: templates/core/pages/system_status.html:115
+msgid "Status"
+msgstr ""
+
+#: templates/core/pages/system_status.html:77
+msgid "Time taken"
+msgstr ""
+
+#: templates/core/pages/system_status.html:96
+msgid "seconds"
+msgstr ""
+
+#: templates/core/pages/system_status.html:107
+msgid "Celery task results"
+msgstr ""
+
+#: templates/core/pages/system_status.html:112
+msgid "Task"
+msgstr ""
+
+#: templates/core/pages/system_status.html:113
+msgid "ID"
+msgstr ""
+
+#: templates/core/pages/system_status.html:114
+msgid "Date done"
+msgstr ""
+
+#: templates/core/partials/announcements.html:9
+#: templates/core/partials/announcements.html:36
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:13
+#, python-format
+msgid ""
+"\n"
+"              Valid from %(from)s until %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/announcements.html:40
+#, python-format
+msgid ""
+"\n"
+"              Valid for %(from)s – %(until)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:10
+#, python-format
+msgid ""
+"\n"
+"              Created by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:14
+#: templates/core/partials/crud_events.html:22
+#: templates/core/partials/crud_events.html:26
+#, python-format
+msgid ""
+"\n"
+"              Updated by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/crud_events.html:18
+#, python-format
+msgid ""
+"\n"
+"              Deleted by %(person)s\n"
+"            "
+msgstr ""
+
+#: templates/core/partials/language_form.html:16
+msgid "Language"
+msgstr ""
+
+#: templates/core/partials/language_form.html:28
+msgid "Select language"
+msgstr ""
+
+#: templates/core/partials/no_person.html:12
+msgid ""
+"\n"
+"            Your administrator account is not linked to any person. Therefore,\n"
+"            a dummy person has been linked to your account.\n"
+"          "
+msgstr ""
+
+#: templates/core/partials/no_person.html:19
+msgid ""
+"\n"
+"            Your user account is not linked to a person. This means you\n"
+"            cannot access any school-related information. Please contact\n"
+"            the managers of AlekSIS at your school.\n"
+"          "
+msgstr ""
+
+#: templates/core/person/accounts.html:7 templates/core/person/accounts.html:9
+msgid "Link persons to accounts"
+msgstr ""
+
+#: templates/core/person/accounts.html:16
+msgid ""
+"\n"
+"        You can use this form to assign user accounts to persons. Use the\n"
+"        dropdowns to select existing accounts; use the text fields to create new\n"
+"        accounts on-the-fly. The latter will create a new account with the\n"
+"        entered username and copy all other details from the person.\n"
+"      "
+msgstr ""
+
+#: templates/core/person/accounts.html:31
+#: templates/core/person/accounts.html:55
+msgid "Update"
+msgstr ""
+
+#: templates/core/person/accounts.html:37
+msgid "Existing account"
+msgstr ""
+
+#: templates/core/person/accounts.html:38
+msgid "New account"
+msgstr ""
+
+#: templates/core/person/edit.html:11 templates/core/person/edit.html:12
+msgid "Edit person"
+msgstr ""
+
+#: templates/core/person/full.html:42
+msgid "Contact details"
+msgstr ""
+
+#: templates/core/person/full.html:122
+msgid "Children"
+msgstr ""
+
+#: templates/core/person/list.html:17
+msgid "Create person"
+msgstr ""
+
+#: templates/core/person/list.html:21
+msgid "Filter persons"
+msgstr ""
+
+#: templates/core/person/list.html:32
+msgid "Selected persons"
+msgstr ""
+
+#: templates/core/school_term/create.html:6
+#: templates/core/school_term/create.html:7
+#: templates/core/school_term/list.html:14
+msgid "Create school term"
+msgstr ""
+
+#: templates/core/school_term/edit.html:6
+#: templates/core/school_term/edit.html:7
+msgid "Edit school term"
+msgstr ""
+
 #: templates/dynamic_preferences/form.html:9
 msgid "Site preferences"
 msgstr ""
@@ -1078,23 +1288,6 @@ msgstr ""
 msgid "Impersonate user"
 msgstr ""
 
-#: templates/offline.html:6
-msgid ""
-"No internet\n"
-"    connection."
-msgstr ""
-
-#: templates/offline.html:10
-msgid ""
-"\n"
-"      There was an error accessing this page. You probably don't have an "
-"internet connection. Check to see if your WiFi\n"
-"      or mobile data is turned on and try again. If you think you are "
-"connected, please contact the system\n"
-"      administrators:\n"
-"    "
-msgstr ""
-
 #: templates/search/search.html:8
 msgid "Global Search"
 msgstr ""
@@ -1119,28 +1312,43 @@ msgstr ""
 msgid "New notification for"
 msgstr ""
 
-#: templates/templated_email/notification.email:7
-msgid "Dear"
+#: templates/templated_email/notification.email:6
+#: templates/templated_email/notification.email:27
+#, python-format
+msgid "Dear %(notification_user)s,"
 msgstr ""
 
 #: templates/templated_email/notification.email:8
+#: templates/templated_email/notification.email:29
 msgid "we got a new notification for you:"
 msgstr ""
 
-#: templates/templated_email/notification.email:12
+#: templates/templated_email/notification.email:15
+#: templates/templated_email/notification.email:35
 msgid "More information"
 msgstr ""
 
-#: templates/templated_email/notification.email:16
+#: templates/templated_email/notification.email:18
 #, python-format
 msgid ""
 "\n"
-"    <p>By %(trans_sender)s at %(trans_created_at)s</p>\n"
-"\n"
-"    <i>Your AlekSIS team</i>\n"
+"        Sent by %(trans_sender)s at %(trans_created_at)s\n"
 "    "
 msgstr ""
 
+#: templates/templated_email/notification.email:22
+#: templates/templated_email/notification.email:46
+msgid "Your AlekSIS team"
+msgstr ""
+
+#: templates/templated_email/notification.email:40
+#, python-format
+msgid ""
+"\n"
+"            Sent by %(trans_sender)s at %(trans_created_at)s\n"
+"        "
+msgstr ""
+
 #: templates/two_factor/_base_focus.html:6
 #: templates/two_factor/core/otp_required.html:22
 #: templates/two_factor/core/setup.html:5
@@ -1163,10 +1371,8 @@ msgid ""
 "\n"
 "        Backup tokens can be used when your primary and backup\n"
 "        phone numbers aren't available. The backup tokens below can be used\n"
-"        for login verification. If you've used up all your backup tokens, "
-"you\n"
-"        can generate a new set of backup tokens. Only the backup tokens "
-"shown\n"
+"        for login verification. If you've used up all your backup tokens, you\n"
+"        can generate a new set of backup tokens. Only the backup tokens shown\n"
 "        below will be valid.\n"
 "      "
 msgstr ""
@@ -1191,52 +1397,58 @@ msgid "Generate Tokens"
 msgstr ""
 
 #: templates/two_factor/core/login.html:16
-msgid ""
-"You have no permission to view this page. Please login with an other account."
+msgid "You have no permission to view this page. Please login with an other account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:25
+#: templates/two_factor/core/login.html:24
 msgid "Please login to see this page."
 msgstr ""
 
-#: templates/two_factor/core/login.html:28
+#: templates/two_factor/core/login.html:30
+msgid "Login with username and password"
+msgstr ""
+
+#: templates/two_factor/core/login.html:40
 msgid ""
 "We are calling your phone right now, please enter the\n"
 "              digits you hear."
 msgstr ""
 
-#: templates/two_factor/core/login.html:31
+#: templates/two_factor/core/login.html:43
 msgid ""
 "We sent you a text message, please enter the tokens we\n"
 "              sent."
 msgstr ""
 
-#: templates/two_factor/core/login.html:34
+#: templates/two_factor/core/login.html:46
 msgid ""
 "Please enter the tokens generated by your token\n"
 "              generator."
 msgstr ""
 
-#: templates/two_factor/core/login.html:38
+#: templates/two_factor/core/login.html:50
 msgid ""
 "Use this form for entering backup tokens for logging in.\n"
-"            These tokens have been generated for you to print and keep safe. "
-"Please\n"
+"            These tokens have been generated for you to print and keep safe. Please\n"
 "            enter one of these backup tokens to login to your account."
 msgstr ""
 
-#: templates/two_factor/core/login.html:56
+#: templates/two_factor/core/login.html:68
 msgid "Or, alternatively, use one of your backup phones:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:66
+#: templates/two_factor/core/login.html:78
 msgid "As a last resort, you can use a backup token:"
 msgstr ""
 
-#: templates/two_factor/core/login.html:69
+#: templates/two_factor/core/login.html:81
 msgid "Use Backup Token"
 msgstr ""
 
+#: templates/two_factor/core/login.html:93
+msgid "Use alternative login options"
+msgstr ""
+
 #: templates/two_factor/core/otp_required.html:9
 msgid "Permission Denied"
 msgstr ""
@@ -1244,8 +1456,7 @@ msgstr ""
 #: templates/two_factor/core/otp_required.html:10
 msgid ""
 "The page you requested, enforces users to verify using\n"
-"          two-factor authentication for security reasons. You need to enable "
-"these\n"
+"          two-factor authentication for security reasons. You need to enable these\n"
 "          security features in order to access this page."
 msgstr ""
 
@@ -1256,10 +1467,6 @@ msgid ""
 "          security."
 msgstr ""
 
-#: templates/two_factor/core/otp_required.html:19
-msgid "Go back"
-msgstr ""
-
 #: templates/two_factor/core/phone_register.html:5
 #: templates/two_factor/core/phone_register.html:9
 msgid "Add Backup Phone"
@@ -1322,8 +1529,7 @@ msgstr ""
 #: templates/two_factor/core/setup.html:50
 msgid ""
 "\n"
-"            We are calling your phone right now, please enter the digits you "
-"hear.\n"
+"            We are calling your phone right now, please enter the digits you hear.\n"
 "          "
 msgstr ""
 
@@ -1337,12 +1543,9 @@ msgstr ""
 #: templates/two_factor/core/setup.html:63
 msgid ""
 "\n"
-"          We've encountered an issue with the selected authentication "
-"method. Please\n"
-"          go back and verify that you entered your information correctly, "
-"try\n"
-"          again, or use a different authentication method instead. If the "
-"issue\n"
+"          We've encountered an issue with the selected authentication method. Please\n"
+"          go back and verify that you entered your information correctly, try\n"
+"          again, or use a different authentication method instead. If the issue\n"
 "          persists, contact the site administrator.\n"
 "        "
 msgstr ""
@@ -1364,8 +1567,7 @@ msgstr ""
 #: templates/two_factor/core/setup_complete.html:14
 msgid ""
 "\n"
-"        Congratulations, you've successfully enabled two-factor "
-"authentication.\n"
+"        Congratulations, you've successfully enabled two-factor authentication.\n"
 "      "
 msgstr ""
 
@@ -1383,8 +1585,7 @@ msgstr ""
 msgid ""
 "\n"
 "          However, it might happen that you don't have access to\n"
-"          your primary token device. To enable account recovery, generate "
-"backup codes\n"
+"          your primary token device. To enable account recovery, generate backup codes\n"
 "          or add a phone number.\n"
 "        "
 msgstr ""
@@ -1402,9 +1603,7 @@ msgid "Disable Two-Factor Authentication"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:12
-msgid ""
-"You are about to disable two-factor authentication. This weakens your "
-"account security, are you sure?"
+msgid "You are about to disable two-factor authentication. This weakens your account security, are you sure?"
 msgstr ""
 
 #: templates/two_factor/profile/disable.html:26
@@ -1491,26 +1690,58 @@ msgstr ""
 msgid "SMS"
 msgstr ""
 
-#: views.py:212
+#: views.py:122
+msgid "The school term has been created."
+msgstr ""
+
+#: views.py:133
+msgid "The school term has been saved."
+msgstr ""
+
+#: views.py:273
 msgid "The child groups were successfully saved."
 msgstr ""
 
-#: views.py:240
+#: views.py:309
 msgid "The person has been saved."
 msgstr ""
 
-#: views.py:276
+#: views.py:346
 msgid "The group has been saved."
 msgstr ""
 
-#: views.py:348
+#: views.py:434
 msgid "The announcement has been saved."
 msgstr ""
 
-#: views.py:364
+#: views.py:450
 msgid "The announcement has been deleted."
 msgstr ""
 
-#: views.py:435
+#: views.py:521
 msgid "The preferences have been saved successfully."
 msgstr ""
+
+#: views.py:544
+msgid "The person has been deleted."
+msgstr ""
+
+#: views.py:557
+msgid "The group has been deleted."
+msgstr ""
+
+#: views.py:588
+msgid "The additional_field has been saved."
+msgstr ""
+
+#: views.py:622
+msgid "The additional field has been deleted."
+msgstr ""
+
+#: views.py:646
+msgid "The group type has been saved."
+msgstr ""
+
+#: views.py:676
+msgid "The group type has been deleted."
+msgstr ""
diff --git a/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po b/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po
index 21309c0096e0f1ec402dfa7c4e2f8604b96e2466..9dbef6e6f74f842b0e8f25e389edf1a852cd8d99 100644
--- a/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po
+++ b/aleksis/core/locale/tr_TR/LC_MESSAGES/djangojs.po
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-04-28 13:31+0000\n"
+"POT-Creation-Date: 2020-08-02 16:29+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
diff --git a/aleksis/core/managers.py b/aleksis/core/managers.py
index a0871078015df8e117a09e23a593b384f7b25dc2..02a0cb6fb6504d931b3d848217b154951d8a0932 100644
--- a/aleksis/core/managers.py
+++ b/aleksis/core/managers.py
@@ -79,3 +79,15 @@ class SchoolTermRelatedQuerySet(QuerySet):
             return self.for_school_term(current_school_term)
         else:
             return None
+
+
+class GroupManager(CurrentSiteManagerWithoutMigrations):
+    """Manager adding specific methods to groups."""
+
+    def get_queryset(self):
+        """Ensure all related data is loaded as well."""
+        return super().get_queryset().select_related("school_term")
+
+
+class GroupQuerySet(SchoolTermRelatedQuerySet):
+    pass
diff --git a/aleksis/core/migrations/0003_drop_image_cropping.py b/aleksis/core/migrations/0003_drop_image_cropping.py
new file mode 100644
index 0000000000000000000000000000000000000000..1fecda4aeed0c9c0c0075bc8972f648a8ec981a0
--- /dev/null
+++ b/aleksis/core/migrations/0003_drop_image_cropping.py
@@ -0,0 +1,22 @@
+# Generated by Django 3.0.7 on 2020-06-28 11:37
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0002_school_term'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='person',
+            name='photo_cropping',
+        ),
+        migrations.AlterField(
+            model_name='person',
+            name='photo',
+            field=models.ImageField(blank=True, null=True, upload_to='', verbose_name='Photo'),
+        ),
+    ]
diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index d196b044c610ae9ad94627e2f65d34c8d57da1a7..2fcab29dac2250ad3fcc5dd70df67cea4ea8d8cd 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -9,19 +9,19 @@ from django.contrib.contenttypes.models import ContentType
 from django.contrib.sites.managers import CurrentSiteManager
 from django.contrib.sites.models import Site
 from django.db import models
-from django.db.models import QuerySet
+from django.db.models import JSONField, QuerySet
 from django.forms.forms import BaseForm
 from django.forms.models import ModelForm, ModelFormMetaclass
 from django.http import HttpResponse
 from django.utils.functional import lazy
 from django.utils.translation import gettext as _
 from django.views.generic import CreateView, UpdateView
-from django.views.generic.edit import ModelFormMixin
+from django.views.generic.edit import DeleteView, ModelFormMixin
 
 import reversion
 from easyaudit.models import CRUDEvent
 from guardian.admin import GuardedModelAdmin
-from jsonstore.fields import IntegerField, JSONField, JSONFieldMixin
+from jsonstore.fields import IntegerField, JSONFieldMixin
 from material.base import Layout, LayoutNode
 from rules.contrib.admin import ObjectPermissionsModelAdmin
 
@@ -115,7 +115,7 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase):
 
         return CRUDEvent.objects.filter(
             object_id=self.pk, content_type=content_type
-        ).select_related("user")
+        ).select_related("user", "user__person")
 
     @property
     def crud_event_create(self) -> Optional[CRUDEvent]:
@@ -232,7 +232,7 @@ class ExtensibleModel(models.Model, metaclass=_ExtensibleModelBase):
             related_name = cls.Meta.default_related_name
 
         # Add field to hold key to foreign model
-        id_field = to_field_type()
+        id_field = to_field_type(blank=True, null=True)
         cls.field(**{id_field_name: id_field})
 
         @property
@@ -375,6 +375,25 @@ class AdvancedEditView(UpdateView, SuccessMessageMixin):
     pass
 
 
+class AdvancedDeleteView(DeleteView):
+    """Common confirm view for deleting.
+
+    .. warning ::
+
+        Using this view, objects are deleted permanently after confirming.
+        We recommend to include the mixin :class:`reversion.views.RevisionMixin`
+        from `django-reversion` to enable soft-delete.
+    """
+
+    success_message: Optional[str] = None
+
+    def delete(self, request, *args, **kwargs):
+        r = super().delete(request, *args, **kwargs)
+        if self.success_message:
+            messages.success(self.request, self.success_message)
+        return r
+
+
 class SchoolTermRelatedExtensibleModel(ExtensibleModel):
     """Add relation to school term."""
 
diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index 7a2c5bcb8c397b1eeb46315aed1a115029472541..4c9c28ea657b98dea8c14188bac0e19cad048ab2 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -9,22 +9,27 @@ from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.sites.models import Site
 from django.core.exceptions import ValidationError
-from django.db import models
+from django.db import models, transaction
 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.decorators import classproperty
+from django.utils.functional import classproperty
 from django.utils.text import slugify
 from django.utils.translation import gettext_lazy as _
 
 import jsonstore
+from cache_memoize import cache_memoize
 from dynamic_preferences.models import PerInstancePreferenceModel
-from image_cropping import ImageCropField, ImageRatioField
 from phonenumber_field.modelfields import PhoneNumberField
 from polymorphic.models import PolymorphicModel
 
-from .managers import CurrentSiteManagerWithoutMigrations, SchoolTermQuerySet
+from .managers import (
+    CurrentSiteManagerWithoutMigrations,
+    GroupManager,
+    GroupQuerySet,
+    SchoolTermQuerySet,
+)
 from .mixins import ExtensibleModel, PureDjangoModel, SchoolTermRelatedExtensibleModel
 from .tasks import send_notification
 from .util.core_helpers import get_site_preferences, now_tomorrow
@@ -60,6 +65,7 @@ class SchoolTerm(ExtensibleModel):
     date_end = models.DateField(verbose_name=_("End date"))
 
     @classmethod
+    @cache_memoize(3600)
     def get_current(cls, day: Optional[date] = None):
         if not day:
             day = timezone.now().date()
@@ -79,7 +85,7 @@ class SchoolTerm(ExtensibleModel):
 
         qs = SchoolTerm.objects.within_dates(self.date_start, self.date_end)
         if self.pk:
-            qs.exclude(pk=self.pk)
+            qs = qs.exclude(pk=self.pk)
         if qs.exists():
             raise ValidationError(
                 _("There is already a school term for this time or a part of this time.")
@@ -149,8 +155,7 @@ class Person(ExtensibleModel):
     date_of_birth = models.DateField(verbose_name=_("Date of birth"), blank=True, null=True)
     sex = models.CharField(verbose_name=_("Sex"), max_length=1, choices=SEX_CHOICES, blank=True)
 
-    photo = ImageCropField(verbose_name=_("Photo"), blank=True, null=True)
-    photo_cropping = ImageRatioField("photo", "600x800", size_warning=True)
+    photo = models.ImageField(verbose_name=_("Photo"), blank=True, null=True)
 
     guardians = models.ManyToManyField(
         "self",
@@ -216,7 +221,7 @@ class Person(ExtensibleModel):
     @property
     def age(self):
         """Age of the person at current time."""
-        return self.age_at(timezone.datetime.now().date())
+        return self.age_at(timezone.now().date())
 
     def age_at(self, today):
         if self.date_of_birth:
@@ -315,6 +320,8 @@ class Group(SchoolTermRelatedExtensibleModel):
     classes, clubs, and the like.
     """
 
+    objects = GroupManager.from_queryset(GroupQuerySet)()
+
     class Meta:
         ordering = ["short_name", "name"]
         verbose_name = _("Group")
@@ -477,7 +484,7 @@ class Notification(ExtensibleModel):
     def save(self, **kwargs):
         super().save(**kwargs)
         if not self.sent:
-            send_notification(self.pk, resend=True)
+            transaction.on_commit(lambda: send_notification(self.pk, resend=True))
         self.sent = True
         super().save(**kwargs)
 
@@ -506,7 +513,7 @@ class AnnouncementQuerySet(models.QuerySet):
 
     def at_time(self, when: Optional[datetime] = None) -> models.QuerySet:
         """Get all announcements at a certain time."""
-        when = when or timezone.datetime.now()
+        when = when or timezone.now()
 
         # Get announcements by time
         announcements = self.filter(valid_from__lte=when, valid_until__gte=when)
@@ -515,7 +522,7 @@ class AnnouncementQuerySet(models.QuerySet):
 
     def on_date(self, when: Optional[date] = None) -> models.QuerySet:
         """Get all announcements at a certain date."""
-        when = when or timezone.datetime.now().date()
+        when = when or timezone.now().date()
 
         # Get announcements by time
         announcements = self.filter(valid_from__date__lte=when, valid_until__date__gte=when)
@@ -554,7 +561,7 @@ class Announcement(ExtensibleModel):
     link = models.URLField(blank=True, verbose_name=_("Link to detailed view"))
 
     valid_from = models.DateTimeField(
-        verbose_name=_("Date and time from when to show"), default=timezone.datetime.now
+        verbose_name=_("Date and time from when to show"), default=timezone.now
     )
     valid_until = models.DateTimeField(
         verbose_name=_("Date and time until when to show"), default=now_tomorrow,
@@ -702,9 +709,10 @@ class CustomMenu(ExtensibleModel):
         return self.name if self.name != "" else self.id
 
     @classmethod
+    @cache_memoize(3600)
     def get_default(cls, name):
         """Get a menu by name or create if it does not exist."""
-        menu, _ = cls.objects.get_or_create(name=name)
+        menu, _ = cls.objects.prefetch_related("items").get_or_create(name=name)
         return menu
 
     class Meta:
diff --git a/aleksis/core/preferences.py b/aleksis/core/preferences.py
index 6693aff1fba605180b6f83e7741fe1cb005267fe..890801b6770db01d0aea4bea07b2eb9b4c2e81a4 100644
--- a/aleksis/core/preferences.py
+++ b/aleksis/core/preferences.py
@@ -3,7 +3,12 @@ from django.forms import EmailField, ImageField, URLField
 from django.utils.translation import gettext_lazy as _
 
 from dynamic_preferences.preferences import Section
-from dynamic_preferences.types import ChoicePreference, FilePreference, StringPreference
+from dynamic_preferences.types import (
+    ChoicePreference,
+    FilePreference,
+    MultipleChoicePreference,
+    StringPreference,
+)
 
 from .models import Person
 from .registries import person_preferences_registry, site_preferences_registry
@@ -16,6 +21,7 @@ mail = Section("mail")
 notification = Section("notification")
 footer = Section("footer")
 account = Section("account")
+auth = Section("auth", verbose_name=_("Authentication"))
 
 
 @site_preferences_registry.register
@@ -178,3 +184,15 @@ class SchoolNameOfficial(StringPreference):
     default = ""
     required = False
     verbose_name = _("Official name of the school, e.g. as given by supervisory authority")
+
+
+@site_preferences_registry.register
+class AuthenticationBackends(MultipleChoicePreference):
+    section = auth
+    name = "backends"
+    default = None
+    verbose_name = _("Enabled custom authentication backends")
+    field_attribute = {"initial": []}
+
+    def get_choices(self):
+        return [(b, b) for b in settings.CUSTOM_AUTHENTICATION_BACKENDS]
diff --git a/aleksis/core/rules.py b/aleksis/core/rules.py
index 18c0edae65ddd985b4f26f2bd52fac1f664c63f2..4b0cf23d6119a05075dc36c32aaf366d0588e80f 100644
--- a/aleksis/core/rules.py
+++ b/aleksis/core/rules.py
@@ -1,4 +1,4 @@
-from rules import add_perm, always_allow
+import rules
 
 from .models import AdditionalField, Announcement, Group, GroupType, Person
 from .util.predicates import (
@@ -11,32 +11,32 @@ from .util.predicates import (
     is_notification_recipient,
 )
 
-add_perm("core", always_allow)
+rules.add_perm("core", rules.always_allow)
 
 # View dashboard
-add_perm("core.view_dashboard", has_person)
+rules.add_perm("core.view_dashboard", has_person)
 
 # Use search
 search_predicate = has_person & has_global_perm("core.search")
-add_perm("core.search", search_predicate)
+rules.add_perm("core.search", search_predicate)
 
 # View persons
 view_persons_predicate = has_person & (
     has_global_perm("core.view_person") | has_any_object("core.view_person", Person)
 )
-add_perm("core.view_persons", view_persons_predicate)
+rules.add_perm("core.view_persons", view_persons_predicate)
 
 # View person
 view_person_predicate = has_person & (
     has_global_perm("core.view_person") | has_object_perm("core.view_person") | is_current_person
 )
-add_perm("core.view_person", view_person_predicate)
+rules.add_perm("core.view_person", view_person_predicate)
 
 # View person address
 view_address_predicate = has_person & (
     has_global_perm("core.view_address") | has_object_perm("core.view_address") | is_current_person
 )
-add_perm("core.view_address", view_address_predicate)
+rules.add_perm("core.view_address", view_address_predicate)
 
 # View person contact details
 view_contact_details_predicate = has_person & (
@@ -44,13 +44,13 @@ view_contact_details_predicate = has_person & (
     | has_object_perm("core.view_contact_details")
     | is_current_person
 )
-add_perm("core.view_contact_details", view_contact_details_predicate)
+rules.add_perm("core.view_contact_details", view_contact_details_predicate)
 
 # View person photo
 view_photo_predicate = has_person & (
     has_global_perm("core.view_photo") | has_object_perm("core.view_photo") | is_current_person
 )
-add_perm("core.view_photo", view_photo_predicate)
+rules.add_perm("core.view_photo", view_photo_predicate)
 
 # View persons groups
 view_groups_predicate = has_person & (
@@ -58,96 +58,96 @@ view_groups_predicate = has_person & (
     | has_object_perm("core.view_person_groups")
     | is_current_person
 )
-add_perm("core.view_person_groups", view_groups_predicate)
+rules.add_perm("core.view_person_groups", view_groups_predicate)
 
 # Edit person
 edit_person_predicate = has_person & (
     has_global_perm("core.change_person") | has_object_perm("core.change_person")
 )
-add_perm("core.edit_person", edit_person_predicate)
+rules.add_perm("core.edit_person", edit_person_predicate)
 
 # Delete person
 delete_person_predicate = has_person & (
     has_global_perm("core.delete_person") | has_object_perm("core.delete_person")
 )
-add_perm("core.delete_person", delete_person_predicate)
+rules.add_perm("core.delete_person", delete_person_predicate)
 
 # Link persons with accounts
 link_persons_accounts_predicate = has_person & has_global_perm("core.link_persons_accounts")
-add_perm("core.link_persons_accounts", link_persons_accounts_predicate)
+rules.add_perm("core.link_persons_accounts", link_persons_accounts_predicate)
 
 # View groups
 view_groups_predicate = has_person & (
     has_global_perm("core.view_group") | has_any_object("core.view_group", Group)
 )
-add_perm("core.view_groups", view_groups_predicate)
+rules.add_perm("core.view_groups", view_groups_predicate)
 
 # View group
 view_group_predicate = has_person & (
     has_global_perm("core.view_group") | has_object_perm("core.view_group")
 )
-add_perm("core.view_group", view_group_predicate)
+rules.add_perm("core.view_group", view_group_predicate)
 
 # Edit group
 edit_group_predicate = has_person & (
     has_global_perm("core.change_group") | has_object_perm("core.change_group")
 )
-add_perm("core.edit_group", edit_group_predicate)
+rules.add_perm("core.edit_group", edit_group_predicate)
 
 # Delete group
 delete_group_predicate = has_person & (
     has_global_perm("core.delete_group") | has_object_perm("core.delete_group")
 )
-add_perm("core.delete_group", delete_group_predicate)
+rules.add_perm("core.delete_group", delete_group_predicate)
 
 # Assign child groups to groups
 assign_child_groups_to_groups_predicate = has_person & has_global_perm(
     "core.assign_child_groups_to_groups"
 )
-add_perm("core.assign_child_groups_to_groups", assign_child_groups_to_groups_predicate)
+rules.add_perm("core.assign_child_groups_to_groups", assign_child_groups_to_groups_predicate)
 
 # Edit school information
 edit_school_information_predicate = has_person & has_global_perm("core.change_school")
-add_perm("core.edit_school_information", edit_school_information_predicate)
+rules.add_perm("core.edit_school_information", edit_school_information_predicate)
 
 # Manage data
 manage_data_predicate = has_person & has_global_perm("core.manage_data")
-add_perm("core.manage_data", manage_data_predicate)
+rules.add_perm("core.manage_data", manage_data_predicate)
 
 # Mark notification as read
 mark_notification_as_read_predicate = has_person & is_notification_recipient
-add_perm("core.mark_notification_as_read", mark_notification_as_read_predicate)
+rules.add_perm("core.mark_notification_as_read", mark_notification_as_read_predicate)
 
 # View announcements
 view_announcements_predicate = has_person & (
     has_global_perm("core.view_announcement")
     | has_any_object("core.view_announcement", Announcement)
 )
-add_perm("core.view_announcements", view_announcements_predicate)
+rules.add_perm("core.view_announcements", view_announcements_predicate)
 
 # Create or edit announcement
 create_or_edit_announcement_predicate = has_person & (
     has_global_perm("core.add_announcement")
     & (has_global_perm("core.change_announcement") | has_object_perm("core.change_announcement"))
 )
-add_perm("core.create_or_edit_announcement", create_or_edit_announcement_predicate)
+rules.add_perm("core.create_or_edit_announcement", create_or_edit_announcement_predicate)
 
 # Delete announcement
 delete_announcement_predicate = has_person & (
     has_global_perm("core.delete_announcement") | has_object_perm("core.delete_announcement")
 )
-add_perm("core.delete_announcement", delete_announcement_predicate)
+rules.add_perm("core.delete_announcement", delete_announcement_predicate)
 
 # Use impersonate
 impersonate_predicate = has_person & has_global_perm("core.impersonate")
-add_perm("core.impersonate", impersonate_predicate)
+rules.add_perm("core.impersonate", impersonate_predicate)
 
 # View system status
 view_system_status_predicate = has_person & has_global_perm("core.view_system_status")
-add_perm("core.view_system_status", view_system_status_predicate)
+rules.add_perm("core.view_system_status", view_system_status_predicate)
 
 # View people menu (persons + objects)
-add_perm(
+rules.add_perm(
     "core.view_people_menu",
     has_person
     & (
@@ -164,14 +164,14 @@ view_personal_details_predicate = has_person & (
     | has_object_perm("core.view_personal_details")
     | is_current_person
 )
-add_perm("core.view_personal_details", view_personal_details_predicate)
+rules.add_perm("core.view_personal_details", view_personal_details_predicate)
 
 # Change site preferences
 change_site_preferences = has_person & (
     has_global_perm("core.change_site_preferences")
     | has_object_perm("core.change_site_preferences")
 )
-add_perm("core.change_site_preferences", change_site_preferences)
+rules.add_perm("core.change_site_preferences", change_site_preferences)
 
 # Change person preferences
 change_person_preferences = has_person & (
@@ -179,7 +179,7 @@ change_person_preferences = has_person & (
     | has_object_perm("core.change_person_preferences")
     | is_current_person
 )
-add_perm("core.change_person_preferences", change_person_preferences)
+rules.add_perm("core.change_person_preferences", change_person_preferences)
 
 # Change group preferences
 change_group_preferences = has_person & (
@@ -187,81 +187,81 @@ change_group_preferences = has_person & (
     | has_object_perm("core.change_group_preferences")
     | is_group_owner
 )
-add_perm("core.change_group_preferences", change_group_preferences)
+rules.add_perm("core.change_group_preferences", change_group_preferences)
 
 
 # Edit additional field
 change_additional_field_predicate = has_person & (
     has_global_perm("core.change_additionalfield") | has_object_perm("core.change_additionalfield")
 )
-add_perm("core.change_additionalfield", change_additional_field_predicate)
+rules.add_perm("core.change_additionalfield", change_additional_field_predicate)
 
 # Edit additional field
 create_additional_field_predicate = has_person & (
     has_global_perm("core.create_additionalfield") | has_object_perm("core.create_additionalfield")
 )
-add_perm("core.create_additionalfield", create_additional_field_predicate)
+rules.add_perm("core.create_additionalfield", create_additional_field_predicate)
 
 
 # Delete additional field
 delete_additional_field_predicate = has_person & (
     has_global_perm("core.delete_additionalfield") | has_object_perm("core.delete_additionalfield")
 )
-add_perm("core.delete_additionalfield", delete_additional_field_predicate)
+rules.add_perm("core.delete_additionalfield", delete_additional_field_predicate)
 
 # View additional fields
 view_additional_field_predicate = has_person & (
     has_global_perm("core.view_additionalfield")
     | has_any_object("core.view_additionalfield", AdditionalField)
 )
-add_perm("core.view_additionalfield", view_additional_field_predicate)
+rules.add_perm("core.view_additionalfield", view_additional_field_predicate)
 
 # Edit group type
 change_group_type_predicate = has_person & (
     has_global_perm("core.change_grouptype") | has_object_perm("core.change_grouptype")
 )
-add_perm("core.edit_grouptype", change_group_type_predicate)
+rules.add_perm("core.edit_grouptype", change_group_type_predicate)
 
 # Create group type
 create_group_type_predicate = has_person & (
     has_global_perm("core.create_grouptype") | has_object_perm("core.change_grouptype")
 )
-add_perm("core.create_grouptype", create_group_type_predicate)
+rules.add_perm("core.create_grouptype", create_group_type_predicate)
 
 
 # Delete group type
 delete_group_type_predicate = has_person & (
     has_global_perm("core.delete_grouptype") | has_object_perm("core.delete_grouptype")
 )
-add_perm("core.delete_grouptype", delete_group_type_predicate)
+rules.add_perm("core.delete_grouptype", delete_group_type_predicate)
 
 # View group types
 view_group_type_predicate = has_person & (
     has_global_perm("core.view_grouptype") | has_any_object("core.view_grouptype", GroupType)
 )
-add_perm("core.view_grouptype", view_group_type_predicate)
+rules.add_perm("core.view_grouptype", view_group_type_predicate)
 
 # Create person
 create_person_predicate = has_person & (
     has_global_perm("core.create_person") | has_object_perm("core.create_person")
 )
-add_perm("core.create_person", create_person_predicate)
+rules.add_perm("core.create_person", create_person_predicate)
 
 # Create group
 create_group_predicate = has_person & (
     has_global_perm("core.create_group") | has_object_perm("core.create_group")
 )
-add_perm("core.create_group", create_group_predicate)
+rules.add_perm("core.create_group", create_group_predicate)
 
 # School years
 view_school_term_predicate = has_person & has_global_perm("core.view_schoolterm")
-add_perm("core.view_schoolterm", view_school_term_predicate)
+rules.add_perm("core.view_schoolterm", view_school_term_predicate)
 
 create_school_term_predicate = has_person & has_global_perm("core.add_schoolterm")
-add_perm("core.create_schoolterm", create_school_term_predicate)
+rules.add_perm("core.create_schoolterm", create_school_term_predicate)
 
 edit_school_term_predicate = has_person & has_global_perm("core.change_schoolterm")
-add_perm("core.edit_schoolterm", edit_school_term_predicate)
+rules.add_perm("core.edit_schoolterm", edit_school_term_predicate)
 
 # View admin menu
 view_admin_menu_predicate = has_person & (
@@ -271,10 +271,10 @@ view_admin_menu_predicate = has_person & (
     | view_system_status_predicate
     | view_announcements_predicate
 )
-add_perm("core.view_admin_menu", view_admin_menu_predicate)
+rules.add_perm("core.view_admin_menu", view_admin_menu_predicate)
 
 # View group stats
 view_group_stats_predicate = has_person & (
     has_global_perm("core.view_group_stats") | has_object_perm("core.view_group_stats")
 )
-add_perm("core.view_group_stats", view_group_stats_predicate)
+rules.add_perm("core.view_group_stats", view_group_stats_predicate)
diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py
index ad5d7077eba8bccb0981f70b2ea7fffce7c9474c..5eea8c972a3edb2510f944ed33cfa10bcc9ff31e 100644
--- a/aleksis/core/settings.py
+++ b/aleksis/core/settings.py
@@ -70,7 +70,6 @@ INSTALLED_APPS = [
     "django_yarnpkg",
     "django_tables2",
     "easy_thumbnails",
-    "image_cropping",
     "maintenance_mode",
     "menu_generator",
     "reversion",
@@ -157,12 +156,7 @@ TEMPLATES = [
     },
 ]
 
-THUMBNAIL_PROCESSORS = (
-    "image_cropping.thumbnail_processors.crop_corners",
-) + thumbnail_settings.THUMBNAIL_PROCESSORS
-
-# Already included by base template / Bootstrap
-IMAGE_CROPPING_JQUERY_URL = None
+THUMBNAIL_PROCESSORS = () + thumbnail_settings.THUMBNAIL_PROCESSORS
 
 WSGI_APPLICATION = "aleksis.core.wsgi.application"
 
@@ -178,6 +172,7 @@ DATABASES = {
         "HOST": _settings.get("database.host", "127.0.0.1"),
         "PORT": _settings.get("database.port", "5432"),
         "ATOMIC_REQUESTS": True,
+        "CONN_MAX_AGE": _settings.get("database.conn_max_age", None),
     }
 }
 
@@ -213,7 +208,7 @@ if _settings.get("ldap.uri", None):
         NestedGroupOfNamesType,
         NestedGroupOfUniqueNamesType,
         PosixGroupType,
-    )  # noqa
+    )
 
     # Enable Django's integration to LDAP
     AUTHENTICATION_BACKENDS.append("django_auth_ldap.backend.LDAPBackend")
@@ -288,10 +283,17 @@ if _settings.get("ldap.uri", None):
                 "is_superuser"
             ]
 
+CUSTOM_AUTHENTICATION_BACKENDS = []
+merge_app_settings("AUTHENTICATION_BACKENDS", CUSTOM_AUTHENTICATION_BACKENDS)
+
 # Add ModelBckend last so all other backends get a chance
 # to verify passwords first
 AUTHENTICATION_BACKENDS.append("django.contrib.auth.backends.ModelBackend")
 
+# Structure of items: backend, URL name, icon name, button title
+ALTERNATIVE_LOGIN_VIEWS = []
+merge_app_settings("ALTERNATIVE_LOGIN_VIEWS", ALTERNATIVE_LOGIN_VIEWS, True)
+
 # Internationalization
 # https://docs.djangoproject.com/en/2.1/topics/i18n/
 
@@ -299,7 +301,7 @@ LANGUAGES = [
     ("en", _("English")),
     ("de", _("German")),
     ("fr", _("French")),
-    ("nb", _("Norsk (bokmål)")),
+    ("nb", _("Norwegian (bokmål)")),
 ]
 LANGUAGE_CODE = _settings.get("l10n.lang", "en")
 TIME_ZONE = _settings.get("l10n.tz", "UTC")
@@ -411,6 +413,8 @@ DBBACKUP_COMPRESS_DB = _settings.get("backup.database.compress", True)
 DBBACKUP_ENCRYPT_DB = _settings.get("backup.database.encrypt", DBBACKUP_GPG_RECIPIENT is not None)
 DBBACKUP_COMPRESS_MEDIA = _settings.get("backup.media.compress", True)
 DBBACKUP_ENCRYPT_MEDIA = _settings.get("backup.media.encrypt", DBBACKUP_GPG_RECIPIENT is not None)
+DBBACKUP_CLEANUP_DB = _settings.get("backup.database.clean", True)
+DBBACKUP_CLEANUP_MEDIA = _settings.get("backup.media.clean", True)
 
 IMPERSONATE = {"USE_HTTP_REFERER": True, "REQUIRE_SUPERUSER": True, "ALLOW_SUPERUSER": True}
 
@@ -689,3 +693,5 @@ HEALTH_CHECK = {
     "DISK_USAGE_MAX": _settings.get("health.disk_usage_max_percent", 90),
     "MEMORY_MIN": _settings.get("health.memory_min_mb", 500),
 }
+
+ORIGINAL_AUTHENTICATION_BACKENDS = AUTHENTICATION_BACKENDS[:]
diff --git a/aleksis/core/static/js/main.js b/aleksis/core/static/js/main.js
index ba4e56cd54d8909d1f74cb54bbdb3c669b4cfeab..615f8b287df18ed38c57d1f44358073bb74bcf61 100644
--- a/aleksis/core/static/js/main.js
+++ b/aleksis/core/static/js/main.js
@@ -1,21 +1,15 @@
-$(document).ready( function () {
-    $("dmc-datetime input").addClass("datepicker");
-    $("[data-form-control='date']").addClass("datepicker");
-    $("[data-form-control='time']").addClass("timepicker");
-
-    // Initialize sidenav [MAT]
-    $(".sidenav").sidenav();
-
+function initDatePicker(sel) {
     // Initialize datepicker [MAT]
-    $('.datepicker').datepicker({
-        format: get_format('SHORT_DATE_FORMAT').toLowerCase().replace('d', 'dd').replace('m', 'mm').replace('y', 'yyyy'),
+    const format = get_format('SHORT_DATE_FORMAT').toLowerCase().replace('d', 'dd').replace('m', 'mm').replace('y', 'yyyy');
+    const el = $(sel).datepicker({
+        format: format,
         // Pull translations from Django helpers
         i18n: {
             months: calendarweek_i18n.month_names,
             monthsShort: calendarweek_i18n.month_abbrs,
             weekdays: calendarweek_i18n.day_names,
             weekdaysShort: calendarweek_i18n.day_abbrs,
-            weekdaysAbbrev: calendarweek_i18n.day_abbrs.map(([v])=> v),
+            weekdaysAbbrev: calendarweek_i18n.day_abbrs.map(([v]) => v),
 
             // Buttons
             today: gettext('Today'),
@@ -27,9 +21,13 @@ $(document).ready( function () {
         firstDay: get_format('FIRST_DAY_OF_WEEK'),
         autoClose: true
     });
+    el.datepicker("setDate", $(sel).val());
+    return el;
+}
 
+function initTimePicker(sel) {
     // Initialize timepicker [MAT]
-    $('.timepicker').timepicker({
+    return $(sel).timepicker({
         twelveHour: false,
         autoClose: true,
         i18n: {
@@ -38,6 +36,21 @@ $(document).ready( function () {
             done: 'OK'
         },
     });
+}
+
+$(document).ready(function () {
+    $("dmc-datetime input").addClass("datepicker");
+    $("[data-form-control='date']").addClass("datepicker");
+    $("[data-form-control='time']").addClass("timepicker");
+
+    // Initialize sidenav [MAT]
+    $(".sidenav").sidenav();
+
+    // Initialize datepicker [MAT]
+    initDatePicker(".datepicker");
+
+    // Initialize timepicker [MAT]
+    initTimePicker(".timepicker");
 
     // Initialize tooltip [MAT]
     $('.tooltipped').tooltip();
diff --git a/aleksis/core/static/print.css b/aleksis/core/static/print.css
index 0e2389e1dfb308f2b763fae85887f8a682fd1ad7..cd3eeeea0accb97cb9e2b48054b8ad033476b41c 100644
--- a/aleksis/core/static/print.css
+++ b/aleksis/core/static/print.css
@@ -110,3 +110,22 @@ header .row, header .col {
         border: white;
     }
 }
+
+/* Some stuff for tables */
+
+table.small-print, td.small-print, th.small-print {
+    font-size: 10pt;
+}
+
+tr {
+    border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+}
+
+td, th {
+    padding: 1px;
+}
+
+td.rotate, th.rotate {
+    text-align: center;
+    transform: rotate(-90deg);
+}
diff --git a/aleksis/core/tasks.py b/aleksis/core/tasks.py
index f391fe05bd6dfd82eaf3e84ddb222bf322881b5f..d085f027fad09e875bf612d8352d83151e77d880 100644
--- a/aleksis/core/tasks.py
+++ b/aleksis/core/tasks.py
@@ -19,11 +19,22 @@ def send_notification(notification: int, resend: bool = False) -> None:
 def backup_data() -> None:
     """Backup database and media using django-dbbackup."""
     # Assemble command-line options for dbbackup management command
-    db_options = "-z " * settings.DBBACKUP_COMPRESS_DB + "-e" * settings.DBBACKUP_ENCRYPT_DB
-    media_options = (
-        "-z " * settings.DBBACKUP_COMPRESS_MEDIA + "-e" * settings.DBBACKUP_ENCRYPT_MEDIA
-    )
+    db_options = []
+    if settings.DBBACKUP_COMPRESS_DB:
+        db_options.append("-z")
+    if settings.DBBACKUP_ENCRYPT_DB:
+        db_options.append("-e")
+    if settings.DBBACKUP_CLEANUP_DB:
+        db_options.append("-c")
+
+    media_options = []
+    if settings.DBBACKUP_COMPRESS_MEDIA:
+        media_options.append("-z")
+    if settings.DBBACKUP_ENCRYPT_MEDIA:
+        media_options.append("-e")
+    if settings.DBBACKUP_CLEANUP_MEDIA:
+        media_options.append("-c")
 
     # Hand off to dbbackup's management commands
-    management.call_command("dbbackup", db_options)
-    management.call_command("mediabackup", media_options)
+    management.call_command("dbbackup", *db_options)
+    management.call_command("mediabackup", *media_options)
diff --git a/aleksis/core/templates/core/announcement/form.html b/aleksis/core/templates/core/announcement/form.html
index 0cd31cdefc11e8f1a2d29a30fb72a001357a946f..44d60280c6d358f74c60cb9c5ccff2c7aba89b07 100644
--- a/aleksis/core/templates/core/announcement/form.html
+++ b/aleksis/core/templates/core/announcement/form.html
@@ -2,8 +2,12 @@
 
 {% extends "core/base.html" %}
 
-{% load i18n material_form %}
+{% load i18n material_form any_js %}
 
+{% block extra_head %}
+    {{ form.media.css }}
+    {% include_css "select2-materialize" %}
+{% endblock %}
 
 {% block browser_title %}
   {% if mode == "edit" %}
@@ -30,4 +34,6 @@
       {% trans "Save und publish announcement" %}
     </button>
   </form>
+  {% include_js "select2-materialize" %}
+  {{ form.media.js }}
 {% endblock %}
diff --git a/aleksis/core/templates/core/group/edit.html b/aleksis/core/templates/core/group/edit.html
index b26a28d1efc5ee292a257220bca00754512c1b99..146a5d83abe78307c20f5f70aaff28dc82b62fed 100644
--- a/aleksis/core/templates/core/group/edit.html
+++ b/aleksis/core/templates/core/group/edit.html
@@ -1,7 +1,12 @@
 {# -*- engine:django -*- #}
 
 {% extends "core/base.html" %}
-{% load material_form i18n %}
+{% load material_form i18n any_js %}
+
+{% block extra_head %}
+    {{ edit_group_form.media.css }}
+    {% include_css "select2-materialize" %}
+{% endblock %}
 
 {% block browser_title %}{% blocktrans %}Edit group{% endblocktrans %}{% endblock %}
 {% block page_title %}{% blocktrans %}Edit group{% endblocktrans %}{% endblock %}
@@ -13,5 +18,7 @@
     {% form form=edit_group_form %}{% endform %}
     {% include "core/partials/save_button.html" %}
   </form>
+  {% include_js "select2-materialize" %}
+  {{ edit_group_form.media.js }}
 
 {% endblock %}
diff --git a/aleksis/core/templates/core/group/full.html b/aleksis/core/templates/core/group/full.html
index 40856b88f067c90292b93a7ee29d2c89066b2d66..1a15daf5c490c4cd1af12e7c43c02a3872c8b883 100644
--- a/aleksis/core/templates/core/group/full.html
+++ b/aleksis/core/templates/core/group/full.html
@@ -80,19 +80,9 @@
   {% endif %}
 
   <h5>{% blocktrans %}Owners{% endblocktrans %}</h5>
-  <form method="get">
-    {% form form=owners_filter.form %}{% endform %}
-    {% trans "Search" as caption %}
-    {% include "core/partials/save_button.html" with caption=caption icon="search" %}
-  </form>
   {% render_table owners_table %}
 
   <h5>{% blocktrans %}Members{% endblocktrans %}</h5>
-  <form method="get">
-    {% form form=members_filter.form %}{% endform %}
-    {% trans "Search" as caption %}
-    {% include "core/partials/save_button.html" with caption=caption icon="search" %}
-  </form>
   {% render_table members_table %}
 
 {% endblock %}
diff --git a/aleksis/core/templates/core/group/list.html b/aleksis/core/templates/core/group/list.html
index 5dff8c86ade16e1b9f77aee7e2494fddb7ea0ba3..436b193e74f4c7e7e718fe5ba69a0b9fa0812a2b 100644
--- a/aleksis/core/templates/core/group/list.html
+++ b/aleksis/core/templates/core/group/list.html
@@ -14,11 +14,17 @@
     {% trans "Create group" %}
   </a>
 
+  <h5>{% trans "Filter groups" %}</h5>
   <form method="get">
     {% form form=groups_filter.form %}{% endform %}
     {% trans "Search" as caption %}
     {% include "core/partials/save_button.html" with caption=caption icon="search" %}
+    <button type="reset" class="btn red waves-effect waves-light">
+      <i class="material-icons left">clear</i>
+      {% trans "Clear" %}
+    </button>
   </form>
 
+  <h5>{% trans "Selected groups" %}</h5>
   {% render_table groups_table %}
 {% endblock %}
diff --git a/aleksis/core/templates/core/pages/delete.html b/aleksis/core/templates/core/pages/delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..db64ee8fc3b977ed9cb74333e1a25834ce3e58b7
--- /dev/null
+++ b/aleksis/core/templates/core/pages/delete.html
@@ -0,0 +1,25 @@
+{% extends "core/base.html" %}
+{% load data_helpers i18n %}
+
+{% block browser_title %}
+  {% verbose_name_object object as object_name %}
+  {% blocktrans with object_name=object_name %}Delete {{ object_name }}{% endblocktrans %}
+{% endblock %}
+
+{% block content %}
+  {% verbose_name_object object as object_name %}
+
+  <p class="flow-text">
+    {% blocktrans with object_name=object_name object=object %}
+      Do you really want to delete the {{ object_name }} "{{ object }}"?
+    {% endblocktrans %}
+  </p>
+
+  <form method="post" action="">
+    {% csrf_token %}
+    <button type="submit" class="btn red waves-effect waves-light">
+      <i class="material-icons left">delete</i>
+      {% trans "Delete" %}
+    </button>
+  </form>
+{% endblock %}
diff --git a/aleksis/core/templates/core/partials/alternative_login_options.html b/aleksis/core/templates/core/partials/alternative_login_options.html
new file mode 100644
index 0000000000000000000000000000000000000000..24d36e9ef76f3da11554169106fc1eafd3c7ac46
--- /dev/null
+++ b/aleksis/core/templates/core/partials/alternative_login_options.html
@@ -0,0 +1,10 @@
+{% if ALTERNATIVE_LOGIN_VIEWS %}
+  <p>
+    {% for backend, url, icon, text in ALTERNATIVE_LOGIN_VIEWS %}
+      <a class="btn-large waves-effect waves-light primary" href="{% url url %}">
+        <i class="material-icons left">{{ icon }}</i>
+        {{ text }}
+      </a>
+    {% endfor %}
+  </p>
+{% endif %}
diff --git a/aleksis/core/templates/core/person/accounts.html b/aleksis/core/templates/core/person/accounts.html
index 672b089aaa949560e958d829597e1b7abd986265..03725518dfcbf8552a53199790daa44d541bac32 100644
--- a/aleksis/core/templates/core/person/accounts.html
+++ b/aleksis/core/templates/core/person/accounts.html
@@ -2,7 +2,12 @@
 
 {% extends "core/base.html" %}
 
-{% load i18n %}
+{% load i18n any_js %}
+
+{% block extra_head %}
+  {{ persons_accounts_formset.media.css }}
+  {% include_css "select2-materialize" %}
+{% endblock %}
 
 {% block browser_title %}{% blocktrans %}Link persons to accounts{% endblocktrans %}{% endblock %}
 {% block page_title %}
@@ -55,4 +60,6 @@
       {% blocktrans %}Update{% endblocktrans %}
     </button>
   </form>
+  {% include_js "select2-materialize" %}
+  {{ persons_accounts_formset.media.js }}
 {% endblock %}
diff --git a/aleksis/core/templates/core/person/edit.html b/aleksis/core/templates/core/person/edit.html
index 8f854610e3424b9da47f142cef41b71c9e0fb097..3bf16ca3521ea744acfe48c6829dfae21db06eb5 100644
--- a/aleksis/core/templates/core/person/edit.html
+++ b/aleksis/core/templates/core/person/edit.html
@@ -2,8 +2,12 @@
 
 {% extends "core/base.html" %}
 
-{% load material_form i18n %}
+{% load material_form i18n any_js %}
 
+{% block extra_head %}
+  {{ edit_person_form.media }}
+  {% include_css "select2-materialize" %}
+{% endblock %}
 
 {% block browser_title %}{% blocktrans %}Edit person{% endblocktrans %}{% endblock %}
 {% block page_title %}{% blocktrans %}Edit person{% endblocktrans %}{% endblock %}
@@ -16,5 +20,7 @@
     {% form form=edit_person_form %}{% endform %}
     {% include "core/partials/save_button.html" %}
   </form>
+  {% include_js "select2-materialize" %}
+  {{ edit_group_form.media.js }}
 
 {% endblock %}
diff --git a/aleksis/core/templates/core/person/full.html b/aleksis/core/templates/core/person/full.html
index bc7b66d8ea52cce7c4e64a9e0b3e443c5b18c37b..80aff9b9fe0b2d3c4146929758430b3401bf5270 100644
--- a/aleksis/core/templates/core/person/full.html
+++ b/aleksis/core/templates/core/person/full.html
@@ -2,7 +2,7 @@
 
 {% extends "core/base.html" %}
 
-{% load i18n static cropping rules material_form %}
+{% load i18n static rules material_form %}
 {% load render_table from django_tables2 %}
 
 {% block browser_title %}{{ person.first_name }} {{ person.last_name }}{% endblock %}
@@ -13,8 +13,9 @@
   {% has_perm 'core.edit_person' user person as can_change_person %}
   {% has_perm 'core.change_person_preferences' user person as can_change_person_preferences %}
   {% has_perm 'core.delete_person' user person as can_delete_person %}
+  {% has_perm "core.impersonate" user person as can_impersonate %}
 
-  {% if can_change_person or can_change_person_preferences or can_delete_person %}
+  {% if can_change_person or can_change_person_preferences or can_delete_person or can_impersonate %}
     <p>
       {% if can_change_person %}
         <a href="{% url 'edit_person_by_id' person.id %}" class="btn waves-effect waves-light">
@@ -36,6 +37,13 @@
           {% trans "Change preferences" %}
         </a>
       {% endif %}
+
+    {% if can_impersonate and person.user %}
+        <a href="{% url "impersonate-start" person.user.id %}" class="btn waves-effect waves-light">
+          <i class="material-icons left">portrait</i>
+          {% trans "Impersonate" %}
+        </a>
+      {% endif %}
     </p>
   {% endif %}
 
@@ -44,7 +52,7 @@
     <div class="col s12 m4">
       {% has_perm 'core.view_photo' user person as can_view_photo %}
       {% if person.photo and can_view_photo %}
-        <img class="person-img" src="{% cropped_thumbnail person 'photo_cropping' max_size='300x400' %}"
+        <img class="person-img" src="{{ person.photo.url }}"
              alt="{{ person.first_name }} {{ person.last_name }}"/>
       {% else %}
         <img class="person-img" src="{% static 'img/fallback.png' %}"
@@ -134,11 +142,6 @@
   {% has_perm 'core.view_person_groups' user person as can_view_groups %}
   {% if can_view_groups %}
     <h5>{% blocktrans %}Groups{% endblocktrans %}</h5>
-    <form method="get">
-      {% form form=groups_filter.form %}{% endform %}
-      {% trans "Search" as caption %}
-      {% include "core/partials/save_button.html" with caption=caption icon="search" %}
-    </form>
     {% render_table groups_table %}
   {% endif %}
 {% endblock %}
diff --git a/aleksis/core/templates/core/person/list.html b/aleksis/core/templates/core/person/list.html
index 816e7254b8bc58d8a6a155afdd97d17310042509..b48baf3e5ff8b0f229ab13dfb7c6b5a5885d105f 100644
--- a/aleksis/core/templates/core/person/list.html
+++ b/aleksis/core/templates/core/person/list.html
@@ -18,11 +18,17 @@
     </a>
   {% endif %}
 
+  <h5>{% trans "Filter persons" %}</h5>
   <form method="get">
     {% form form=persons_filter.form %}{% endform %}
     {% trans "Search" as caption %}
     {% include "core/partials/save_button.html" with caption=caption icon="search" %}
+    <button type="reset" class="btn red waves-effect waves-light">
+      <i class="material-icons left">clear</i>
+      {% trans "Clear" %}
+    </button>
   </form>
 
+  <h5>{% trans "Selected persons" %}</h5>
   {% render_table persons_table %}
 {% endblock %}
diff --git a/aleksis/core/templates/material/fields/django_select2_modelselect2multiplewidget.html b/aleksis/core/templates/material/fields/django_select2_modelselect2multiplewidget.html
new file mode 100644
index 0000000000000000000000000000000000000000..1b19d8ec88bf72a694e32066c935327691c00738
--- /dev/null
+++ b/aleksis/core/templates/material/fields/django_select2_modelselect2multiplewidget.html
@@ -0,0 +1,21 @@
+{% load l10n material_form material_form_internal %}
+{% part bound_field.field %}<{{ field.widget.component|default:'dmc-select' }}>
+  <label>{{ bound_field.label }}</label>
+  <div class="row">
+    <div{% attrs bound_field 'group' %}
+        id="id_{{ bound_field.html_name }}_container"
+        class="input-field col s12{% if field.required %} required{% endif %}{% if bound_field.errors %} has-error{% endif %}"
+        style="margin-top: 0"
+    {% endattrs %}>
+        {% part field prefix %}{% endpart %}
+        {% part field control %}
+        {{ bound_field }}
+        {% endpart %}
+        {% part field help_text %}{% if field.help_text %}
+            <div class="help-block">{{ bound_field.help_text|safe }}</div>
+        {% endif %}{% endpart %}{% part field errors %}
+        {% if bound_field.errors %}
+            {% include  'material/field_errors.html' %}
+        {% endif %}{% endpart %}{{ hidden_initial }}
+    </div>
+</div></{{ field.widget.component|default:'dmc-select' }}>{% endpart %}
diff --git a/aleksis/core/templates/material/fields/django_select2_select2widget.html b/aleksis/core/templates/material/fields/django_select2_select2widget.html
new file mode 100644
index 0000000000000000000000000000000000000000..1b19d8ec88bf72a694e32066c935327691c00738
--- /dev/null
+++ b/aleksis/core/templates/material/fields/django_select2_select2widget.html
@@ -0,0 +1,21 @@
+{% load l10n material_form material_form_internal %}
+{% part bound_field.field %}<{{ field.widget.component|default:'dmc-select' }}>
+  <label>{{ bound_field.label }}</label>
+  <div class="row">
+    <div{% attrs bound_field 'group' %}
+        id="id_{{ bound_field.html_name }}_container"
+        class="input-field col s12{% if field.required %} required{% endif %}{% if bound_field.errors %} has-error{% endif %}"
+        style="margin-top: 0"
+    {% endattrs %}>
+        {% part field prefix %}{% endpart %}
+        {% part field control %}
+        {{ bound_field }}
+        {% endpart %}
+        {% part field help_text %}{% if field.help_text %}
+            <div class="help-block">{{ bound_field.help_text|safe }}</div>
+        {% endif %}{% endpart %}{% part field errors %}
+        {% if bound_field.errors %}
+            {% include  'material/field_errors.html' %}
+        {% endif %}{% endpart %}{{ hidden_initial }}
+    </div>
+</div></{{ field.widget.component|default:'dmc-select' }}>{% endpart %}
diff --git a/aleksis/core/templates/two_factor/core/login.html b/aleksis/core/templates/two_factor/core/login.html
index 6e0df1a4e4fa35a411f9e71cb41868808c942045..0e62194597024dbb613d2c13669513c33dcb9d05 100644
--- a/aleksis/core/templates/two_factor/core/login.html
+++ b/aleksis/core/templates/two_factor/core/login.html
@@ -16,14 +16,26 @@
         {% blocktrans %}You have no permission to view this page. Please login with an other account.{% endblocktrans %}
       </p>
     </div>
-  {% else %}
+  {% elif wizard.steps.current == 'auth' %}
     <div class="alert primary">
       <p>
         <i class="material-icons left">info</i>
 
-        {% if wizard.steps.current == 'auth' %}
-          {% blocktrans %}Please login to see this page.{% endblocktrans %}
-        {% elif wizard.steps.current == 'token' %}
+        {% blocktrans %}Please login to see this page.{% endblocktrans %}
+      </p>
+    </div>
+  {% endif %}
+
+  {% if wizard.steps.current == 'auth' and ALTERNATIVE_LOGIN_VIEWS %}
+    <h5>{% trans "Login with username and password" %}</h5>
+  {% endif %}
+
+  {% if not  wizard.steps.current == "auth" %}
+    <div class="alert primary">
+      <p>
+        <i class="material-icons left">info</i>
+
+        {% if wizard.steps.current == 'token' %}
           {% if device.method == 'call' %}
             {% blocktrans %}We are calling your phone right now, please enter the
               digits you hear.{% endblocktrans %}
@@ -70,7 +82,16 @@
       </p>
     {% endif %}
 
-    <button type="submit" class="btn green waves-effect waves-light">{% trans "Login" %}</button>
+    <button type="submit" class="btn green waves-effect waves-light">
+      {% trans "Login" %}
+      <i class="material-icons right">send</i>
+    </button>
 
   </form>
+
+  {% if wizard.steps.current == 'auth' and ALTERNATIVE_LOGIN_VIEWS %}
+    <h5>{% trans "Use alternative login options" %}</h5>
+    {% include "core/partials/alternative_login_options.html" %}
+  {% endif %}
+
 {% endblock %}
diff --git a/aleksis/core/templatetags/data_helpers.py b/aleksis/core/templatetags/data_helpers.py
index f7393c73fd86eba6f861f87e321bf8dc5cbce6fd..ab2309f260dd6b039cc722bae86fa71637967a1f 100644
--- a/aleksis/core/templatetags/data_helpers.py
+++ b/aleksis/core/templatetags/data_helpers.py
@@ -3,6 +3,7 @@ from typing import Any, Optional, Union
 
 from django import template
 from django.contrib.contenttypes.models import ContentType
+from django.db.models import Model
 
 register = template.Library()
 
@@ -33,6 +34,17 @@ def verbose_name(app_label: str, model: str, field: Optional[str] = None) -> str
         return ct._meta.verbose_name.title()
 
 
+@register.simple_tag
+def verbose_name_object(model: Model, field: Optional[str] = None) -> str:
+    """Get a verbose name of a model or a field by a model or an instance of a model."""
+    if field:
+        # Field
+        return model._meta.get_field(field).verbose_name.title()
+    else:
+        # Whole model
+        return model._meta.verbose_name.title()
+
+
 @register.simple_tag
 def parse_json(value: Optional[str] = None) -> Union[dict, None]:
     """Template tag for parsing JSON from a string."""
diff --git a/aleksis/core/templatetags/html_helpers.py b/aleksis/core/templatetags/html_helpers.py
index a30a230ce4f9aebdf93499ef8ff511befe2a8871..16238fcd00b0a88cb8eb8d6e25fb190ec432e1a5 100644
--- a/aleksis/core/templatetags/html_helpers.py
+++ b/aleksis/core/templatetags/html_helpers.py
@@ -15,6 +15,6 @@ def add_class_to_el(value: str, arg: str) -> str:
     soup = BeautifulSoup(value, "html.parser")
 
     for el in soup.find_all(el):
-        el["class"] = el.get("class", "") + f" {cls}"
+        el["class"] = el.get("class", []) + [cls]
 
     return str(soup)
diff --git a/aleksis/core/tests/test_authentication_backends.py b/aleksis/core/tests/test_authentication_backends.py
new file mode 100644
index 0000000000000000000000000000000000000000..227f48c1469d97f246132a4bfbef2f5af5f4dbb9
--- /dev/null
+++ b/aleksis/core/tests/test_authentication_backends.py
@@ -0,0 +1,64 @@
+from typing import Optional
+
+from django.contrib.auth import authenticate
+from django.contrib.auth.backends import BaseBackend
+from django.contrib.auth.base_user import AbstractBaseUser
+from django.contrib.auth.models import User
+
+import pytest
+
+from aleksis.core.apps import CoreConfig
+from aleksis.core.util.core_helpers import get_site_preferences
+
+pytestmark = pytest.mark.django_db
+
+
+class DummyBackend(BaseBackend):
+    def authenticate(
+        self, request, username: str, password: str, **kwargs
+    ) -> Optional[AbstractBaseUser]:
+        if username == "foo" and password == "baz":
+            return User.objects.get_or_create(username="foo")[0]
+
+
+backend_name = "aleksis.core.tests.test_authentication_backends.DummyBackend"
+
+
+def test_backends_simple(settings):
+
+    assert not authenticate(username="foo", password="baz")
+
+    assert backend_name not in settings.AUTHENTICATION_BACKENDS
+
+    settings.AUTHENTICATION_BACKENDS.append(backend_name)
+    assert backend_name in settings.AUTHENTICATION_BACKENDS
+
+    assert authenticate(username="foo", password="baz")
+
+    settings.AUTHENTICATION_BACKENDS.remove(backend_name)
+
+    assert not authenticate(username="foo", password="baz")
+
+
+def test_backends_with_activation(settings):
+    assert not authenticate(username="foo", password="baz")
+
+    settings.CUSTOM_AUTHENTICATION_BACKENDS.append(backend_name)
+
+    assert backend_name not in get_site_preferences()["auth__backends"]
+    assert backend_name not in settings.AUTHENTICATION_BACKENDS
+    assert not authenticate(username="foo", password="baz")
+
+    print(get_site_preferences()["auth__backends"])
+    print(get_site_preferences()["auth__backends"].append(backend_name))
+
+    get_site_preferences()["auth__backends"] = [backend_name]
+
+    assert backend_name in get_site_preferences()["auth__backends"]
+    assert backend_name in settings.AUTHENTICATION_BACKENDS
+    assert authenticate(username="foo", password="baz")
+
+    get_site_preferences()["auth__backends"] = []
+
+    assert backend_name not in get_site_preferences()["auth__backends"]
+    assert backend_name not in settings.AUTHENTICATION_BACKENDS
diff --git a/aleksis/core/tests/util/test_core_helpers.py b/aleksis/core/tests/util/test_core_helpers.py
new file mode 100644
index 0000000000000000000000000000000000000000..d018ddba3b610251aafcf47698f7669c49ef8fef
--- /dev/null
+++ b/aleksis/core/tests/util/test_core_helpers.py
@@ -0,0 +1,19 @@
+import re
+
+from aleksis.core.util.core_helpers import path_and_rename
+
+
+def test_path_and_rename():
+    re_base = r"[a-z0-9]+"
+
+    example_1 = "sdjaasjkl.jpg"
+    re_example_1 = "files/" + re_base + r"\.jpg"
+    re2_example_1 = "images/" + re_base + r"\.jpg"
+    assert re.match(re_example_1, path_and_rename(None, example_1))
+    assert re.match(re2_example_1, path_and_rename(None, example_1, upload_to="images"))
+
+    example_2 = "sdjaasjkl"
+    re_example_2 = "files/" + re_base
+    re2_example_2 = "images/" + re_base
+    assert re.match(re_example_2, path_and_rename(None, example_2))
+    assert re.match(re2_example_2, path_and_rename(None, example_2, upload_to="images"))
diff --git a/aleksis/core/util/apps.py b/aleksis/core/util/apps.py
index 72e0a2fcd0c46c7ca8bae47dd79e79b70ec9d432..79548a79dfbbb94a36a40bfad54fef5a24d3653c 100644
--- a/aleksis/core/util/apps.py
+++ b/aleksis/core/util/apps.py
@@ -204,7 +204,5 @@ class AppConfig(django.apps.AppConfig):
                 ct = ContentType.objects.get_for_model(model)
                 for perm, verbose_name in model.extra_permissions:
                     Permission.objects.get_or_create(
-                        codename=perm,
-                        content_type=ct,
-                        defaults={"name": verbose_name},
+                        codename=perm, content_type=ct, defaults={"name": verbose_name},
                     )
diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py
index ba28f66292217b77a8d15eb1988774bbe09776fb..aeffad13fb6d1d869a8b6e2793b18f36a9063096 100644
--- a/aleksis/core/util/core_helpers.py
+++ b/aleksis/core/util/core_helpers.py
@@ -9,12 +9,13 @@ from typing import Any, Callable, Optional, Sequence, Union
 from uuid import uuid4
 
 from django.conf import settings
-from django.db.models import Model
+from django.db.models import Model, QuerySet
 from django.http import HttpRequest
 from django.shortcuts import get_object_or_404
 from django.utils import timezone
 from django.utils.functional import lazy
 
+from cache_memoize import cache_memoize
 from django_global_request.middleware import get_request
 
 from aleksis.core.util import messages
@@ -133,6 +134,7 @@ def lazy_get_favicon_url(
 ) -> Callable[[str, str], Any]:
     """Lazily get the URL to a favicon image."""
 
+    @cache_memoize(3600)
     def _get_favicon_url(size: int, rel: str) -> Any:
         from favicon.models import Favicon  # noqa
 
@@ -308,7 +310,7 @@ def path_and_rename(instance, filename: str, upload_to: str = "files") -> str:
     _, ext = os.path.splitext(filename)
 
     # set filename as random string
-    new_filename = f"{uuid4().hex}.{ext}"
+    new_filename = f"{uuid4().hex}{ext}"
 
     # Create upload directory if necessary
     os.makedirs(os.path.join(settings.MEDIA_ROOT, upload_to), exist_ok=True)
@@ -323,6 +325,14 @@ def custom_information_processor(request: HttpRequest) -> dict:
 
     return {
         "FOOTER_MENU": CustomMenu.get_default("footer"),
+        "ALTERNATIVE_LOGIN_VIEWS_LIST": [
+            a[0]
+            for a in settings.ALTERNATIVE_LOGIN_VIEWS
+            if a[0] in settings.AUTHENTICATION_BACKENDS
+        ],
+        "ALTERNATIVE_LOGIN_VIEWS": [
+            a for a in settings.ALTERNATIVE_LOGIN_VIEWS if a[0] in settings.AUTHENTICATION_BACKENDS
+        ],
     }
 
 
@@ -349,3 +359,31 @@ def handle_uploaded_file(f, filename: str):
     with open(filename, "wb+") as destination:
         for chunk in f.chunks():
             destination.write(chunk)
+
+
+@cache_memoize(3600)
+def get_content_type_by_perm(perm: str) -> Union["ContentType", None]:
+    from django.contrib.contenttypes.models import ContentType  # noqa
+
+    try:
+        return ContentType.objects.get(
+            app_label=perm.split(".", 1)[0], permission__codename=perm.split(".", 1)[1]
+        )
+    except ContentType.DoesNotExist:
+        return None
+
+
+@cache_memoize(3600)
+def queryset_rules_filter(
+    obj: Union[HttpRequest, Model], queryset: QuerySet, perm: str
+) -> QuerySet:
+    """Filter queryset by user and permission."""
+    wanted_objects = set()
+    if isinstance(obj, HttpRequest) and hasattr(obj, "user"):
+        obj = obj.user
+
+    for item in queryset:
+        if obj.has_perm(perm, item):
+            wanted_objects.add(item.pk)
+
+    return queryset.filter(pk__in=wanted_objects)
diff --git a/aleksis/core/util/predicates.py b/aleksis/core/util/predicates.py
index 975273d7d934ae41df8ecefb494b121ed69b2a94..d107b425bab206b9a1a0c57d0cb4a4e997a82d34 100644
--- a/aleksis/core/util/predicates.py
+++ b/aleksis/core/util/predicates.py
@@ -8,8 +8,9 @@ from guardian.shortcuts import get_objects_for_user
 from rules import predicate
 
 from ..models import Group
-from .core_helpers import get_site_preferences
+from .core_helpers import get_content_type_by_perm, get_site_preferences
 from .core_helpers import has_person as has_person_helper
+from .core_helpers import queryset_rules_filter
 
 
 def permission_validator(request: HttpRequest, perm: str) -> bool:
@@ -57,14 +58,17 @@ def has_any_object(perm: str, klass):
     """Check if has any object.
 
     Build predicate which checks whether a user has access
-    to objects with the provided permission.
+    to objects with the provided permission or rule.
     """
     name = f"has_any_object:{perm}"
 
     @predicate(name)
     def fn(user: User) -> bool:
-        objs = get_objects_for_user(user, perm, klass)
-        return len(objs) > 0
+        ct_perm = get_content_type_by_perm(perm)
+        if ct_perm and ct_perm.model_class() == klass:
+            return get_objects_for_user(user, perm, klass).exists()
+        else:
+            return queryset_rules_filter(user, klass.objects.all(), perm).exists()
 
     return fn
 
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index e854fd0f8b60c549e03022414fa0686342b2b193..33181720258981e79dc04f13cf02fcc0133072de 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -168,12 +168,8 @@ def person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
     # Get groups where person is member of
     groups = Group.objects.filter(members=person)
 
-    # Get filter
-    groups_filter = GroupFilter(request.GET, queryset=groups)
-    context["groups_filter"] = groups_filter
-
     # Build table
-    groups_table = GroupsTable(groups_filter.qs)
+    groups_table = GroupsTable(groups)
     RequestConfig(request).configure(groups_table)
     context["groups_table"] = groups_table
 
@@ -194,24 +190,16 @@ def group(request: HttpRequest, id_: int) -> HttpResponse:
     # Get members
     members = group.members.filter(is_active=True)
 
-    # Get filter
-    members_filter = PersonFilter(request.GET, queryset=members)
-    context["members_filter"] = members_filter
-
     # Build table
-    members_table = PersonsTable(members_filter.qs)
+    members_table = PersonsTable(members)
     RequestConfig(request).configure(members_table)
     context["members_table"] = members_table
 
     # Get owners
     owners = group.owners.filter(is_active=True)
 
-    # Get filter
-    owners_filter = PersonFilter(request.GET, queryset=owners)
-    context["owners_filter"] = owners_filter
-
     # Build table
-    owners_table = PersonsTable(owners_filter.qs)
+    owners_table = PersonsTable(owners)
     RequestConfig(request).configure(owners_table)
     context["owners_table"] = owners_table
 
@@ -234,7 +222,7 @@ def groups(request: HttpRequest) -> HttpResponse:
     context["groups_filter"] = groups_filter
 
     # Build table
-    groups_table = GroupsTable(group_filter.qs)
+    groups_table = GroupsTable(groups_filter.qs)
     RequestConfig(request).configure(groups_table)
     context["groups_table"] = groups_table
 
@@ -308,23 +296,21 @@ def edit_person(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse
 
     if id_:
         # Edit form for existing group
-        edit_person_form = EditPersonForm(request.POST or None, instance=person)
+        edit_person_form = EditPersonForm(
+            request.POST or None, request.FILES or None, instance=person
+        )
     else:
         # Empty form to create a new group
         if request.user.has_perm("core.create_person"):
-            edit_person_form = EditPersonForm(request.POST or None)
+            edit_person_form = EditPersonForm(request.POST or None, request.FILES or None)
         else:
             raise PermissionDenied()
-
     if request.method == "POST":
         if edit_person_form.is_valid():
             with reversion.create_revision():
                 edit_person_form.save(commit=True)
             messages.success(request, _("The person has been saved."))
 
-            # Redirect to self to ensure post-processed data is displayed
-            return redirect("edit_person_by_id", id_=person.id)
-
     context["edit_person_form"] = edit_person_form
 
     return render(request, "core/person/edit.html", context)
@@ -385,6 +371,7 @@ class SystemStatus(MainView, PermissionRequiredMixin):
 
     def get(self, request, *args, **kwargs):
         status_code = 500 if self.errors else 200
+        task_results = []
 
         if "django_celery_results" in settings.INSTALLED_APPS:
             from django_celery_results.models import TaskResult  # noqa
@@ -392,11 +379,12 @@ class SystemStatus(MainView, PermissionRequiredMixin):
 
             if inspect().registered_tasks():
                 job_list = list(inspect().registered_tasks().values())[0]
-                results = []
                 for job in job_list:
-                    results.append(TaskResult.objects.filter(task_name=job).last())
+                    task_results.append(
+                        TaskResult.objects.filter(task_name=job).order_by("date_done").last()
+                    )
 
-        context = {"plugins": self.plugins, "status_code": status_code}
+        context = {"plugins": self.plugins, "status_code": status_code, "tasks": task_results}
         return self.render_to_response(context, status=status_code)
 
 
diff --git a/apps/official/AlekSIS-App-Chronos b/apps/official/AlekSIS-App-Chronos
index b081e4d32922d38e4f6229f33e7cecf5a1b408e0..a931c49771c04a03fba7a724cdb26fa0e4e5e9ec 160000
--- a/apps/official/AlekSIS-App-Chronos
+++ b/apps/official/AlekSIS-App-Chronos
@@ -1 +1 @@
-Subproject commit b081e4d32922d38e4f6229f33e7cecf5a1b408e0
+Subproject commit a931c49771c04a03fba7a724cdb26fa0e4e5e9ec
diff --git a/apps/official/AlekSIS-App-DashboardFeeds b/apps/official/AlekSIS-App-DashboardFeeds
index 85814a4f6c4fc1d94a853b46be8544c11b5767ee..7a8c8a235b96e1ad023fceebbf937ca3d5831e8f 160000
--- a/apps/official/AlekSIS-App-DashboardFeeds
+++ b/apps/official/AlekSIS-App-DashboardFeeds
@@ -1 +1 @@
-Subproject commit 85814a4f6c4fc1d94a853b46be8544c11b5767ee
+Subproject commit 7a8c8a235b96e1ad023fceebbf937ca3d5831e8f
diff --git a/apps/official/AlekSIS-App-Hjelp b/apps/official/AlekSIS-App-Hjelp
index 31500a0580b6839122df35f114e471334903d26e..fb7b67ec20ac9dd9ae4b34e3cb615c1045393662 160000
--- a/apps/official/AlekSIS-App-Hjelp
+++ b/apps/official/AlekSIS-App-Hjelp
@@ -1 +1 @@
-Subproject commit 31500a0580b6839122df35f114e471334903d26e
+Subproject commit fb7b67ec20ac9dd9ae4b34e3cb615c1045393662
diff --git a/apps/official/AlekSIS-App-LDAP b/apps/official/AlekSIS-App-LDAP
index 487a3423abc8b8bc8a4d89e474336c76b5cafa61..019a7de78614ab8f41e4e236e6c7bdb11e1ec6af 160000
--- a/apps/official/AlekSIS-App-LDAP
+++ b/apps/official/AlekSIS-App-LDAP
@@ -1 +1 @@
-Subproject commit 487a3423abc8b8bc8a4d89e474336c76b5cafa61
+Subproject commit 019a7de78614ab8f41e4e236e6c7bdb11e1ec6af
diff --git a/apps/official/AlekSIS-App-Untis b/apps/official/AlekSIS-App-Untis
index 0b417dfef095fb7a52f03301abb66066a841b467..6587ab6aa9120a388ffae84acd9777ae1bd75d1f 160000
--- a/apps/official/AlekSIS-App-Untis
+++ b/apps/official/AlekSIS-App-Untis
@@ -1 +1 @@
-Subproject commit 0b417dfef095fb7a52f03301abb66066a841b467
+Subproject commit 6587ab6aa9120a388ffae84acd9777ae1bd75d1f
diff --git a/ci/deploy.yml b/ci/deploy.yml
index d01e23e4f3436bc8dd4849d283038591157e9668..249e4c3333cf7c8800600a7801727110305a487e 100644
--- a/ci/deploy.yml
+++ b/ci/deploy.yml
@@ -1,16 +1,3 @@
-pages:
-  stage: deploy
-  before_script:
-    - cp -r .tox/screenshots/firefox docs/screenshots
-  script:
-    - export LC_ALL=en_GB.utf8
-    - tox -e docs -- BUILDDIR=../public/docs
-  artifacts:
-    paths:
-    - public/
-  only:
-    - master
-
 deploy_demo-master:
   stage: deploy
   environment:
diff --git a/ci/pages.yml b/ci/pages.yml
new file mode 100644
index 0000000000000000000000000000000000000000..31d8866e1d1c1b665d12ce15da9a7c918440aa7a
--- /dev/null
+++ b/ci/pages.yml
@@ -0,0 +1,12 @@
+pages:
+  stage: deploy
+  before_script:
+    - cp -r .tox/screenshots/firefox docs/screenshots
+  script:
+    - export LC_ALL=en_GB.utf8
+    - tox -e docs -- BUILDDIR=../public/docs
+  artifacts:
+    paths:
+    - public/
+  only:
+    - master
diff --git a/dev.sh b/dev.sh
index 33c36f4748de2c5ceb2b3c3eb812e12d11013c67..fa77b4c47f287c48d7839801223bbeddac5c88e1 100755
--- a/dev.sh
+++ b/dev.sh
@@ -28,7 +28,7 @@ case "$1" in
 	locales="-l ar -l de_DE -l fr -l nb_NO -l tr_TR -l la"
 	for d in aleksis/core apps/official/*/aleksis/apps/*; do
 		echo; echo "Entering $d."
-		poetry run sh -c "cd $d; $manage_py makemessages --no-wrap -i static $locales"
+		poetry run sh -c "cd $d; $manage_py makemessages --no-wrap -e html,txt,py,email -i static $locales"
 		poetry run sh -c "cd $d; $manage_py makemessages --no-wrap -d djangojs $locales"
 	done
 	exit
diff --git a/docs/admin/01_config.rst b/docs/admin/01_config.rst
index 089c4416b031f7cf78d92ef8a57e3d86084f9094..a8e593b4afb1bf98b980c1bb548a75fb513b6bbf 100644
--- a/docs/admin/01_config.rst
+++ b/docs/admin/01_config.rst
@@ -27,25 +27,24 @@ configuration by topic.
 
 A configuration file might look like this::
 
-  [default]
   secret_key = "VerySecretKeyForSessionSecurity"
 
-  [default.http]
+  [http]
   allowed_hosts = [ "aleksis.myschool.example.com", "localhost" ]
 
-  [default.database]
+  [database]
   name = "aleksis"
   user = "aleksis"
   password = "SuperSecretPassword"
 
-  [default.caching]
+  [caching]
   memcached = { enabled = true, address = "127.0.0.1" }
 
 The `secret_key` setting above defines a single value. The following `http`
 section defines a table (cf. a dictionary) in one way, and you can see the
 second form of such a table in the `memcached` setting (we could as well
-have defined another section called `[default.caching.memcached]` and placed
-`enabled` and `address` below it as scalars).
+have defined another section and placed `enabled` and `address` below it
+as scalars).
 
 This can be a bit confusing, so this documentation will explain how to
 configure AlekSIS on a per-feature basis.
diff --git a/docs/admin/02_ldap.rst b/docs/admin/02_ldap.rst
index 1239d43e1b45d255100b249c417b44bd5de67b51..5ef33259b580fc68909c58f4b4a8b1fd507fcd4b 100644
--- a/docs/admin/02_ldap.rst
+++ b/docs/admin/02_ldap.rst
@@ -25,10 +25,10 @@ configuration file. For example, add something like the following to your
 configuration (normally in `/etc/aleksis`; you can either append to an
 existing file or add a new one)::
 
-  [default.ldap]
+  [ldap]
   uri = "ldaps://ldap.myschool.edu"
   bind = { dn = "cn=reader,dc=myschool,dc=edu", password = "secret" }
 
-  [default.ldap.users]
+  [ldap.users]
   search = { base = "ou=people,dc=myschool,dc=edu", filter = "(uid=%(user)s)" }
   map = { first_name = "givenName", last_name = "sn", email = "mail" }
diff --git a/docs/admin/03_psql.rst b/docs/admin/03_psql.rst
index 8c544041fdce1dc6ee83d3311526bb3561dcb487..6d5ab57ae3b157ca906f3cfb7df1d3897efdfbd7 100644
--- a/docs/admin/03_psql.rst
+++ b/docs/admin/03_psql.rst
@@ -32,7 +32,7 @@ Configure AlekSIS to use PostgreSQL
 
 Fill in the configuration under `/etc/aleksis/aleksis.toml` (or a file with any other name in this directory)::
 
-  [default.database]
+  [database]
   host = "localhost"
   name = "aleksis"
   username = "aleksis"
diff --git a/poetry.lock b/poetry.lock
index cc0f45102b25299110e3d77f897bc120b8c8b49a..0503c4d2afff52bbe5c875a3e725c650a4205d40 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -12,7 +12,7 @@ description = "Low-level AMQP client for Python (fork of amqplib)."
 name = "amqp"
 optional = true
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "2.6.0"
+version = "2.6.1"
 
 [package.dependencies]
 vine = ">=1.1.3,<5.0.0a1"
@@ -51,13 +51,13 @@ description = "Classes Without Boilerplate"
 name = "attrs"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "19.3.0"
+version = "20.2.0"
 
 [package.extras]
-azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
-dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
-docs = ["sphinx", "zope.interface"]
-tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
+dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "sphinx-rtd-theme", "pre-commit"]
+docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
+tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
+tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
 
 [[package]]
 category = "main"
@@ -91,10 +91,12 @@ description = "Screen-scraping library"
 name = "beautifulsoup4"
 optional = false
 python-versions = "*"
-version = "4.9.1"
+version = "4.9.3"
 
 [package.dependencies]
-soupsieve = [">1.2", "<2.0"]
+[package.dependencies.soupsieve]
+python = ">=3.0"
+version = ">1.2"
 
 [package.extras]
 html5lib = ["html5lib"]
@@ -134,7 +136,7 @@ description = "An easy safelist-based HTML-sanitizing tool."
 name = "bleach"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "3.1.5"
+version = "3.2.1"
 
 [package.dependencies]
 packaging = "*"
@@ -166,11 +168,10 @@ description = "Distributed Task Queue."
 name = "celery"
 optional = true
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "4.4.6"
+version = "4.4.7"
 
 [package.dependencies]
 billiard = ">=3.6.3.0,<4.0"
-future = ">=0.18.0"
 kombu = ">=4.6.10,<4.7"
 pytz = ">0.0-dev"
 vine = "1.3.0"
@@ -234,7 +235,7 @@ description = "Drop in, configurable, dependency-free progress bars for your Dja
 name = "celery-progress"
 optional = false
 python-versions = "*"
-version = "0.0.10"
+version = "0.0.12"
 
 [package.extras]
 rabbitmq = ["channels-rabbitmq"]
@@ -258,7 +259,7 @@ python-versions = "*"
 version = "3.0.4"
 
 [[package]]
-category = "main"
+category = "dev"
 description = "Composable command line interface toolkit"
 name = "click"
 optional = false
@@ -272,7 +273,7 @@ marker = "platform_system == \"Windows\" or sys_platform == \"win32\""
 name = "colorama"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "0.4.3"
+version = "0.4.4"
 
 [[package]]
 category = "main"
@@ -302,7 +303,7 @@ description = "Code coverage measurement for Python"
 name = "coverage"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
-version = "5.1"
+version = "5.3"
 
 [package.extras]
 toml = ["toml"]
@@ -321,10 +322,10 @@ description = "A high-level Python Web framework that encourages rapid developme
 name = "django"
 optional = false
 python-versions = ">=3.6"
-version = "3.0.7"
+version = "3.1.2"
 
 [package.dependencies]
-asgiref = ">=3.2,<4.0"
+asgiref = ">=3.2.10,<3.3.0"
 pytz = "*"
 sqlparse = ">=0.2.2"
 
@@ -406,11 +407,11 @@ description = "Database-backed Periodic Tasks."
 name = "django-celery-beat"
 optional = true
 python-versions = "*"
-version = "2.0.0"
+version = "2.1.0"
 
 [package.dependencies]
-Django = ">=1.11.17"
-celery = "*"
+Django = ">=2.2"
+celery = ">=4.4,<6.0"
 django-timezone-field = ">=4.0,<5.0"
 python-crontab = ">=2.3.4"
 
@@ -444,7 +445,7 @@ description = "Django admin CKEditor integration."
 name = "django-ckeditor"
 optional = false
 python-versions = "*"
-version = "5.9.0"
+version = "6.0.0"
 
 [package.dependencies]
 django-js-asset = ">=1.2.2"
@@ -455,7 +456,7 @@ description = "simple color field for your models with a nice color-picker in th
 name = "django-colorfield"
 optional = false
 python-versions = "*"
-version = "0.3.1"
+version = "0.3.2"
 
 [[package]]
 category = "main"
@@ -488,7 +489,7 @@ description = "Dynamic global and instance settings for your django project"
 name = "django-dynamic-preferences"
 optional = false
 python-versions = "*"
-version = "1.9"
+version = "1.10.1"
 
 [package.dependencies]
 django = ">=1.11"
@@ -500,11 +501,12 @@ category = "main"
 description = "Yet another Django audit log app, hopefully the simplest one."
 name = "django-easy-audit"
 optional = false
-python-versions = "*"
-version = "1.2.3a5"
+python-versions = ">=3.5"
+version = "1.3.0"
 
 [package.dependencies]
 beautifulsoup4 = "*"
+django = ">=2.2,<3.2"
 
 [[package]]
 category = "main"
@@ -524,7 +526,7 @@ description = "Django-filter is a reusable Django application for allowing users
 name = "django-filter"
 optional = false
 python-versions = ">=3.5"
-version = "2.3.0"
+version = "2.4.0"
 
 [package.dependencies]
 Django = ">=2.2"
@@ -583,7 +585,7 @@ description = "Run checks on services like databases, queue servers, celery proc
 name = "django-health-check"
 optional = false
 python-versions = "*"
-version = "3.12.1"
+version = "3.14.3"
 
 [package.dependencies]
 django = ">=1.11"
@@ -594,7 +596,7 @@ description = "A reusable app for cropping images easily and non-destructively i
 name = "django-image-cropping"
 optional = false
 python-versions = ">=3.5"
-version = "1.4.0"
+version = "1.5.0"
 
 [package.dependencies]
 django-appconf = ">=1.0.2"
@@ -613,7 +615,7 @@ description = "A Django utility application that returns client's real IP addres
 name = "django-ipware"
 optional = false
 python-versions = "*"
-version = "2.1.0"
+version = "3.0.1"
 
 [[package]]
 category = "main"
@@ -652,7 +654,7 @@ description = "django-maintenance-mode shows a 503 error page when maintenance-m
 name = "django-maintenance-mode"
 optional = false
 python-versions = "*"
-version = "0.14.0"
+version = "0.15.0"
 
 [[package]]
 category = "main"
@@ -660,7 +662,7 @@ description = "Material design for django forms and admin"
 name = "django-material"
 optional = false
 python-versions = "*"
-version = "1.6.7"
+version = "1.7.1"
 
 [package.dependencies]
 six = "*"
@@ -690,10 +692,10 @@ description = "A pluggable framework for adding two-factor authentication to Dja
 name = "django-otp"
 optional = false
 python-versions = "*"
-version = "0.9.3"
+version = "1.0.1"
 
 [package.dependencies]
-django = ">=1.11"
+django = ">=2.2"
 
 [package.extras]
 qrcode = ["qrcode"]
@@ -704,12 +706,11 @@ description = "A django-otp plugin that verifies YubiKey OTP tokens."
 name = "django-otp-yubikey"
 optional = false
 python-versions = "*"
-version = "0.5.2"
+version = "1.0.0"
 
 [package.dependencies]
 YubiOTP = ">=0.2.2"
-django-otp = ">=0.5.0"
-six = ">=1.10.0"
+django-otp = ">=1.0.0"
 
 [[package]]
 category = "main"
@@ -723,6 +724,10 @@ version = "3.0.1"
 Django = ">=1.11.3"
 babel = "*"
 
+[package.dependencies.phonenumbers]
+optional = true
+version = ">=7.0.2"
+
 [package.extras]
 phonenumbers = ["phonenumbers (>=7.0.2)"]
 phonenumberslite = ["phonenumberslite (>=7.0.2)"]
@@ -733,10 +738,10 @@ description = "Seamless polymorphic inheritance for Django models"
 name = "django-polymorphic"
 optional = false
 python-versions = "*"
-version = "2.1.2"
+version = "3.0.0"
 
 [package.dependencies]
-Django = ">=1.11"
+Django = ">=2.1"
 
 [[package]]
 category = "main"
@@ -744,7 +749,7 @@ description = "A Django app to include a manifest.json and Service Worker instan
 name = "django-pwa"
 optional = false
 python-versions = "*"
-version = "1.0.9"
+version = "1.0.10"
 
 [package.dependencies]
 django = ">=1.8"
@@ -754,11 +759,11 @@ category = "main"
 description = "Render a particular block from a template to a string."
 name = "django-render-block"
 optional = false
-python-versions = "*"
-version = "0.6"
+python-versions = ">=3.5"
+version = "0.8.1"
 
 [package.dependencies]
-django = ">=1.11"
+django = ">=2.2"
 
 [[package]]
 category = "main"
@@ -766,7 +771,7 @@ description = "An extension to the Django web framework that provides version co
 name = "django-reversion"
 optional = false
 python-versions = ">=3.6"
-version = "3.0.7"
+version = "3.0.8"
 
 [package.dependencies]
 django = ">=1.11"
@@ -777,7 +782,7 @@ description = "SASS processor to compile SCSS files into *.css, while rendering,
 name = "django-sass-processor"
 optional = false
 python-versions = "*"
-version = "0.8"
+version = "0.8.2"
 
 [package.extras]
 dev = ["libsass (>=0.13)"]
@@ -812,11 +817,11 @@ description = "Mypy stubs for Django"
 name = "django-stubs"
 optional = false
 python-versions = ">=3.6"
-version = "1.5.0"
+version = "1.6.0"
 
 [package.dependencies]
 django = "*"
-mypy = ">=0.770,<0.780"
+mypy = ">=0.782,<0.790"
 typing-extensions = "*"
 
 [[package]]
@@ -825,7 +830,7 @@ description = "Table/data-grid framework for Django"
 name = "django-tables2"
 optional = false
 python-versions = "*"
-version = "2.3.1"
+version = "2.3.2"
 
 [package.dependencies]
 Django = ">=1.11"
@@ -863,12 +868,12 @@ description = "Complete Two-Factor Authentication for Django"
 name = "django-two-factor-auth"
 optional = false
 python-versions = "*"
-version = "1.11.0"
+version = "1.13"
 
 [package.dependencies]
-Django = ">=1.11"
+Django = ">=2.2"
 django-formtools = "*"
-django-otp = ">=0.6.0,<0.99"
+django-otp = ">=0.8.0"
 django-phonenumber-field = ">=1.1.0,<3.99"
 qrcode = ">=4.0.0,<6.99"
 
@@ -941,30 +946,29 @@ description = "The dynamic configurator for your Python Project"
 name = "dynaconf"
 optional = false
 python-versions = "*"
-version = "2.2.3"
+version = "3.1.2"
 
 [package.dependencies]
-click = "*"
-python-box = "<4.0.0"
-python-dotenv = "*"
-toml = "*"
+[package.dependencies.configobj]
+optional = true
+version = "*"
 
-[package.dependencies.PyYAML]
+[package.dependencies."ruamel.yaml"]
 optional = true
 version = "*"
 
-[package.dependencies.configobj]
+[package.dependencies.toml]
 optional = true
 version = "*"
 
 [package.extras]
-all = ["redis", "pyyaml", "configobj", "hvac"]
+all = ["redis", "ruamel.yaml", "configobj", "hvac"]
 configobj = ["configobj"]
 ini = ["configobj"]
 redis = ["redis"]
 toml = ["toml"]
 vault = ["hvac"]
-yaml = ["pyyaml"]
+yaml = ["ruamel.yaml"]
 
 [[package]]
 category = "main"
@@ -983,8 +987,8 @@ category = "main"
 description = "Faker is a Python package that generates fake data for you."
 name = "faker"
 optional = false
-python-versions = ">=3.4"
-version = "4.1.1"
+python-versions = ">=3.5"
+version = "4.14.0"
 
 [package.dependencies]
 python-dateutil = ">=2.4"
@@ -996,7 +1000,7 @@ description = "the modular source code checker: pep8 pyflakes and co"
 name = "flake8"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
-version = "3.8.3"
+version = "3.8.4"
 
 [package.dependencies]
 mccabe = ">=0.6.0,<0.7.0"
@@ -1027,7 +1031,7 @@ description = "flake8 plugin to call black as a code style validator"
 name = "flake8-black"
 optional = false
 python-versions = "*"
-version = "0.2.0"
+version = "0.2.1"
 
 [package.dependencies]
 black = "*"
@@ -1084,18 +1088,15 @@ description = "flake8 plugin that integrates isort ."
 name = "flake8-isort"
 optional = false
 python-versions = "*"
-version = "3.0.0"
+version = "4.0.0"
 
 [package.dependencies]
-flake8 = ">=3.2.1"
-testfixtures = "*"
-
-[package.dependencies.isort]
-extras = ["pyproject"]
-version = ">=4.3.5"
+flake8 = ">=3.2.1,<4"
+isort = ">=4.3.5,<6"
+testfixtures = ">=6.8.0,<7"
 
 [package.extras]
-test = ["pytest"]
+test = ["pytest (>=4.0.2,<6)", "toml"]
 
 [[package]]
 category = "dev"
@@ -1133,14 +1134,6 @@ version = "0.0.13"
 flake8 = ">=3.0.0"
 restructuredtext_lint = "*"
 
-[[package]]
-category = "main"
-description = "Clean single-source support for Python 3 and 2"
-name = "future"
-optional = true
-python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
-version = "0.18.2"
-
 [[package]]
 category = "dev"
 description = "Git Object Database"
@@ -1158,7 +1151,7 @@ description = "Python Git Library"
 name = "gitpython"
 optional = false
 python-versions = ">=3.4"
-version = "3.1.3"
+version = "3.1.9"
 
 [package.dependencies]
 gitdb = ">=4.0.1,<5"
@@ -1177,7 +1170,7 @@ description = "Internationalized Domain Names in Applications (IDNA)"
 name = "idna"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "2.9"
+version = "2.10"
 
 [[package]]
 category = "dev"
@@ -1194,7 +1187,7 @@ marker = "python_version < \"3.8\""
 name = "importlib-metadata"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
-version = "1.7.0"
+version = "2.0.0"
 
 [package.dependencies]
 zipp = ">=0.5"
@@ -1203,19 +1196,26 @@ zipp = ">=0.5"
 docs = ["sphinx", "rst.linker"]
 testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
 
+[[package]]
+category = "dev"
+description = "iniconfig: brain-dead simple config-ini parsing"
+name = "iniconfig"
+optional = false
+python-versions = "*"
+version = "1.1.1"
+
 [[package]]
 category = "dev"
 description = "A Python utility / library to sort Python imports."
 name = "isort"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "4.3.21"
+python-versions = ">=3.6,<4.0"
+version = "5.6.4"
 
 [package.extras]
-pipfile = ["pipreqs", "requirementslib"]
-pyproject = ["toml"]
-requirements = ["pipreqs", "pip-api"]
-xdg_home = ["appdirs (>=1.4.0)"]
+colors = ["colorama (>=0.4.3,<0.5.0)"]
+pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
+requirements_deprecated_finder = ["pipreqs", "pip-api"]
 
 [[package]]
 category = "dev"
@@ -1268,7 +1268,7 @@ description = "Sass for Python: A straightforward binding of libsass for Python.
 name = "libsass"
 optional = false
 python-versions = "*"
-version = "0.20.0"
+version = "0.20.1"
 
 [package.dependencies]
 six = "*"
@@ -1300,21 +1300,13 @@ optional = false
 python-versions = "*"
 version = "0.6.1"
 
-[[package]]
-category = "dev"
-description = "More routines for operating on iterables, beyond itertools"
-name = "more-itertools"
-optional = false
-python-versions = ">=3.5"
-version = "8.4.0"
-
 [[package]]
 category = "dev"
 description = "Optional static typing for Python"
 name = "mypy"
 optional = false
 python-versions = ">=3.5"
-version = "0.770"
+version = "0.782"
 
 [package.dependencies]
 mypy-extensions = ">=0.4.3,<0.5.0"
@@ -1357,8 +1349,8 @@ category = "dev"
 description = "Python Build Reasonableness"
 name = "pbr"
 optional = false
-python-versions = "*"
-version = "5.4.5"
+python-versions = ">=2.6"
+version = "5.5.1"
 
 [[package]]
 category = "main"
@@ -1374,7 +1366,7 @@ description = "PostgreSQL interface library"
 name = "pg8000"
 optional = false
 python-versions = ">=3.5"
-version = "1.15.3"
+version = "1.16.6"
 
 [package.dependencies]
 scramp = "1.2.0"
@@ -1385,7 +1377,7 @@ description = "Python version of Google's common library for parsing, formatting
 name = "phonenumbers"
 optional = false
 python-versions = "*"
-version = "8.12.6"
+version = "8.12.11"
 
 [[package]]
 category = "main"
@@ -1393,7 +1385,7 @@ description = "Python Imaging Library (Fork)"
 name = "pillow"
 optional = false
 python-versions = ">=3.5"
-version = "7.1.2"
+version = "7.2.0"
 
 [[package]]
 category = "dev"
@@ -1417,10 +1409,10 @@ description = "Cross-platform lib for process and system monitoring in Python."
 name = "psutil"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "5.7.0"
+version = "5.7.2"
 
 [package.extras]
-enum = ["enum34"]
+test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"]
 
 [[package]]
 category = "main"
@@ -1428,7 +1420,7 @@ description = "psycopg2 - Python-PostgreSQL Database Adapter"
 name = "psycopg2"
 optional = false
 python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
-version = "2.8.5"
+version = "2.8.6"
 
 [[package]]
 category = "dev"
@@ -1479,7 +1471,7 @@ description = "Python docstring style checker"
 name = "pydocstyle"
 optional = false
 python-versions = ">=3.5"
-version = "5.0.2"
+version = "5.1.1"
 
 [package.dependencies]
 snowballstemmer = "*"
@@ -1498,7 +1490,7 @@ description = "Pygments is a syntax highlighting package written in Python."
 name = "pygments"
 optional = false
 python-versions = ">=3.5"
-version = "2.6.1"
+version = "2.7.1"
 
 [[package]]
 category = "main"
@@ -1527,24 +1519,24 @@ description = "pytest: simple powerful testing with Python"
 name = "pytest"
 optional = false
 python-versions = ">=3.5"
-version = "5.4.3"
+version = "6.1.1"
 
 [package.dependencies]
 atomicwrites = ">=1.0"
 attrs = ">=17.4.0"
 colorama = "*"
-more-itertools = ">=4.0.0"
+iniconfig = "*"
 packaging = "*"
 pluggy = ">=0.12,<1.0"
-py = ">=1.5.0"
-wcwidth = "*"
+py = ">=1.8.2"
+toml = "*"
 
 [package.dependencies.importlib-metadata]
 python = "<3.8"
 version = ">=0.12"
 
 [package.extras]
-checkqa-mypy = ["mypy (v0.761)"]
+checkqa_mypy = ["mypy (0.780)"]
 testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
 
 [[package]]
@@ -1553,7 +1545,7 @@ description = "Pytest plugin for measuring coverage."
 name = "pytest-cov"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-version = "2.10.0"
+version = "2.10.1"
 
 [package.dependencies]
 coverage = ">=4.4"
@@ -1568,7 +1560,7 @@ description = "A Django plugin for pytest."
 name = "pytest-django"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "3.9.0"
+version = "3.10.0"
 
 [package.dependencies]
 pytest = ">=3.6"
@@ -1595,7 +1587,7 @@ description = "pytest-sugar is a plugin for pytest that changes the default look
 name = "pytest-sugar"
 optional = false
 python-versions = "*"
-version = "0.9.3"
+version = "0.9.4"
 
 [package.dependencies]
 packaging = ">=14.1"
@@ -1607,11 +1599,15 @@ category = "main"
 description = "Advanced Python dictionaries with dot notation access"
 name = "python-box"
 optional = false
-python-versions = "*"
-version = "3.4.6"
+python-versions = ">=3.6"
+version = "5.1.1"
 
 [package.extras]
-testing = ["pytest", "coverage (>=3.6)", "pytest-cov"]
+all = ["ruamel.yaml", "toml", "msgpack"]
+msgpack = ["msgpack"]
+pyyaml = ["pyyaml"]
+"ruamel.yaml" = ["ruamel.yaml"]
+toml = ["toml"]
 
 [[package]]
 category = "main"
@@ -1639,24 +1635,13 @@ version = "2.8.1"
 [package.dependencies]
 six = ">=1.5"
 
-[[package]]
-category = "main"
-description = "Add .env support to your django/flask apps in development and deployments"
-name = "python-dotenv"
-optional = false
-python-versions = "*"
-version = "0.13.0"
-
-[package.extras]
-cli = ["click (>=5.0)"]
-
 [[package]]
 category = "main"
 description = "Python modules for implementing LDAP clients"
 name = "python-ldap"
 optional = true
 python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
-version = "3.3.0"
+version = "3.3.1"
 
 [package.dependencies]
 pyasn1 = ">=0.3.7"
@@ -1682,7 +1667,7 @@ python-versions = "*"
 version = "2020.1"
 
 [[package]]
-category = "main"
+category = "dev"
 description = "YAML parser and emitter for Python"
 name = "pyyaml"
 optional = false
@@ -1724,7 +1709,7 @@ description = "Alternative regular expression module, to replace re."
 name = "regex"
 optional = false
 python-versions = "*"
-version = "2020.6.8"
+version = "2020.10.15"
 
 [[package]]
 category = "main"
@@ -1755,6 +1740,32 @@ version = "1.3.1"
 [package.dependencies]
 docutils = ">=0.11,<1.0"
 
+[[package]]
+category = "main"
+description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
+name = "ruamel.yaml"
+optional = false
+python-versions = "*"
+version = "0.16.12"
+
+[package.dependencies]
+[package.dependencies."ruamel.yaml.clib"]
+python = "<3.9"
+version = ">=0.1.2"
+
+[package.extras]
+docs = ["ryd"]
+jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
+
+[[package]]
+category = "main"
+description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
+marker = "platform_python_implementation == \"CPython\" and python_version < \"3.9\""
+name = "ruamel.yaml.clib"
+optional = false
+python-versions = "*"
+version = "0.2.2"
+
 [[package]]
 category = "main"
 description = "Awesome Django authorization, without the database"
@@ -1824,10 +1835,11 @@ version = "2.0.0"
 [[package]]
 category = "main"
 description = "A modern CSS selector implementation for Beautiful Soup."
+marker = "python_version >= \"3.0\""
 name = "soupsieve"
 optional = false
-python-versions = "*"
-version = "1.9.6"
+python-versions = ">=3.5"
+version = "2.0.1"
 
 [[package]]
 category = "main"
@@ -1835,7 +1847,7 @@ description = "A simple tool/library for working with SPDX license definitions."
 name = "spdx-license-list"
 optional = false
 python-versions = "*"
-version = "0.5.0"
+version = "0.5.1"
 
 [[package]]
 category = "dev"
@@ -1843,7 +1855,7 @@ description = "Python documentation generator"
 name = "sphinx"
 optional = false
 python-versions = ">=3.5"
-version = "3.1.1"
+version = "3.2.1"
 
 [package.dependencies]
 Jinja2 = ">=2.3"
@@ -1875,13 +1887,13 @@ description = "Type hints (PEP 484) support for the Sphinx autodoc extension"
 name = "sphinx-autodoc-typehints"
 optional = false
 python-versions = ">=3.5.2"
-version = "1.11.0"
+version = "1.11.1"
 
 [package.dependencies]
 Sphinx = ">=3.0"
 
 [package.extras]
-test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "dataclasses"]
+test = ["pytest (>=3.1.0)", "typing-extensions (>=3.5)", "sphobjinv (>=2.0)", "Sphinx (>=3.2.0)", "dataclasses"]
 type_comments = ["typed-ast (>=1.4.0)"]
 
 [[package]]
@@ -1965,11 +1977,11 @@ test = ["pytest"]
 
 [[package]]
 category = "main"
-description = "Non-validating SQL parser"
+description = "A non-validating SQL parser."
 name = "sqlparse"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-version = "0.3.1"
+python-versions = ">=3.5"
+version = "0.4.1"
 
 [[package]]
 category = "dev"
@@ -1977,11 +1989,15 @@ description = "Manage dynamic plugins for Python applications"
 name = "stevedore"
 optional = false
 python-versions = ">=3.6"
-version = "2.0.1"
+version = "3.2.2"
 
 [package.dependencies]
 pbr = ">=2.0.0,<2.1.0 || >2.1.0"
 
+[package.dependencies.importlib-metadata]
+python = "<3.8"
+version = ">=1.7.0"
+
 [[package]]
 category = "dev"
 description = "ANSII Color formatting for output in terminal."
@@ -1996,7 +2012,7 @@ description = "A collection of helpers and mock objects for unit tests and doc t
 name = "testfixtures"
 optional = false
 python-versions = "*"
-version = "6.14.1"
+version = "6.15.0"
 
 [package.extras]
 build = ["setuptools-git", "wheel", "twine"]
@@ -2051,7 +2067,7 @@ description = "Fast, Extensible Progress Meter"
 name = "tqdm"
 optional = false
 python-versions = ">=2.6, !=3.0.*, !=3.1.*"
-version = "4.46.1"
+version = "4.50.2"
 
 [package.extras]
 dev = ["py-make (>=0.1.0)", "twine", "argopt", "pydoc-markdown"]
@@ -2062,7 +2078,7 @@ description = "Twilio API client and TwiML generator"
 name = "twilio"
 optional = false
 python-versions = "*"
-version = "6.43.0"
+version = "6.46.0"
 
 [package.dependencies]
 PyJWT = ">=1.4.2"
@@ -2087,7 +2103,7 @@ description = "Backported and Experimental Type Hints for Python 3.5+"
 name = "typing-extensions"
 optional = false
 python-versions = "*"
-version = "3.7.4.2"
+version = "3.7.4.3"
 
 [[package]]
 category = "main"
@@ -2095,11 +2111,11 @@ description = "HTTP library with thread-safe connection pooling, file post, and
 name = "urllib3"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
-version = "1.25.9"
+version = "1.25.11"
 
 [package.extras]
 brotli = ["brotlipy (>=0.6.0)"]
-secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
+secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
 socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
 
 [[package]]
@@ -2110,14 +2126,6 @@ optional = true
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 version = "1.3.0"
 
-[[package]]
-category = "dev"
-description = "Measures the displayed width of unicode strings in a terminal"
-name = "wcwidth"
-optional = false
-python-versions = "*"
-version = "0.2.5"
-
 [[package]]
 category = "main"
 description = "Character encoding aliases for legacy web content"
@@ -2132,11 +2140,10 @@ description = "A library for verifying YubiKey OTP tokens, both locally and thro
 name = "yubiotp"
 optional = false
 python-versions = "*"
-version = "0.2.2.post1"
+version = "1.0.0.post1"
 
 [package.dependencies]
 pycryptodome = "*"
-six = "*"
 
 [[package]]
 category = "main"
@@ -2145,18 +2152,18 @@ marker = "python_version < \"3.8\""
 name = "zipp"
 optional = false
 python-versions = ">=3.6"
-version = "3.1.0"
+version = "3.3.1"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
-testing = ["jaraco.itertools", "func-timeout"]
+testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [extras]
 celery = ["Celery", "django-celery-results", "django-celery-beat", "django-celery-email", "celery-haystack"]
 ldap = ["django-auth-ldap"]
 
 [metadata]
-content-hash = "ab4755861d9926350d3e669b36d26ec7c31aa5b68004bb69ecb49eb13419b216"
+content-hash = "e651879b40f546919c6b7bd3f6cf1e0b1acf72e6e880d67f82cc23b95847eda9"
 python-versions = "^3.7"
 
 [metadata.files]
@@ -2165,8 +2172,8 @@ alabaster = [
     {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
 ]
 amqp = [
-    {file = "amqp-2.6.0-py2.py3-none-any.whl", hash = "sha256:bb68f8d2bced8f93ccfd07d96c689b716b3227720add971be980accfc2952139"},
-    {file = "amqp-2.6.0.tar.gz", hash = "sha256:24dbaff8ce4f30566bb88976b398e8c4e77637171af3af6f1b9650f48890e60b"},
+    {file = "amqp-2.6.1-py2.py3-none-any.whl", hash = "sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"},
+    {file = "amqp-2.6.1.tar.gz", hash = "sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21"},
 ]
 appdirs = [
     {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
@@ -2181,8 +2188,8 @@ atomicwrites = [
     {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
 ]
 attrs = [
-    {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
-    {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
+    {file = "attrs-20.2.0-py2.py3-none-any.whl", hash = "sha256:fce7fc47dfc976152e82d53ff92fa0407700c21acd20886a13777a0d20e655dc"},
+    {file = "attrs-20.2.0.tar.gz", hash = "sha256:26b54ddbbb9ee1d34d5d3668dd37d6cf74990ab23c828c2888dccdceee395594"},
 ]
 babel = [
     {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"},
@@ -2193,9 +2200,9 @@ bandit = [
     {file = "bandit-1.6.2.tar.gz", hash = "sha256:41e75315853507aa145d62a78a2a6c5e3240fe14ee7c601459d0df9418196065"},
 ]
 beautifulsoup4 = [
-    {file = "beautifulsoup4-4.9.1-py2-none-any.whl", hash = "sha256:e718f2342e2e099b640a34ab782407b7b676f47ee272d6739e60b8ea23829f2c"},
-    {file = "beautifulsoup4-4.9.1-py3-none-any.whl", hash = "sha256:a6237df3c32ccfaee4fd201c8f5f9d9df619b93121d01353a64a73ce8c6ef9a8"},
-    {file = "beautifulsoup4-4.9.1.tar.gz", hash = "sha256:73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7"},
+    {file = "beautifulsoup4-4.9.3-py2-none-any.whl", hash = "sha256:4c98143716ef1cb40bf7f39a8e3eec8f8b009509e74904ba3a7b315431577e35"},
+    {file = "beautifulsoup4-4.9.3-py3-none-any.whl", hash = "sha256:fff47e031e34ec82bf17e00da8f592fe7de69aeea38be00523c04623c04fb666"},
+    {file = "beautifulsoup4-4.9.3.tar.gz", hash = "sha256:84729e322ad1d5b4d25f805bfa05b902dd96450f43842c4e99067d5e1369eb25"},
 ]
 billiard = [
     {file = "billiard-3.6.3.0-py3-none-any.whl", hash = "sha256:bff575450859a6e0fbc2f9877d9b715b0bbc07c3565bb7ed2280526a0cdf5ede"},
@@ -2206,8 +2213,8 @@ black = [
     {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
 ]
 bleach = [
-    {file = "bleach-3.1.5-py2.py3-none-any.whl", hash = "sha256:2bce3d8fab545a6528c8fa5d9f9ae8ebc85a56da365c7f85180bfe96a35ef22f"},
-    {file = "bleach-3.1.5.tar.gz", hash = "sha256:3c4c520fdb9db59ef139915a5db79f8b51bc2a7257ea0389f30c846883430a4b"},
+    {file = "bleach-3.2.1-py2.py3-none-any.whl", hash = "sha256:9f8ccbeb6183c6e6cddea37592dfb0167485c1e3b13b3363bc325aa8bda3adbd"},
+    {file = "bleach-3.2.1.tar.gz", hash = "sha256:52b5919b81842b1854196eaae5ca29679a2f2e378905c346d3ca8227c2c66080"},
 ]
 "boolean.py" = [
     {file = "boolean.py-3.8-py2.py3-none-any.whl", hash = "sha256:d75da0fd0354425fa64f6bbc6cec6ae1485d0eec3447b73187ff8cbf9b572e26"},
@@ -2218,16 +2225,16 @@ calendarweek = [
     {file = "calendarweek-0.4.5.tar.gz", hash = "sha256:5b1788ca435022f9348fc81a718974e51dd85d080f9aa3dad717df70a1bc6e1f"},
 ]
 celery = [
-    {file = "celery-4.4.6-py2.py3-none-any.whl", hash = "sha256:ef17d7dffde7fc73ecab3a3b6389d93d3213bac53fa7f28e68e33647ad50b916"},
-    {file = "celery-4.4.6.tar.gz", hash = "sha256:fd77e4248bb1b7af5f7922dd8e81156f540306e3a5c4b1c24167c1f5f06025da"},
+    {file = "celery-4.4.7-py2.py3-none-any.whl", hash = "sha256:a92e1d56e650781fb747032a3997d16236d037c8199eacd5217d1a72893bca45"},
+    {file = "celery-4.4.7.tar.gz", hash = "sha256:d220b13a8ed57c78149acf82c006785356071844afe0b27012a4991d44026f9f"},
 ]
 celery-haystack = [
     {file = "celery-haystack-0.10.tar.gz", hash = "sha256:b6e2a3c70071bef0838ca1a7d9f14fae6c2ecf385704092e59b82147a1ee552e"},
     {file = "celery_haystack-0.10-py2.py3-none-any.whl", hash = "sha256:ec1f39050661e033f554de99cb9393c2e94427667ff5401f16393b2a68f888fc"},
 ]
 celery-progress = [
-    {file = "celery-progress-0.0.10.tar.gz", hash = "sha256:3f7b35e1e6c79eec38f5647b024aa74193d0a41d5b47ecbb85b66f9ca68d5261"},
-    {file = "celery_progress-0.0.10-py3-none-any.whl", hash = "sha256:90941bf3aaeac9333d554a2191fa6cd81ef323472329ace0dd77344ac6aab092"},
+    {file = "celery-progress-0.0.12.tar.gz", hash = "sha256:df61d61ac2b29e51b61a2cbd070d28b69f9f538d31e5f4b8076d9721251d6c59"},
+    {file = "celery_progress-0.0.12-py3-none-any.whl", hash = "sha256:b3727b1b65c79ec072513eb42f1903eaec64a75d2f691b5664fa660f2bd319ad"},
 ]
 certifi = [
     {file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
@@ -2242,8 +2249,7 @@ click = [
     {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
 ]
 colorama = [
-    {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
-    {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
+    {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
 ]
 colour = [
     {file = "colour-0.1.5-py2.py3-none-any.whl", hash = "sha256:33f6db9d564fadc16e59921a56999b79571160ce09916303d35346dddc17978c"},
@@ -2253,45 +2259,48 @@ configobj = [
     {file = "configobj-5.0.6.tar.gz", hash = "sha256:a2f5650770e1c87fb335af19a9b7eb73fc05ccf22144eb68db7d00cd2bcb0902"},
 ]
 coverage = [
-    {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"},
-    {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"},
-    {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"},
-    {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"},
-    {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"},
-    {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"},
-    {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"},
-    {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"},
-    {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"},
-    {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"},
-    {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"},
-    {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"},
-    {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"},
-    {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"},
-    {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"},
-    {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"},
-    {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"},
-    {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"},
-    {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"},
-    {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"},
-    {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"},
-    {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"},
-    {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"},
-    {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"},
-    {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"},
-    {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"},
-    {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"},
-    {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"},
-    {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"},
-    {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"},
-    {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"},
+    {file = "coverage-5.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:bd3166bb3b111e76a4f8e2980fa1addf2920a4ca9b2b8ca36a3bc3dedc618270"},
+    {file = "coverage-5.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9342dd70a1e151684727c9c91ea003b2fb33523bf19385d4554f7897ca0141d4"},
+    {file = "coverage-5.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:63808c30b41f3bbf65e29f7280bf793c79f54fb807057de7e5238ffc7cc4d7b9"},
+    {file = "coverage-5.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4d6a42744139a7fa5b46a264874a781e8694bb32f1d76d8137b68138686f1729"},
+    {file = "coverage-5.3-cp27-cp27m-win32.whl", hash = "sha256:86e9f8cd4b0cdd57b4ae71a9c186717daa4c5a99f3238a8723f416256e0b064d"},
+    {file = "coverage-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:7858847f2d84bf6e64c7f66498e851c54de8ea06a6f96a32a1d192d846734418"},
+    {file = "coverage-5.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:530cc8aaf11cc2ac7430f3614b04645662ef20c348dce4167c22d99bec3480e9"},
+    {file = "coverage-5.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:381ead10b9b9af5f64646cd27107fb27b614ee7040bb1226f9c07ba96625cbb5"},
+    {file = "coverage-5.3-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:71b69bd716698fa62cd97137d6f2fdf49f534decb23a2c6fc80813e8b7be6822"},
+    {file = "coverage-5.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d44bb3a652fed01f1f2c10d5477956116e9b391320c94d36c6bf13b088a1097"},
+    {file = "coverage-5.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1c6703094c81fa55b816f5ae542c6ffc625fec769f22b053adb42ad712d086c9"},
+    {file = "coverage-5.3-cp35-cp35m-win32.whl", hash = "sha256:cedb2f9e1f990918ea061f28a0f0077a07702e3819602d3507e2ff98c8d20636"},
+    {file = "coverage-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7f43286f13d91a34fadf61ae252a51a130223c52bfefb50310d5b2deb062cf0f"},
+    {file = "coverage-5.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:c851b35fc078389bc16b915a0a7c1d5923e12e2c5aeec58c52f4aa8085ac8237"},
+    {file = "coverage-5.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aac1ba0a253e17889550ddb1b60a2063f7474155465577caa2a3b131224cfd54"},
+    {file = "coverage-5.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2b31f46bf7b31e6aa690d4c7a3d51bb262438c6dcb0d528adde446531d0d3bb7"},
+    {file = "coverage-5.3-cp36-cp36m-win32.whl", hash = "sha256:c5f17ad25d2c1286436761b462e22b5020d83316f8e8fcb5deb2b3151f8f1d3a"},
+    {file = "coverage-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:aef72eae10b5e3116bac6957de1df4d75909fc76d1499a53fb6387434b6bcd8d"},
+    {file = "coverage-5.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:e8caf961e1b1a945db76f1b5fa9c91498d15f545ac0ababbe575cfab185d3bd8"},
+    {file = "coverage-5.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:29a6272fec10623fcbe158fdf9abc7a5fa032048ac1d8631f14b50fbfc10d17f"},
+    {file = "coverage-5.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2d43af2be93ffbad25dd959899b5b809618a496926146ce98ee0b23683f8c51c"},
+    {file = "coverage-5.3-cp37-cp37m-win32.whl", hash = "sha256:c3888a051226e676e383de03bf49eb633cd39fc829516e5334e69b8d81aae751"},
+    {file = "coverage-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9669179786254a2e7e57f0ecf224e978471491d660aaca833f845b72a2df3709"},
+    {file = "coverage-5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0203acd33d2298e19b57451ebb0bed0ab0c602e5cf5a818591b4918b1f97d516"},
+    {file = "coverage-5.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:582ddfbe712025448206a5bc45855d16c2e491c2dd102ee9a2841418ac1c629f"},
+    {file = "coverage-5.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0f313707cdecd5cd3e217fc68c78a960b616604b559e9ea60cc16795c4304259"},
+    {file = "coverage-5.3-cp38-cp38-win32.whl", hash = "sha256:78e93cc3571fd928a39c0b26767c986188a4118edc67bc0695bc7a284da22e82"},
+    {file = "coverage-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f264ba2701b8c9f815b272ad568d555ef98dfe1576802ab3149c3629a9f2221"},
+    {file = "coverage-5.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:50691e744714856f03a86df3e2bff847c2acede4c191f9a1da38f088df342978"},
+    {file = "coverage-5.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9361de40701666b034c59ad9e317bae95c973b9ff92513dd0eced11c6adf2e21"},
+    {file = "coverage-5.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:c1b78fb9700fc961f53386ad2fd86d87091e06ede5d118b8a50dea285a071c24"},
+    {file = "coverage-5.3-cp39-cp39-win32.whl", hash = "sha256:cb7df71de0af56000115eafd000b867d1261f786b5eebd88a0ca6360cccfaca7"},
+    {file = "coverage-5.3-cp39-cp39-win_amd64.whl", hash = "sha256:47a11bdbd8ada9b7ee628596f9d97fbd3851bd9999d398e9436bd67376dbece7"},
+    {file = "coverage-5.3.tar.gz", hash = "sha256:280baa8ec489c4f542f8940f9c4c2181f0306a8ee1a54eceba071a449fb870a0"},
 ]
 dj-database-url = [
     {file = "dj-database-url-0.5.0.tar.gz", hash = "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163"},
     {file = "dj_database_url-0.5.0-py2.py3-none-any.whl", hash = "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9"},
 ]
 django = [
-    {file = "Django-3.0.7-py3-none-any.whl", hash = "sha256:e1630333248c9b3d4e38f02093a26f1e07b271ca896d73097457996e0fae12e8"},
-    {file = "Django-3.0.7.tar.gz", hash = "sha256:5052b34b34b3425233c682e0e11d658fd6efd587d11335a0203d827224ada8f2"},
+    {file = "Django-3.1.2-py3-none-any.whl", hash = "sha256:c93c28ccf1d094cbd00d860e83128a39e45d2c571d3b54361713aaaf9a94cac4"},
+    {file = "Django-3.1.2.tar.gz", hash = "sha256:a2127ad0150ec6966655bedf15dbbff9697cc86d61653db2da1afa506c0b04cc"},
 ]
 django-any-js = [
     {file = "django-any-js-1.0.3.post0.tar.gz", hash = "sha256:1da88b44b861b0f54f6b8ea0eb4c7c4fa1a5772e9a4320532cd4e0871a4e23f7"},
@@ -2317,8 +2326,8 @@ django-cache-memoize = [
     {file = "django_cache_memoize-0.1.7-py2.py3-none-any.whl", hash = "sha256:bc7f53725558244af62197d0125732d7ec88ecc1281a3a2f37d77ae1a8c269d3"},
 ]
 django-celery-beat = [
-    {file = "django-celery-beat-2.0.0.tar.gz", hash = "sha256:fdf1255eecfbeb770c6521fe3e69989dfc6373cd5a7f0fe62038d37f80f47e48"},
-    {file = "django_celery_beat-2.0.0-py2.py3-none-any.whl", hash = "sha256:fe0b2a1b31d4a6234fea4b31986ddfd4644a48fab216ce1843f3ed0ddd2e9097"},
+    {file = "django-celery-beat-2.1.0.tar.gz", hash = "sha256:4eb0e8412e2e05ba0029912a6f80d1054731001eecbcb4d59688c4e07cf4d9d3"},
+    {file = "django_celery_beat-2.1.0-py2.py3-none-any.whl", hash = "sha256:8a169e11d96faed8b72d505ddbc70e7fe0b16cdc854df43cb209c153ed08d651"},
 ]
 django-celery-email = [
     {file = "django-celery-email-3.0.0.tar.gz", hash = "sha256:5546cbba80952cc3b8a0ffa4206ce90a4a996a7ffd1c385a2bdb65903ca18ece"},
@@ -2329,12 +2338,12 @@ django-celery-results = [
     {file = "django_celery_results-1.2.1.tar.gz", hash = "sha256:e390f70cc43bbc2cd7c8e4607dc29ab6211a2ab968f93677583f0160921f670c"},
 ]
 django-ckeditor = [
-    {file = "django-ckeditor-5.9.0.tar.gz", hash = "sha256:e4d112851a72c5bf8b586e1c674d34084cab16d28f2553ad15cc770d1e9639c7"},
-    {file = "django_ckeditor-5.9.0-py2.py3-none-any.whl", hash = "sha256:71c3c7bb46b0cbfb9712ef64af0d2a406eab233f44ecd7c42c24bdfa39ae3bde"},
+    {file = "django-ckeditor-6.0.0.tar.gz", hash = "sha256:29fd1a333cb9741ac2c3fd4e427a5c00115ed33a2389716a09af7656022dcdde"},
+    {file = "django_ckeditor-6.0.0-py2.py3-none-any.whl", hash = "sha256:cc2d377f1bdcd4ca1540caeebe85f7e2cd006198d57328ef6c718d3eaa5a0846"},
 ]
 django-colorfield = [
-    {file = "django-colorfield-0.3.1.tar.gz", hash = "sha256:5e3a720fd8dd46878b62d8d06b9ec81927d5ba8d2bc828ebaba49e7775f8393f"},
-    {file = "django_colorfield-0.3.1-py2-none-any.whl", hash = "sha256:5830fcc4b1ab3111e2e6c8a2d75e25c09e404cea80d9f50002b09f068c8854df"},
+    {file = "django-colorfield-0.3.2.tar.gz", hash = "sha256:f5dde281f4db8871eb5845aee614b4f1a47e7fd5b20476238793f519cd7bdf41"},
+    {file = "django_colorfield-0.3.2-py2-none-any.whl", hash = "sha256:e435ec31712f5e8b955cc7633aef1e49cc3b409c21dfcefeb2f6ef0e1cb69533"},
 ]
 django-dbbackup = [
     {file = "django-dbbackup-3.3.0.tar.gz", hash = "sha256:bb109735cae98b64ad084e5b461b7aca2d7b39992f10c9ed9435e3ebb6fb76c8"},
@@ -2344,20 +2353,20 @@ django-debug-toolbar = [
     {file = "django_debug_toolbar-2.2-py3-none-any.whl", hash = "sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"},
 ]
 django-dynamic-preferences = [
-    {file = "django-dynamic-preferences-1.9.tar.gz", hash = "sha256:407db27bf55d391c4c8a4944e0521f35eff82c2f2fd5a2fc843fb1b4cc1a31f4"},
-    {file = "django_dynamic_preferences-1.9-py2.py3-none-any.whl", hash = "sha256:a3c84696f0459d8d6d9c43374ff3db7daa59b46670b461bb954057d08af607e1"},
+    {file = "django-dynamic-preferences-1.10.1.tar.gz", hash = "sha256:e4b2bb7b2563c5064ba56dd76441c77e06b850ff1466a386a1cd308909a6c7de"},
+    {file = "django_dynamic_preferences-1.10.1-py2.py3-none-any.whl", hash = "sha256:9419fa925fd2cbb665269ae72059eb3058bf080913d853419b827e4e7a141902"},
 ]
 django-easy-audit = [
-    {file = "django-easy-audit-1.2.3a5.tar.gz", hash = "sha256:48fc3042760485eb9baae232c4ce21fb96476246e341ee7656a09db3ab3df047"},
-    {file = "django_easy_audit-1.2.3a5-py3-none-any.whl", hash = "sha256:32a60f1278f8b34aeda7c6f16a8f04bfab777584a38829e28e468ce0d5a45313"},
+    {file = "django-easy-audit-1.3.0.tar.gz", hash = "sha256:78b2909c8259b3140b81852adef00e9bea652cea04758cc46c63e0baab0bac84"},
+    {file = "django_easy_audit-1.3.0-py3-none-any.whl", hash = "sha256:d7d5738e5bec0e01027aca3eb5b91e1e57226dcb14d4f35b01a3e4f0b4973460"},
 ]
 django-favicon-plus-reloaded = [
     {file = "django-favicon-plus-reloaded-1.0.4.tar.gz", hash = "sha256:90c761c636a338e6e9fb1d086649d82095085f92cff816c9cf074607f28c85a5"},
     {file = "django_favicon_plus_reloaded-1.0.4-py3-none-any.whl", hash = "sha256:26e4316d41328a61ced52c7fc0ead795f0eb194d6a30311c34a9833c6fe30a7c"},
 ]
 django-filter = [
-    {file = "django-filter-2.3.0.tar.gz", hash = "sha256:11e63dd759835d9ba7a763926ffb2662cf8a6dcb4c7971a95064de34dbc7e5af"},
-    {file = "django_filter-2.3.0-py3-none-any.whl", hash = "sha256:616848eab6fc50193a1b3730140c49b60c57a3eda1f7fc57fa8505ac156c6c75"},
+    {file = "django-filter-2.4.0.tar.gz", hash = "sha256:84e9d5bb93f237e451db814ed422a3a625751cbc9968b484ecc74964a8696b06"},
+    {file = "django_filter-2.4.0-py3-none-any.whl", hash = "sha256:e00d32cebdb3d54273c48f4f878f898dced8d5dfaad009438fe61ebdf535ace1"},
 ]
 django-formtools = [
     {file = "django-formtools-2.2.tar.gz", hash = "sha256:c5272c03c1cd51b2375abf7397a199a3148a9fbbf2f100e186467a84025d13b2"},
@@ -2376,18 +2385,18 @@ django-haystack = [
     {file = "django_haystack-3.0b1-py3-none-any.whl", hash = "sha256:b83705e1cf8141cd1755fc6683ac65fea4e1281f4b4306bc9224af96495b0df3"},
 ]
 django-health-check = [
-    {file = "django-health-check-3.12.1.tar.gz", hash = "sha256:0563827e003d25fd4d9ebbd7467dea5f390435628d645aaa63f8889deaded73a"},
-    {file = "django_health_check-3.12.1-py2.py3-none-any.whl", hash = "sha256:9e6b7d93d4902901474efd4e25d31b5aaea7563b570c0260adce52cd3c3a9e36"},
+    {file = "django-health-check-3.14.3.tar.gz", hash = "sha256:6e84e7a3e5f1fcb82b7692833fa205bc274415850d333d5a50259de06080dfa8"},
+    {file = "django_health_check-3.14.3-py2.py3-none-any.whl", hash = "sha256:d5f5cbf3c34bc5ea297696e183c5084b0c15d3bd13d9eb997c25258241589c75"},
 ]
 django-image-cropping = [
-    {file = "django-image-cropping-1.4.0.tar.gz", hash = "sha256:6cc4a6bd8901e69b710caceea29b942fdb202da26626313cd9271ae989a83a52"},
-    {file = "django_image_cropping-1.4.0-py3-none-any.whl", hash = "sha256:fe6a139c6d5dfc480f2a1d4e7e3e928d5edaefc898e17be66bc5f73140762ad9"},
+    {file = "django-image-cropping-1.5.0.tar.gz", hash = "sha256:59744e8df88db7e46e37b526fc715fdde665d9efa345922745f50411a6dadb3f"},
+    {file = "django_image_cropping-1.5.0-py3-none-any.whl", hash = "sha256:81dbcabb6421c5a1e88fac9d96f336d6109a23dcb8fa6c678329d3688c9973c4"},
 ]
 django-impersonate = [
     {file = "django-impersonate-1.5.1.tar.gz", hash = "sha256:7c786ffaa7a5dd430f9277b53a64676c470b684eee5aa52c3b483298860d09b4"},
 ]
 django-ipware = [
-    {file = "django-ipware-2.1.0.tar.gz", hash = "sha256:a7c7a8fd019dbdc9c357e6e582f65034e897572fc79a7e467674efa8aef9d00b"},
+    {file = "django-ipware-3.0.1.tar.gz", hash = "sha256:73a640a5bff00aa7503a35e92e462001cfabb07d73d649c262f117423beee953"},
 ]
 django-js-asset = [
     {file = "django-js-asset-1.2.2.tar.gz", hash = "sha256:c163ae80d2e0b22d8fb598047cd0dcef31f81830e127cfecae278ad574167260"},
@@ -2401,12 +2410,12 @@ django-jsonstore = [
     {file = "django-jsonstore-0.4.1.tar.gz", hash = "sha256:d6e42152af3f924e4657c99e80144ba9a6410799256f6134b5a4e9fa4282ec10"},
 ]
 django-maintenance-mode = [
-    {file = "django-maintenance-mode-0.14.0.tar.gz", hash = "sha256:f3fef1760fdcda5e0bf6c2966aadc77eea6f328580a9c751920daba927281a68"},
-    {file = "django_maintenance_mode-0.14.0-py2-none-any.whl", hash = "sha256:b4cc24a469ed10897826a28f05d64e6166a58d130e4940ac124ce198cd4cc778"},
+    {file = "django-maintenance-mode-0.15.0.tar.gz", hash = "sha256:f8c500b077045db5444d4d4eb613fd1085b51f960d6d61b13b1cce461e1d0102"},
+    {file = "django_maintenance_mode-0.15.0-py3-none-any.whl", hash = "sha256:54b5afe3282d450bc4161461c5d518b8097cbb29a5fdd0baf1b8c3a1e5f90c08"},
 ]
 django-material = [
-    {file = "django-material-1.6.7.tar.gz", hash = "sha256:3cc68b34348634f019bf529f3e0b99b1474ab36ec9b50040f5e557b5b65add1d"},
-    {file = "django_material-1.6.7-py2.py3-none-any.whl", hash = "sha256:9da268532c92c270b512d9610c9723a07dbfea06db98434dac8aa1dd2910778f"},
+    {file = "django-material-1.7.1.tar.gz", hash = "sha256:77cfcc83da7724066b5b78bbb72cd4fbe752b38ffb20cb6ca36feb9657d9f19f"},
+    {file = "django_material-1.7.1-py2.py3-none-any.whl", hash = "sha256:2b70ef05d4c6805554e91efc81c34f71081a5287f016d0172b7368b0a465d759"},
 ]
 django-menu-generator = [
     {file = "django-menu-generator-1.0.4.tar.gz", hash = "sha256:ce71a5055c16933c8aff64fb36c21e5cf8b6d505733aceed1252f8b99369a378"},
@@ -2415,34 +2424,35 @@ django-middleware-global-request = [
     {file = "django-middleware-global-request-0.1.2.tar.gz", hash = "sha256:f6490759bc9f7dbde4001709554e29ca715daf847f2222914b4e47117dca9313"},
 ]
 django-otp = [
-    {file = "django-otp-0.9.3.tar.gz", hash = "sha256:d2390e61794bc10dea2fd949cbcfb7946e9ae4fb248df5494ccc4ef9ac50427e"},
-    {file = "django_otp-0.9.3-py3-none-any.whl", hash = "sha256:97849f7bf1b50c4c36a5845ab4d2e11dd472fa8e6bcc34fe18b6d3af6e4aa449"},
+    {file = "django-otp-1.0.1.tar.gz", hash = "sha256:fef1f2de9a52bc37e16211b98b4323e5b34fa24739116fbe3d1ff018c17ebea8"},
+    {file = "django_otp-1.0.1-py3-none-any.whl", hash = "sha256:2fb1c8dbd7e7ae76a65b63d89d3d8c3e1105a48bc29830b81c6e417a89380658"},
 ]
 django-otp-yubikey = [
-    {file = "django-otp-yubikey-0.5.2.tar.gz", hash = "sha256:f0b1881562fb42ee9f12c28d284cbdb90d1f0383f2d53a595373b080a19bc261"},
-    {file = "django_otp_yubikey-0.5.2-py2.py3-none-any.whl", hash = "sha256:26b12c763b37e99b95b8b8a54d06d8d54c3774eb26133a452f54558033de732b"},
+    {file = "django-otp-yubikey-1.0.0.tar.gz", hash = "sha256:fbd409277892229b7e3578faa4f63ea766e242659456939164c8f71b845287b6"},
+    {file = "django_otp_yubikey-1.0.0-py2.py3-none-any.whl", hash = "sha256:07743473024900c3b7a14647039f2cf66148cf6243d6aee0853ba45516c224a4"},
 ]
 django-phonenumber-field = [
     {file = "django-phonenumber-field-3.0.1.tar.gz", hash = "sha256:794ebbc3068a7af75aa72a80cb0cec67e714ff8409a965968040f1fd210b2d97"},
     {file = "django_phonenumber_field-3.0.1-py3-none-any.whl", hash = "sha256:1ab19f723928582fed412bd9844221fa4ff466276d8526b8b4a9913ee1487c5e"},
 ]
 django-polymorphic = [
-    {file = "django-polymorphic-2.1.2.tar.gz", hash = "sha256:6e08a76c91066635ccb7ef3ebbe9a0ad149febae6b30be2579716ec16d3c6461"},
-    {file = "django_polymorphic-2.1.2-py2.py3-none-any.whl", hash = "sha256:0a25058e95e5e99fe0beeabb8f4734effe242d7b5b77dca416fba9fd3062da6a"},
+    {file = "django-polymorphic-3.0.0.tar.gz", hash = "sha256:9d886f19f031d26bb1391c055ed9be06fb226a04a4cec1842b372c58873b3caa"},
+    {file = "django_polymorphic-3.0.0-py2.py3-none-any.whl", hash = "sha256:73b75eb44ea302bd32820f8661e469509d245ce7f7ff09cd2ad149e5c42034ff"},
 ]
 django-pwa = [
-    {file = "django-pwa-1.0.9.tar.gz", hash = "sha256:c11bcb40bbbb65f9037e4ae4d7233e6fa724c4410419b257cce4b6624a9542e9"},
-    {file = "django_pwa-1.0.9-py3-none-any.whl", hash = "sha256:8706cbd84489fb63d3523d5037d2cdfd8ff177417292bd7845b0f177d3c4ed3f"},
+    {file = "django-pwa-1.0.10.tar.gz", hash = "sha256:07ed9dd57108838e3fe44b551a82032ca4ed76e31cb3c3e8d51604e0fe7e81e9"},
+    {file = "django_pwa-1.0.10-py3-none-any.whl", hash = "sha256:b1a2057b1e72c40c3a14beb90b958482da185f1d40a141fcae3d76580984b930"},
 ]
 django-render-block = [
-    {file = "django_render_block-0.6-py2.py3-none-any.whl", hash = "sha256:95c7dc9610378a10e0c4a10d8364ec7307210889afccd6a67a6aaa0fd599bd4d"},
+    {file = "django-render-block-0.8.1.tar.gz", hash = "sha256:edbc5d444cc50f3eb3387cf17f6f1014bf19d6018f680861cdeae9e0306003fa"},
+    {file = "django_render_block-0.8.1-py3-none-any.whl", hash = "sha256:903969efd0949f750c5fe71affe6e6b1ea66d03005c102a67fda36d5b9f4e1e1"},
 ]
 django-reversion = [
-    {file = "django-reversion-3.0.7.tar.gz", hash = "sha256:72fc53580a6b538f0cfff10f27f42333f67d79c406399289c94ec5a193cfb3e1"},
-    {file = "django_reversion-3.0.7-py3-none-any.whl", hash = "sha256:ecab4703ecc0871dc325c3e100139def84eb153622df3413fbcd9de7d3503c78"},
+    {file = "django-reversion-3.0.8.tar.gz", hash = "sha256:49e9930f90322dc6a2754dd26144285cfcc1c5bd0c1c39ca95d5602c5054ae32"},
+    {file = "django_reversion-3.0.8-py3-none-any.whl", hash = "sha256:9cfadeec2df37cb53d795ab79f6792f9eed8e70363dcf3a275dc19a58b971a8f"},
 ]
 django-sass-processor = [
-    {file = "django-sass-processor-0.8.tar.gz", hash = "sha256:e039551994feaaba6fcf880412b25a772dd313162a34cbb4289814988cfae340"},
+    {file = "django-sass-processor-0.8.2.tar.gz", hash = "sha256:9b46a12ca8bdcb397d46fbcc49e6a926ff9f76a93c5efeb23b495419fd01fc7a"},
 ]
 django-select2 = [
     {file = "django-select2-7.4.2.tar.gz", hash = "sha256:9d3330fa0083a03fb69fceb5dcd2e78065cfd08e45c89d4fd727fce4673d3e08"},
@@ -2452,12 +2462,12 @@ django-settings-context-processor = [
     {file = "django-settings-context-processor-0.2.tar.gz", hash = "sha256:d37c853d69a3069f5abbf94c7f4f6fc0fac38bbd0524190cd5a250ba800e496a"},
 ]
 django-stubs = [
-    {file = "django-stubs-1.5.0.tar.gz", hash = "sha256:b4c9042f2c2fcb89dc0fb37df070cce0f9bf93b39ae193847b6e5a392b13c430"},
-    {file = "django_stubs-1.5.0-py3-none-any.whl", hash = "sha256:4a03df70e062f4133085efc461148d0934f36ccfd60a2b6d7bc35821f62008b6"},
+    {file = "django-stubs-1.6.0.tar.gz", hash = "sha256:5257eaedf50e9a294d45618a878baaa1fc6f21b72ebb927c2a87d37a55ca6c50"},
+    {file = "django_stubs-1.6.0-py3-none-any.whl", hash = "sha256:20759904040bd29783a5ff879b48ad965964b8a9ea9e405cc49a435423d0d5ba"},
 ]
 django-tables2 = [
-    {file = "django-tables2-2.3.1.tar.gz", hash = "sha256:28da782f81f046c7d921246f43e7ba2df430cafe5a0e00a0f9dadef25a0e487d"},
-    {file = "django_tables2-2.3.1-py2.py3-none-any.whl", hash = "sha256:7e425ad51e22caf5470351981f0fcd4fd35d4cf2d4c3b76fa1b7bf56251778d1"},
+    {file = "django-tables2-2.3.2.tar.gz", hash = "sha256:20d3969dcf7895bf4b65983eae24eb7a6dbb0664663b55b9c207740a8425fa6d"},
+    {file = "django_tables2-2.3.2-py2.py3-none-any.whl", hash = "sha256:8d37622acd01bdc964c68d8e1803b01c0411dff7792eb455a5634e427118a365"},
 ]
 django-templated-email = [
     {file = "django-templated-email-2.3.0.tar.gz", hash = "sha256:536c4e5ae099eabfb9aab36087d4d7799948c654e73da55a744213d086d5bb33"},
@@ -2467,8 +2477,8 @@ django-timezone-field = [
     {file = "django_timezone_field-4.0-py3-none-any.whl", hash = "sha256:758b7d41084e9ea2e89e59eb616e9b6326e6fbbf9d14b6ef062d624fe8cc6246"},
 ]
 django-two-factor-auth = [
-    {file = "django-two-factor-auth-1.11.0.tar.gz", hash = "sha256:637bd96e76907d044206c3b038bf4b5eb4769e9e3a4718da755fafc97db38b26"},
-    {file = "django_two_factor_auth-1.11.0-py2.py3-none-any.whl", hash = "sha256:f1835e5368448d1b3d826ce7a36c590b3e39cd536523d372cfc5f9fbdc9731f4"},
+    {file = "django-two-factor-auth-1.13.tar.gz", hash = "sha256:24c2850a687c86800f4aa4131b7cebadf56f35be04ca359c4990578df1cc249a"},
+    {file = "django_two_factor_auth-1.13-py2.py3-none-any.whl", hash = "sha256:afb60e62f22b1f29a568666c0444ab05cabe8acc4d7c54d833d67f7b50f842fd"},
 ]
 django-widget-tweaks = [
     {file = "django-widget-tweaks-1.4.8.tar.gz", hash = "sha256:9f91ca4217199b7671971d3c1f323a2bec71a0c27dec6260b3c006fa541bc489"},
@@ -2486,25 +2496,25 @@ dparse = [
     {file = "dparse-0.5.1.tar.gz", hash = "sha256:a1b5f169102e1c894f9a7d5ccf6f9402a836a5d24be80a986c7ce9eaed78f367"},
 ]
 dynaconf = [
-    {file = "dynaconf-2.2.3-py2.py3-none-any.whl", hash = "sha256:e803cdab2d7addd539c4ee8d121f15ab0b63a83a5b723150e1746aa7e8063adb"},
-    {file = "dynaconf-2.2.3.tar.gz", hash = "sha256:26b84f2b234a203f6005463d954c9f007181c09345eaaab3fc38503acbdadc7d"},
+    {file = "dynaconf-3.1.2-py2.py3-none-any.whl", hash = "sha256:808adfe964f10695846dbf8dad7632e47fc3bc38860fd1887ed57dddffc4eff2"},
+    {file = "dynaconf-3.1.2.tar.gz", hash = "sha256:9b34ab2f811a81755f5eb4beac77a69e1e0887528c7e37fc4bc83fed52dcf502"},
 ]
 easy-thumbnails = [
     {file = "easy-thumbnails-2.7.tar.gz", hash = "sha256:e4e7a0dd4001f56bfd4058428f2c91eafe27d33ef3b8b33ac4e013b159b9ff91"},
 ]
 faker = [
-    {file = "Faker-4.1.1-py3-none-any.whl", hash = "sha256:1290f589648bc470b8d98fff1fdff773fe3f46b4ca2cac73ac74668b12cf008e"},
-    {file = "Faker-4.1.1.tar.gz", hash = "sha256:c006b3664c270a2cfd4785c5e41ff263d48101c4e920b5961cf9c237131d8418"},
+    {file = "Faker-4.14.0-py3-none-any.whl", hash = "sha256:a7a36c3c657f06bd1e3e3821b9480f2a92017d8a26e150e464ab6b97743cbc92"},
+    {file = "Faker-4.14.0.tar.gz", hash = "sha256:30afa8f564350770373f299d2d267bff42aaba699a7ae0a3b6f378b2a8170569"},
 ]
 flake8 = [
-    {file = "flake8-3.8.3-py2.py3-none-any.whl", hash = "sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c"},
-    {file = "flake8-3.8.3.tar.gz", hash = "sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"},
+    {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"},
+    {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"},
 ]
 flake8-bandit = [
     {file = "flake8_bandit-2.1.2.tar.gz", hash = "sha256:687fc8da2e4a239b206af2e54a90093572a60d0954f3054e23690739b0b0de3b"},
 ]
 flake8-black = [
-    {file = "flake8-black-0.2.0.tar.gz", hash = "sha256:10e7ff9f81f637a9471684e5624d6a32b11cba362b38df4e20fc8f761184440b"},
+    {file = "flake8-black-0.2.1.tar.gz", hash = "sha256:f26651bc10db786c03f4093414f7c9ea982ed8a244cec323c984feeffdf4c118"},
 ]
 flake8-builtins = [
     {file = "flake8-builtins-1.5.3.tar.gz", hash = "sha256:09998853b2405e98e61d2ff3027c47033adbdc17f9fe44ca58443d876eb00f3b"},
@@ -2523,8 +2533,8 @@ flake8-fixme = [
     {file = "flake8_fixme-1.1.1-py2.py3-none-any.whl", hash = "sha256:226a6f2ef916730899f29ac140bed5d4a17e5aba79f00a0e3ae1eff1997cb1ac"},
 ]
 flake8-isort = [
-    {file = "flake8-isort-3.0.0.tar.gz", hash = "sha256:3ce227b5c5342b6d63937d3863e8de8783ae21863cb035cf992cdb0ba5990aa3"},
-    {file = "flake8_isort-3.0.0-py2.py3-none-any.whl", hash = "sha256:f5322a85cea89998e0df954162fd35a1f1e5b5eb4fc0c79b5975aa2799106baa"},
+    {file = "flake8-isort-4.0.0.tar.gz", hash = "sha256:2b91300f4f1926b396c2c90185844eb1a3d5ec39ea6138832d119da0a208f4d9"},
+    {file = "flake8_isort-4.0.0-py2.py3-none-any.whl", hash = "sha256:729cd6ef9ba3659512dee337687c05d79c78e1215fdf921ed67e5fe46cce2f3c"},
 ]
 flake8-mypy = [
     {file = "flake8-mypy-17.8.0.tar.gz", hash = "sha256:47120db63aff631ee1f84bac6fe8e64731dc66da3efc1c51f85e15ade4a3ba18"},
@@ -2537,36 +2547,36 @@ flake8-polyfill = [
 flake8-rst-docstrings = [
     {file = "flake8-rst-docstrings-0.0.13.tar.gz", hash = "sha256:b1b619d81d879b874533973ac04ee5d823fdbe8c9f3701bfe802bb41813997b4"},
 ]
-future = [
-    {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
-]
 gitdb = [
     {file = "gitdb-4.0.5-py3-none-any.whl", hash = "sha256:91f36bfb1ab7949b3b40e23736db18231bf7593edada2ba5c3a174a7b23657ac"},
     {file = "gitdb-4.0.5.tar.gz", hash = "sha256:c9e1f2d0db7ddb9a704c2a0217be31214e91a4fe1dea1efad19ae42ba0c285c9"},
 ]
 gitpython = [
-    {file = "GitPython-3.1.3-py3-none-any.whl", hash = "sha256:ef1d60b01b5ce0040ad3ec20bc64f783362d41fa0822a2742d3586e1f49bb8ac"},
-    {file = "GitPython-3.1.3.tar.gz", hash = "sha256:e107af4d873daed64648b4f4beb89f89f0cfbe3ef558fc7821ed2331c2f8da1a"},
+    {file = "GitPython-3.1.9-py3-none-any.whl", hash = "sha256:138016d519bf4dd55b22c682c904ed2fd0235c3612b2f8f65ce218ff358deed8"},
+    {file = "GitPython-3.1.9.tar.gz", hash = "sha256:a03f728b49ce9597a6655793207c6ab0da55519368ff5961e4a74ae475b9fa8e"},
 ]
 html2text = [
     {file = "html2text-2020.1.16-py3-none-any.whl", hash = "sha256:c7c629882da0cf377d66f073329ccf34a12ed2adf0169b9285ae4e63ef54c82b"},
     {file = "html2text-2020.1.16.tar.gz", hash = "sha256:e296318e16b059ddb97f7a8a1d6a5c1d7af4544049a01e261731d2d5cc277bbb"},
 ]
 idna = [
-    {file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
-    {file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
+    {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
+    {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
 ]
 imagesize = [
     {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"},
     {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"},
 ]
 importlib-metadata = [
-    {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"},
-    {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"},
+    {file = "importlib_metadata-2.0.0-py2.py3-none-any.whl", hash = "sha256:cefa1a2f919b866c5beb7c9f7b0ebb4061f30a8a9bf16d609b000e2dfaceb9c3"},
+    {file = "importlib_metadata-2.0.0.tar.gz", hash = "sha256:77a540690e24b0305878c37ffd421785a6f7e53c8b5720d211b211de8d0e95da"},
+]
+iniconfig = [
+    {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
 ]
 isort = [
-    {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"},
-    {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"},
+    {file = "isort-5.6.4-py3-none-any.whl", hash = "sha256:dcab1d98b469a12a1a624ead220584391648790275560e1a43e54c5dceae65e7"},
+    {file = "isort-5.6.4.tar.gz", hash = "sha256:dcaeec1b5f0eca77faea2a35ab790b4f3680ff75590bfcb7145986905aab2f58"},
 ]
 jinja2 = [
     {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"},
@@ -2577,19 +2587,19 @@ kombu = [
     {file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"},
 ]
 libsass = [
-    {file = "libsass-0.20.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:107c409524c6a4ed14410fa9dafa9ee59c6bd3ecae75d73af749ab2b75685726"},
-    {file = "libsass-0.20.0-cp27-cp27m-win32.whl", hash = "sha256:98f6dee9850b29e62977a963e3beb3cfeb98b128a267d59d2c3d675e298c8d57"},
-    {file = "libsass-0.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:b077261a04ba1c213e932943208471972c5230222acb7fa97373e55a40872cbb"},
-    {file = "libsass-0.20.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e6a547c0aa731dcb4ed71f198e814bee0400ce04d553f3f12a53bc3a17f2a481"},
-    {file = "libsass-0.20.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:74f6fb8da58179b5d86586bc045c16d93d55074bc7bb48b6354a4da7ac9f9dfd"},
-    {file = "libsass-0.20.0-cp36-cp36m-win32.whl", hash = "sha256:a43f3830d83ad9a7f5013c05ce239ca71744d0780dad906587302ac5257bce60"},
-    {file = "libsass-0.20.0-cp36-cp36m-win_amd64.whl", hash = "sha256:fd19c8f73f70ffc6cbcca8139da08ea9a71fc48e7dfc4bb236ad88ab2d6558f1"},
-    {file = "libsass-0.20.0-cp37-abi3-macosx_10_14_x86_64.whl", hash = "sha256:8cf72552b39e78a1852132e16b706406bc76029fe3001583284ece8d8752a60a"},
-    {file = "libsass-0.20.0-cp37-cp37m-win32.whl", hash = "sha256:7555d9b24e79943cfafac44dbb4ca7e62105c038de7c6b999838c9ff7b88645d"},
-    {file = "libsass-0.20.0-cp37-cp37m-win_amd64.whl", hash = "sha256:794f4f4661667263e7feafe5cc866e3746c7c8a9192b2aa9afffdadcbc91c687"},
-    {file = "libsass-0.20.0-cp38-cp38-win32.whl", hash = "sha256:3bc0d68778b30b5fa83199e18795314f64b26ca5871e026343e63934f616f7f7"},
-    {file = "libsass-0.20.0-cp38-cp38-win_amd64.whl", hash = "sha256:5c8ff562b233734fbc72b23bb862cc6a6f70b1e9bf85a58422aa75108b94783b"},
-    {file = "libsass-0.20.0.tar.gz", hash = "sha256:b7452f1df274b166dc22ee2e9154c4adca619bcbbdf8041a7aa05f372a1dacbc"},
+    {file = "libsass-0.20.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:4a246e4b88fd279abef8b669206228c92534d96ddcd0770d7012088c408dff23"},
+    {file = "libsass-0.20.1-cp27-cp27m-win32.whl", hash = "sha256:697f0f9fa8a1367ca9ec6869437cb235b1c537fc8519983d1d890178614a8903"},
+    {file = "libsass-0.20.1-cp27-cp27m-win_amd64.whl", hash = "sha256:1b2d415bbf6fa7da33ef46e549db1418498267b459978eff8357e5e823962d35"},
+    {file = "libsass-0.20.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1521d2a8d4b397c6ec90640a1f6b5529077035efc48ef1c2e53095544e713d1b"},
+    {file = "libsass-0.20.1-cp36-abi3-macosx_10_14_x86_64.whl", hash = "sha256:2ae806427b28bc1bb7cb0258666d854fcf92ba52a04656b0b17ba5e190fb48a9"},
+    {file = "libsass-0.20.1-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:25ebc2085f5eee574761ccc8d9cd29a9b436fc970546d5ef08c6fa41eb57dff1"},
+    {file = "libsass-0.20.1-cp36-cp36m-win32.whl", hash = "sha256:553e5096414a8d4fb48d0a48f5a038d3411abe254d79deac5e008516c019e63a"},
+    {file = "libsass-0.20.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e64ae2587f1a683e831409aad03ba547c245ef997e1329fffadf7a866d2510b8"},
+    {file = "libsass-0.20.1-cp37-cp37m-win32.whl", hash = "sha256:c9411fec76f480ffbacc97d8188322e02a5abca6fc78e70b86a2a2b421eae8a2"},
+    {file = "libsass-0.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a8fd4af9f853e8bf42b1425c5e48dd90b504fa2e70d7dac5ac80b8c0a5a5fe85"},
+    {file = "libsass-0.20.1-cp38-cp38-win32.whl", hash = "sha256:f6852828e9e104d2ce0358b73c550d26dd86cc3a69439438c3b618811b9584f5"},
+    {file = "libsass-0.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:daa98a51086d92aa7e9c8871cf1a8258124b90e2abf4697852a3dca619838618"},
+    {file = "libsass-0.20.1.tar.gz", hash = "sha256:e0e60836eccbf2d9e24ec978a805cd6642fa92515fbd95e3493fee276af76f8a"},
 ]
 license-expression = [
     {file = "license-expression-1.2.tar.gz", hash = "sha256:7960e1dfdf20d127e75ead931476f2b5c7556df05b117a73880b22ade17d1abc"},
@@ -2634,25 +2644,21 @@ mccabe = [
     {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
     {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
 ]
-more-itertools = [
-    {file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"},
-    {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
-]
 mypy = [
-    {file = "mypy-0.770-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:a34b577cdf6313bf24755f7a0e3f3c326d5c1f4fe7422d1d06498eb25ad0c600"},
-    {file = "mypy-0.770-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:86c857510a9b7c3104cf4cde1568f4921762c8f9842e987bc03ed4f160925754"},
-    {file = "mypy-0.770-cp35-cp35m-win_amd64.whl", hash = "sha256:a8ffcd53cb5dfc131850851cc09f1c44689c2812d0beb954d8138d4f5fc17f65"},
-    {file = "mypy-0.770-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:7687f6455ec3ed7649d1ae574136835a4272b65b3ddcf01ab8704ac65616c5ce"},
-    {file = "mypy-0.770-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3beff56b453b6ef94ecb2996bea101a08f1f8a9771d3cbf4988a61e4d9973761"},
-    {file = "mypy-0.770-cp36-cp36m-win_amd64.whl", hash = "sha256:15b948e1302682e3682f11f50208b726a246ab4e6c1b39f9264a8796bb416aa2"},
-    {file = "mypy-0.770-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:b90928f2d9eb2f33162405f32dde9f6dcead63a0971ca8a1b50eb4ca3e35ceb8"},
-    {file = "mypy-0.770-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c56ffe22faa2e51054c5f7a3bc70a370939c2ed4de308c690e7949230c995913"},
-    {file = "mypy-0.770-cp37-cp37m-win_amd64.whl", hash = "sha256:8dfb69fbf9f3aeed18afffb15e319ca7f8da9642336348ddd6cab2713ddcf8f9"},
-    {file = "mypy-0.770-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:219a3116ecd015f8dca7b5d2c366c973509dfb9a8fc97ef044a36e3da66144a1"},
-    {file = "mypy-0.770-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7ec45a70d40ede1ec7ad7f95b3c94c9cf4c186a32f6bacb1795b60abd2f9ef27"},
-    {file = "mypy-0.770-cp38-cp38-win_amd64.whl", hash = "sha256:f91c7ae919bbc3f96cd5e5b2e786b2b108343d1d7972ea130f7de27fdd547cf3"},
-    {file = "mypy-0.770-py3-none-any.whl", hash = "sha256:3b1fc683fb204c6b4403a1ef23f0b1fac8e4477091585e0c8c54cbdf7d7bb164"},
-    {file = "mypy-0.770.tar.gz", hash = "sha256:8a627507ef9b307b46a1fea9513d5c98680ba09591253082b4c48697ba05a4ae"},
+    {file = "mypy-0.782-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:2c6cde8aa3426c1682d35190b59b71f661237d74b053822ea3d748e2c9578a7c"},
+    {file = "mypy-0.782-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9c7a9a7ceb2871ba4bac1cf7217a7dd9ccd44c27c2950edbc6dc08530f32ad4e"},
+    {file = "mypy-0.782-cp35-cp35m-win_amd64.whl", hash = "sha256:c05b9e4fb1d8a41d41dec8786c94f3b95d3c5f528298d769eb8e73d293abc48d"},
+    {file = "mypy-0.782-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:6731603dfe0ce4352c555c6284c6db0dc935b685e9ce2e4cf220abe1e14386fd"},
+    {file = "mypy-0.782-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f05644db6779387ccdb468cc47a44b4356fc2ffa9287135d05b70a98dc83b89a"},
+    {file = "mypy-0.782-cp36-cp36m-win_amd64.whl", hash = "sha256:b7fbfabdbcc78c4f6fc4712544b9b0d6bf171069c6e0e3cb82440dd10ced3406"},
+    {file = "mypy-0.782-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:3fdda71c067d3ddfb21da4b80e2686b71e9e5c72cca65fa216d207a358827f86"},
+    {file = "mypy-0.782-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7df6eddb6054d21ca4d3c6249cae5578cb4602951fd2b6ee2f5510ffb098707"},
+    {file = "mypy-0.782-cp37-cp37m-win_amd64.whl", hash = "sha256:a4a2cbcfc4cbf45cd126f531dedda8485671545b43107ded25ce952aac6fb308"},
+    {file = "mypy-0.782-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6bb93479caa6619d21d6e7160c552c1193f6952f0668cdda2f851156e85186fc"},
+    {file = "mypy-0.782-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:81c7908b94239c4010e16642c9102bfc958ab14e36048fa77d0be3289dda76ea"},
+    {file = "mypy-0.782-cp38-cp38-win_amd64.whl", hash = "sha256:5dd13ff1f2a97f94540fd37a49e5d255950ebcdf446fb597463a40d0df3fac8b"},
+    {file = "mypy-0.782-py3-none-any.whl", hash = "sha256:e0b61738ab504e656d1fe4ff0c0601387a5489ca122d55390ade31f9ca0e252d"},
+    {file = "mypy-0.782.tar.gz", hash = "sha256:eff7d4a85e9eea55afa34888dfeaccde99e7520b51f867ac28a48492c0b1130c"},
 ]
 mypy-extensions = [
     {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
@@ -2667,76 +2673,79 @@ pathspec = [
     {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
 ]
 pbr = [
-    {file = "pbr-5.4.5-py2.py3-none-any.whl", hash = "sha256:579170e23f8e0c2f24b0de612f71f648eccb79fb1322c814ae6b3c07b5ba23e8"},
-    {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"},
+    {file = "pbr-5.5.1-py2.py3-none-any.whl", hash = "sha256:b236cde0ac9a6aedd5e3c34517b423cd4fd97ef723849da6b0d2231142d89c00"},
+    {file = "pbr-5.5.1.tar.gz", hash = "sha256:5fad80b613c402d5b7df7bd84812548b2a61e9977387a80a5fc5c396492b13c9"},
 ]
 persisting-theory = [
     {file = "persisting-theory-0.2.1.tar.gz", hash = "sha256:00ff7dcc8f481ff75c770ca5797d968e8725b6df1f77fe0cf7d20fa1e5790c0a"},
 ]
 pg8000 = [
-    {file = "pg8000-1.15.3-py3-none-any.whl", hash = "sha256:79d2e761343e582dec6698cf7c06d49c33255cbafba29ff298dd4690fffb7d80"},
-    {file = "pg8000-1.15.3.tar.gz", hash = "sha256:af97353076b8e5d271d91c64c8ca806e2157d11b7862c90ff6f0e23be0fc217d"},
+    {file = "pg8000-1.16.6-py3-none-any.whl", hash = "sha256:66fa16a402f38f8ba664206b4ba4040f24ea9641c4205b2b96a1ff3a613de3be"},
+    {file = "pg8000-1.16.6.tar.gz", hash = "sha256:8fc1e6a62ccb7c9830f1e7e9288e2d20eaf373cc8875b5c55b7d5d9b7717be91"},
 ]
 phonenumbers = [
-    {file = "phonenumbers-8.12.6-py2.py3-none-any.whl", hash = "sha256:e49b8e21c557f0dafee966ddd55fb2bd3d6db155451999b75fb1b012e8d2016c"},
-    {file = "phonenumbers-8.12.6.tar.gz", hash = "sha256:d332078fe71c6153b5a263ac87283618b2afe514a248a14f06a0d39ce1f5ce0b"},
+    {file = "phonenumbers-8.12.11-py2.py3-none-any.whl", hash = "sha256:f5277ce92ac8813cb1f4174c6d1ee1fd08d563da28f9dec1f4bed0031a780a80"},
+    {file = "phonenumbers-8.12.11.tar.gz", hash = "sha256:17f39f06c1e0e20eabe69ff735b1c08e4547d12a12595da3d835fd3256a9ee0c"},
 ]
 pillow = [
-    {file = "Pillow-7.1.2-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3"},
-    {file = "Pillow-7.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d"},
-    {file = "Pillow-7.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f"},
-    {file = "Pillow-7.1.2-cp35-cp35m-win32.whl", hash = "sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523"},
-    {file = "Pillow-7.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705"},
-    {file = "Pillow-7.1.2-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276"},
-    {file = "Pillow-7.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3"},
-    {file = "Pillow-7.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d"},
-    {file = "Pillow-7.1.2-cp36-cp36m-win32.whl", hash = "sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891"},
-    {file = "Pillow-7.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088"},
-    {file = "Pillow-7.1.2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa"},
-    {file = "Pillow-7.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457"},
-    {file = "Pillow-7.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3"},
-    {file = "Pillow-7.1.2-cp37-cp37m-win32.whl", hash = "sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7"},
-    {file = "Pillow-7.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac"},
-    {file = "Pillow-7.1.2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107"},
-    {file = "Pillow-7.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2"},
-    {file = "Pillow-7.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344"},
-    {file = "Pillow-7.1.2-cp38-cp38-win32.whl", hash = "sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd"},
-    {file = "Pillow-7.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079"},
-    {file = "Pillow-7.1.2-pp373-pypy36_pp73-win32.whl", hash = "sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9"},
-    {file = "Pillow-7.1.2-py3.8-macosx-10.9-x86_64.egg", hash = "sha256:70e3e0d99a0dcda66283a185f80697a9b08806963c6149c8e6c5f452b2aa59c0"},
-    {file = "Pillow-7.1.2.tar.gz", hash = "sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd"},
+    {file = "Pillow-7.2.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae"},
+    {file = "Pillow-7.2.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f"},
+    {file = "Pillow-7.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38"},
+    {file = "Pillow-7.2.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5"},
+    {file = "Pillow-7.2.0-cp35-cp35m-win32.whl", hash = "sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad"},
+    {file = "Pillow-7.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f"},
+    {file = "Pillow-7.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d"},
+    {file = "Pillow-7.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233"},
+    {file = "Pillow-7.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f"},
+    {file = "Pillow-7.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8"},
+    {file = "Pillow-7.2.0-cp36-cp36m-win32.whl", hash = "sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a"},
+    {file = "Pillow-7.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce"},
+    {file = "Pillow-7.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4"},
+    {file = "Pillow-7.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727"},
+    {file = "Pillow-7.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b"},
+    {file = "Pillow-7.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d"},
+    {file = "Pillow-7.2.0-cp37-cp37m-win32.whl", hash = "sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63"},
+    {file = "Pillow-7.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1"},
+    {file = "Pillow-7.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6"},
+    {file = "Pillow-7.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9"},
+    {file = "Pillow-7.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41"},
+    {file = "Pillow-7.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8"},
+    {file = "Pillow-7.2.0-cp38-cp38-win32.whl", hash = "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f"},
+    {file = "Pillow-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6"},
+    {file = "Pillow-7.2.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d"},
+    {file = "Pillow-7.2.0.tar.gz", hash = "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626"},
 ]
 pluggy = [
     {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
     {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
 ]
 psutil = [
-    {file = "psutil-5.7.0-cp27-none-win32.whl", hash = "sha256:298af2f14b635c3c7118fd9183843f4e73e681bb6f01e12284d4d70d48a60953"},
-    {file = "psutil-5.7.0-cp27-none-win_amd64.whl", hash = "sha256:75e22717d4dbc7ca529ec5063000b2b294fc9a367f9c9ede1f65846c7955fd38"},
-    {file = "psutil-5.7.0-cp35-cp35m-win32.whl", hash = "sha256:f344ca230dd8e8d5eee16827596f1c22ec0876127c28e800d7ae20ed44c4b310"},
-    {file = "psutil-5.7.0-cp35-cp35m-win_amd64.whl", hash = "sha256:e2d0c5b07c6fe5a87fa27b7855017edb0d52ee73b71e6ee368fae268605cc3f5"},
-    {file = "psutil-5.7.0-cp36-cp36m-win32.whl", hash = "sha256:a02f4ac50d4a23253b68233b07e7cdb567bd025b982d5cf0ee78296990c22d9e"},
-    {file = "psutil-5.7.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1413f4158eb50e110777c4f15d7c759521703bd6beb58926f1d562da40180058"},
-    {file = "psutil-5.7.0-cp37-cp37m-win32.whl", hash = "sha256:d008ddc00c6906ec80040d26dc2d3e3962109e40ad07fd8a12d0284ce5e0e4f8"},
-    {file = "psutil-5.7.0-cp37-cp37m-win_amd64.whl", hash = "sha256:73f35ab66c6c7a9ce82ba44b1e9b1050be2a80cd4dcc3352cc108656b115c74f"},
-    {file = "psutil-5.7.0-cp38-cp38-win32.whl", hash = "sha256:60b86f327c198561f101a92be1995f9ae0399736b6eced8f24af41ec64fb88d4"},
-    {file = "psutil-5.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:d84029b190c8a66a946e28b4d3934d2ca1528ec94764b180f7d6ea57b0e75e26"},
-    {file = "psutil-5.7.0.tar.gz", hash = "sha256:685ec16ca14d079455892f25bd124df26ff9137664af445563c1bd36629b5e0e"},
+    {file = "psutil-5.7.2-cp27-none-win32.whl", hash = "sha256:f2018461733b23f308c298653c8903d32aaad7873d25e1d228765e91ae42c3f2"},
+    {file = "psutil-5.7.2-cp27-none-win_amd64.whl", hash = "sha256:66c18ca7680a31bf16ee22b1d21b6397869dda8059dbdb57d9f27efa6615f195"},
+    {file = "psutil-5.7.2-cp35-cp35m-win32.whl", hash = "sha256:5e9d0f26d4194479a13d5f4b3798260c20cecf9ac9a461e718eb59ea520a360c"},
+    {file = "psutil-5.7.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4080869ed93cce662905b029a1770fe89c98787e543fa7347f075ade761b19d6"},
+    {file = "psutil-5.7.2-cp36-cp36m-win32.whl", hash = "sha256:d8a82162f23c53b8525cf5f14a355f5d1eea86fa8edde27287dd3a98399e4fdf"},
+    {file = "psutil-5.7.2-cp36-cp36m-win_amd64.whl", hash = "sha256:0ee3c36428f160d2d8fce3c583a0353e848abb7de9732c50cf3356dd49ad63f8"},
+    {file = "psutil-5.7.2-cp37-cp37m-win32.whl", hash = "sha256:ff1977ba1a5f71f89166d5145c3da1cea89a0fdb044075a12c720ee9123ec818"},
+    {file = "psutil-5.7.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a5b120bb3c0c71dfe27551f9da2f3209a8257a178ed6c628a819037a8df487f1"},
+    {file = "psutil-5.7.2-cp38-cp38-win32.whl", hash = "sha256:10512b46c95b02842c225f58fa00385c08fa00c68bac7da2d9a58ebe2c517498"},
+    {file = "psutil-5.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:68d36986ded5dac7c2dcd42f2682af1db80d4bce3faa126a6145c1637e1b559f"},
+    {file = "psutil-5.7.2.tar.gz", hash = "sha256:90990af1c3c67195c44c9a889184f84f5b2320dce3ee3acbd054e3ba0b4a7beb"},
 ]
 psycopg2 = [
-    {file = "psycopg2-2.8.5-cp27-cp27m-win32.whl", hash = "sha256:a0984ff49e176062fcdc8a5a2a670c9bb1704a2f69548bce8f8a7bad41c661bf"},
-    {file = "psycopg2-2.8.5-cp27-cp27m-win_amd64.whl", hash = "sha256:acf56d564e443e3dea152efe972b1434058244298a94348fc518d6dd6a9fb0bb"},
-    {file = "psycopg2-2.8.5-cp34-cp34m-win32.whl", hash = "sha256:440a3ea2c955e89321a138eb7582aa1d22fe286c7d65e26a2c5411af0a88ae72"},
-    {file = "psycopg2-2.8.5-cp34-cp34m-win_amd64.whl", hash = "sha256:6b306dae53ec7f4f67a10942cf8ac85de930ea90e9903e2df4001f69b7833f7e"},
-    {file = "psycopg2-2.8.5-cp35-cp35m-win32.whl", hash = "sha256:d3b29d717d39d3580efd760a9a46a7418408acebbb784717c90d708c9ed5f055"},
-    {file = "psycopg2-2.8.5-cp35-cp35m-win_amd64.whl", hash = "sha256:6a471d4d2a6f14c97a882e8d3124869bc623f3df6177eefe02994ea41fd45b52"},
-    {file = "psycopg2-2.8.5-cp36-cp36m-win32.whl", hash = "sha256:27c633f2d5db0fc27b51f1b08f410715b59fa3802987aec91aeb8f562724e95c"},
-    {file = "psycopg2-2.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2df2bf1b87305bd95eb3ac666ee1f00a9c83d10927b8144e8e39644218f4cf81"},
-    {file = "psycopg2-2.8.5-cp37-cp37m-win32.whl", hash = "sha256:ac5b23d0199c012ad91ed1bbb971b7666da651c6371529b1be8cbe2a7bf3c3a9"},
-    {file = "psycopg2-2.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2c0afb40cfb4d53487ee2ebe128649028c9a78d2476d14a67781e45dc287f080"},
-    {file = "psycopg2-2.8.5-cp38-cp38-win32.whl", hash = "sha256:2327bf42c1744a434ed8ed0bbaa9168cac7ee5a22a9001f6fc85c33b8a4a14b7"},
-    {file = "psycopg2-2.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:132efc7ee46a763e68a815f4d26223d9c679953cd190f1f218187cb60decf535"},
-    {file = "psycopg2-2.8.5.tar.gz", hash = "sha256:f7d46240f7a1ae1dd95aab38bd74f7428d46531f69219954266d669da60c0818"},
+    {file = "psycopg2-2.8.6-cp27-cp27m-win32.whl", hash = "sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725"},
+    {file = "psycopg2-2.8.6-cp27-cp27m-win_amd64.whl", hash = "sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5"},
+    {file = "psycopg2-2.8.6-cp34-cp34m-win32.whl", hash = "sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad"},
+    {file = "psycopg2-2.8.6-cp34-cp34m-win_amd64.whl", hash = "sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3"},
+    {file = "psycopg2-2.8.6-cp35-cp35m-win32.whl", hash = "sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821"},
+    {file = "psycopg2-2.8.6-cp35-cp35m-win_amd64.whl", hash = "sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301"},
+    {file = "psycopg2-2.8.6-cp36-cp36m-win32.whl", hash = "sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a"},
+    {file = "psycopg2-2.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d"},
+    {file = "psycopg2-2.8.6-cp37-cp37m-win32.whl", hash = "sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84"},
+    {file = "psycopg2-2.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5"},
+    {file = "psycopg2-2.8.6-cp38-cp38-win32.whl", hash = "sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e"},
+    {file = "psycopg2-2.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051"},
+    {file = "psycopg2-2.8.6.tar.gz", hash = "sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543"},
 ]
 py = [
     {file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"},
@@ -2809,16 +2818,16 @@ pycryptodome = [
     {file = "pycryptodome-3.9.8.tar.gz", hash = "sha256:0e24171cf01021bc5dc17d6a9d4f33a048f09d62cc3f62541e95ef104588bda4"},
 ]
 pydocstyle = [
-    {file = "pydocstyle-5.0.2-py3-none-any.whl", hash = "sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586"},
-    {file = "pydocstyle-5.0.2.tar.gz", hash = "sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"},
+    {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"},
+    {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"},
 ]
 pyflakes = [
     {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"},
     {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"},
 ]
 pygments = [
-    {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"},
-    {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"},
+    {file = "Pygments-2.7.1-py3-none-any.whl", hash = "sha256:307543fe65c0947b126e83dd5a61bd8acbd84abec11f43caebaf5534cbc17998"},
+    {file = "Pygments-2.7.1.tar.gz", hash = "sha256:926c3f319eda178d1bd90851e4317e6d8cdb5e292a3386aac9bd75eca29cf9c7"},
 ]
 pyjwt = [
     {file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"},
@@ -2829,27 +2838,27 @@ pyparsing = [
     {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
 ]
 pytest = [
-    {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
-    {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
+    {file = "pytest-6.1.1-py3-none-any.whl", hash = "sha256:7a8190790c17d79a11f847fba0b004ee9a8122582ebff4729a082c109e81a4c9"},
+    {file = "pytest-6.1.1.tar.gz", hash = "sha256:8f593023c1a0f916110285b6efd7f99db07d59546e3d8c36fc60e2ab05d3be92"},
 ]
 pytest-cov = [
-    {file = "pytest-cov-2.10.0.tar.gz", hash = "sha256:1a629dc9f48e53512fcbfda6b07de490c374b0c83c55ff7a1720b3fccff0ac87"},
-    {file = "pytest_cov-2.10.0-py2.py3-none-any.whl", hash = "sha256:6e6d18092dce6fad667cd7020deed816f858ad3b49d5b5e2b1cc1c97a4dba65c"},
+    {file = "pytest-cov-2.10.1.tar.gz", hash = "sha256:47bd0ce14056fdd79f93e1713f88fad7bdcc583dcd7783da86ef2f085a0bb88e"},
+    {file = "pytest_cov-2.10.1-py2.py3-none-any.whl", hash = "sha256:45ec2d5182f89a81fc3eb29e3d1ed3113b9e9a873bcddb2a71faaab066110191"},
 ]
 pytest-django = [
-    {file = "pytest-django-3.9.0.tar.gz", hash = "sha256:664e5f42242e5e182519388f01b9f25d824a9feb7cd17d8f863c8d776f38baf9"},
-    {file = "pytest_django-3.9.0-py2.py3-none-any.whl", hash = "sha256:64f99d565dd9497af412fcab2989fe40982c1282d4118ff422b407f3f7275ca5"},
+    {file = "pytest-django-3.10.0.tar.gz", hash = "sha256:4de6dbd077ed8606616958f77655fed0d5e3ee45159475671c7fa67596c6dba6"},
+    {file = "pytest_django-3.10.0-py2.py3-none-any.whl", hash = "sha256:c33e3d3da14d8409b125d825d4e74da17bb252191bf6fc3da6856e27a8b73ea4"},
 ]
 pytest-django-testing-postgresql = [
     {file = "pytest-django-testing-postgresql-0.1.post0.tar.gz", hash = "sha256:78b0c58930084cb4393407b2e5a2a3b8734c627b841ecef7d62d39bbfb8e8a45"},
     {file = "pytest_django_testing_postgresql-0.1.post0-py3-none-any.whl", hash = "sha256:78e52e3d1b0ef5f906d5d69247dd6ac7dfb10d840bd81abab92f3f8c30872cd3"},
 ]
 pytest-sugar = [
-    {file = "pytest-sugar-0.9.3.tar.gz", hash = "sha256:1630b5b7ea3624919b73fde37cffb87965c5087a4afab8a43074ff44e0d810c4"},
+    {file = "pytest-sugar-0.9.4.tar.gz", hash = "sha256:b1b2186b0a72aada6859bea2a5764145e3aaa2c1cfbb23c3a19b5f7b697563d3"},
 ]
 python-box = [
-    {file = "python-box-3.4.6.tar.gz", hash = "sha256:694a7555e3ff9fbbce734bbaef3aad92b8e4ed0659d3ed04d56b6a0a0eff26a9"},
-    {file = "python_box-3.4.6-py2.py3-none-any.whl", hash = "sha256:a71d3dc9dbaa34c8597d3517c89a8041bd62fa875f23c0f3dad55e1958e3ce10"},
+    {file = "python-box-5.1.1.tar.gz", hash = "sha256:e51d03275f0d6fef3c155f79c19e542c2fb6d92e89eb385cd71ea22c5d4681b3"},
+    {file = "python_box-5.1.1-py3-none-any.whl", hash = "sha256:b7a6f3edd2f71e2475d93163b6465f637a2714b155acafef17408b06e55282b3"},
 ]
 python-crontab = [
     {file = "python-crontab-2.5.1.tar.gz", hash = "sha256:4bbe7e720753a132ca4ca9d4094915f40e9d9dc8a807a4564007651018ce8c31"},
@@ -2858,12 +2867,8 @@ python-dateutil = [
     {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
     {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
 ]
-python-dotenv = [
-    {file = "python-dotenv-0.13.0.tar.gz", hash = "sha256:3b9909bc96b0edc6b01586e1eed05e71174ef4e04c71da5786370cebea53ad74"},
-    {file = "python_dotenv-0.13.0-py2.py3-none-any.whl", hash = "sha256:25c0ff1a3e12f4bde8d592cc254ab075cfe734fc5dd989036716fd17ee7e5ec7"},
-]
 python-ldap = [
-    {file = "python-ldap-3.3.0.tar.gz", hash = "sha256:de04939485b53ee5d9a6855562d415b73060c52e681644386de4d5bd18e3f540"},
+    {file = "python-ldap-3.3.1.tar.gz", hash = "sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5"},
 ]
 python-memcached = [
     {file = "python-memcached-1.59.tar.gz", hash = "sha256:a2e28637be13ee0bf1a8b6843e7490f9456fd3f2a4cb60471733c7b5d5557e4f"},
@@ -2895,27 +2900,33 @@ redis = [
     {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"},
 ]
 regex = [
-    {file = "regex-2020.6.8-cp27-cp27m-win32.whl", hash = "sha256:fbff901c54c22425a5b809b914a3bfaf4b9570eee0e5ce8186ac71eb2025191c"},
-    {file = "regex-2020.6.8-cp27-cp27m-win_amd64.whl", hash = "sha256:112e34adf95e45158c597feea65d06a8124898bdeac975c9087fe71b572bd938"},
-    {file = "regex-2020.6.8-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:92d8a043a4241a710c1cf7593f5577fbb832cf6c3a00ff3fc1ff2052aff5dd89"},
-    {file = "regex-2020.6.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bae83f2a56ab30d5353b47f9b2a33e4aac4de9401fb582b55c42b132a8ac3868"},
-    {file = "regex-2020.6.8-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b2ba0f78b3ef375114856cbdaa30559914d081c416b431f2437f83ce4f8b7f2f"},
-    {file = "regex-2020.6.8-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:95fa7726d073c87141f7bbfb04c284901f8328e2d430eeb71b8ffdd5742a5ded"},
-    {file = "regex-2020.6.8-cp36-cp36m-win32.whl", hash = "sha256:e3cdc9423808f7e1bb9c2e0bdb1c9dc37b0607b30d646ff6faf0d4e41ee8fee3"},
-    {file = "regex-2020.6.8-cp36-cp36m-win_amd64.whl", hash = "sha256:c78e66a922de1c95a208e4ec02e2e5cf0bb83a36ceececc10a72841e53fbf2bd"},
-    {file = "regex-2020.6.8-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:08997a37b221a3e27d68ffb601e45abfb0093d39ee770e4257bd2f5115e8cb0a"},
-    {file = "regex-2020.6.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2f6f211633ee8d3f7706953e9d3edc7ce63a1d6aad0be5dcee1ece127eea13ae"},
-    {file = "regex-2020.6.8-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:55b4c25cbb3b29f8d5e63aeed27b49fa0f8476b0d4e1b3171d85db891938cc3a"},
-    {file = "regex-2020.6.8-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89cda1a5d3e33ec9e231ece7307afc101b5217523d55ef4dc7fb2abd6de71ba3"},
-    {file = "regex-2020.6.8-cp37-cp37m-win32.whl", hash = "sha256:690f858d9a94d903cf5cada62ce069b5d93b313d7d05456dbcd99420856562d9"},
-    {file = "regex-2020.6.8-cp37-cp37m-win_amd64.whl", hash = "sha256:1700419d8a18c26ff396b3b06ace315b5f2a6e780dad387e4c48717a12a22c29"},
-    {file = "regex-2020.6.8-cp38-cp38-manylinux1_i686.whl", hash = "sha256:654cb773b2792e50151f0e22be0f2b6e1c3a04c5328ff1d9d59c0398d37ef610"},
-    {file = "regex-2020.6.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:52e1b4bef02f4040b2fd547357a170fc1146e60ab310cdbdd098db86e929b387"},
-    {file = "regex-2020.6.8-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:cf59bbf282b627130f5ba68b7fa3abdb96372b24b66bdf72a4920e8153fc7910"},
-    {file = "regex-2020.6.8-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5aaa5928b039ae440d775acea11d01e42ff26e1561c0ffcd3d805750973c6baf"},
-    {file = "regex-2020.6.8-cp38-cp38-win32.whl", hash = "sha256:97712e0d0af05febd8ab63d2ef0ab2d0cd9deddf4476f7aa153f76feef4b2754"},
-    {file = "regex-2020.6.8-cp38-cp38-win_amd64.whl", hash = "sha256:6ad8663c17db4c5ef438141f99e291c4d4edfeaacc0ce28b5bba2b0bf273d9b5"},
-    {file = "regex-2020.6.8.tar.gz", hash = "sha256:e9b64e609d37438f7d6e68c2546d2cb8062f3adb27e6336bc129b51be20773ac"},
+    {file = "regex-2020.10.15-cp27-cp27m-win32.whl", hash = "sha256:e935a166a5f4c02afe3f7e4ce92ce5a786f75c6caa0c4ce09c922541d74b77e8"},
+    {file = "regex-2020.10.15-cp27-cp27m-win_amd64.whl", hash = "sha256:d81be22d5d462b96a2aa5c512f741255ba182995efb0114e5a946fe254148df1"},
+    {file = "regex-2020.10.15-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6d4cdb6c20e752426b2e569128488c5046fb1b16b1beadaceea9815c36da0847"},
+    {file = "regex-2020.10.15-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:25991861c6fef1e5fd0a01283cf5658c5e7f7aa644128e85243bc75304e91530"},
+    {file = "regex-2020.10.15-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:6e9f72e0ee49f7d7be395bfa29e9533f0507a882e1e6bf302c0a204c65b742bf"},
+    {file = "regex-2020.10.15-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:578ac6379e65eb8e6a85299b306c966c852712c834dc7eef0ba78d07a828f67b"},
+    {file = "regex-2020.10.15-cp36-cp36m-win32.whl", hash = "sha256:65b6b018b07e9b3b6a05c2c3bb7710ed66132b4df41926c243887c4f1ff303d5"},
+    {file = "regex-2020.10.15-cp36-cp36m-win_amd64.whl", hash = "sha256:2f60ba5c33f00ce9be29a140e6f812e39880df8ba9cb92ad333f0016dbc30306"},
+    {file = "regex-2020.10.15-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5d4a3221f37520bb337b64a0632716e61b26c8ae6aaffceeeb7ad69c009c404b"},
+    {file = "regex-2020.10.15-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:26b85672275d8c7a9d4ff93dbc4954f5146efdb2ecec89ad1de49439984dea14"},
+    {file = "regex-2020.10.15-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:828618f3c3439c5e6ef8621e7c885ca561bbaaba90ddbb6a7dfd9e1ec8341103"},
+    {file = "regex-2020.10.15-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:aef23aed9d4017cc74d37f703d57ce254efb4c8a6a01905f40f539220348abf9"},
+    {file = "regex-2020.10.15-cp37-cp37m-win32.whl", hash = "sha256:6c72adb85adecd4522a488a751e465842cdd2a5606b65464b9168bf029a54272"},
+    {file = "regex-2020.10.15-cp37-cp37m-win_amd64.whl", hash = "sha256:ef3a55b16c6450574734db92e0a3aca283290889934a23f7498eaf417e3af9f0"},
+    {file = "regex-2020.10.15-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8958befc139ac4e3f16d44ec386c490ea2121ed8322f4956f83dd9cad8e9b922"},
+    {file = "regex-2020.10.15-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3dd952f3f8dc01b72c0cf05b3631e05c50ac65ddd2afdf26551638e97502107b"},
+    {file = "regex-2020.10.15-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:608d6c05452c0e6cc49d4d7407b4767963f19c4d2230fa70b7201732eedc84f2"},
+    {file = "regex-2020.10.15-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:02686a2f0b1a4be0facdd0d3ad4dc6c23acaa0f38fb5470d892ae88584ba705c"},
+    {file = "regex-2020.10.15-cp38-cp38-win32.whl", hash = "sha256:137da580d1e6302484be3ef41d72cf5c3ad22a076070051b7449c0e13ab2c482"},
+    {file = "regex-2020.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:20cdd7e1736f4f61a5161aa30d05ac108ab8efc3133df5eb70fe1e6a23ea1ca6"},
+    {file = "regex-2020.10.15-cp39-cp39-manylinux1_i686.whl", hash = "sha256:85b733a1ef2b2e7001aff0e204a842f50ad699c061856a214e48cfb16ace7d0c"},
+    {file = "regex-2020.10.15-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:af1f5e997dd1ee71fb6eb4a0fb6921bf7a778f4b62f1f7ef0d7445ecce9155d6"},
+    {file = "regex-2020.10.15-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:b5eeaf4b5ef38fab225429478caf71f44d4a0b44d39a1aa4d4422cda23a9821b"},
+    {file = "regex-2020.10.15-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:aeac7c9397480450016bc4a840eefbfa8ca68afc1e90648aa6efbfe699e5d3bb"},
+    {file = "regex-2020.10.15-cp39-cp39-win32.whl", hash = "sha256:698f8a5a2815e1663d9895830a063098ae2f8f2655ae4fdc5dfa2b1f52b90087"},
+    {file = "regex-2020.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:a51e51eecdac39a50ede4aeed86dbef4776e3b73347d31d6ad0bc9648ba36049"},
+    {file = "regex-2020.10.15.tar.gz", hash = "sha256:d25f5cca0f3af6d425c9496953445bf5b288bb5b71afc2b8308ad194b714c159"},
 ]
 requests = [
     {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
@@ -2924,6 +2935,34 @@ requests = [
 restructuredtext-lint = [
     {file = "restructuredtext_lint-1.3.1.tar.gz", hash = "sha256:470e53b64817211a42805c3a104d2216f6f5834b22fe7adb637d1de4d6501fb8"},
 ]
+"ruamel.yaml" = [
+    {file = "ruamel.yaml-0.16.12-py2.py3-none-any.whl", hash = "sha256:012b9470a0ea06e4e44e99e7920277edf6b46eee0232a04487ea73a7386340a5"},
+    {file = "ruamel.yaml-0.16.12.tar.gz", hash = "sha256:076cc0bc34f1966d920a49f18b52b6ad559fbe656a0748e3535cf7b3f29ebf9e"},
+]
+"ruamel.yaml.clib" = [
+    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:28116f204103cb3a108dfd37668f20abe6e3cafd0d3fd40dba126c732457b3cc"},
+    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:daf21aa33ee9b351f66deed30a3d450ab55c14242cfdfcd377798e2c0d25c9f1"},
+    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win32.whl", hash = "sha256:30dca9bbcbb1cc858717438218d11eafb78666759e5094dd767468c0d577a7e7"},
+    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27m-win_amd64.whl", hash = "sha256:f6061a31880c1ed6b6ce341215336e2f3d0c1deccd84957b6fa8ca474b41e89f"},
+    {file = "ruamel.yaml.clib-0.2.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:73b3d43e04cc4b228fa6fa5d796409ece6fcb53a6c270eb2048109cbcbc3b9c2"},
+    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:53b9dd1abd70e257a6e32f934ebc482dac5edb8c93e23deb663eac724c30b026"},
+    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:839dd72545ef7ba78fd2aa1a5dd07b33696adf3e68fae7f31327161c1093001b"},
+    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win32.whl", hash = "sha256:b1e981fe1aff1fd11627f531524826a4dcc1f26c726235a52fcb62ded27d150f"},
+    {file = "ruamel.yaml.clib-0.2.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4e52c96ca66de04be42ea2278012a2342d89f5e82b4512fb6fb7134e377e2e62"},
+    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a873e4d4954f865dcb60bdc4914af7eaae48fb56b60ed6daa1d6251c72f5337c"},
+    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ab845f1f51f7eb750a78937be9f79baea4a42c7960f5a94dde34e69f3cce1988"},
+    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win32.whl", hash = "sha256:e9f7d1d8c26a6a12c23421061f9022bb62704e38211fe375c645485f38df34a2"},
+    {file = "ruamel.yaml.clib-0.2.2-cp36-cp36m-win_amd64.whl", hash = "sha256:2602e91bd5c1b874d6f93d3086f9830f3e907c543c7672cf293a97c3fabdcd91"},
+    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:44c7b0498c39f27795224438f1a6be6c5352f82cb887bc33d962c3a3acc00df6"},
+    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:8e8fd0a22c9d92af3a34f91e8a2594eeb35cba90ab643c5e0e643567dc8be43e"},
+    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win32.whl", hash = "sha256:464e66a04e740d754170be5e740657a3b3b6d2bcc567f0c3437879a6e6087ff6"},
+    {file = "ruamel.yaml.clib-0.2.2-cp37-cp37m-win_amd64.whl", hash = "sha256:52ae5739e4b5d6317b52f5b040b1b6639e8af68a5b8fd606a8b08658fbd0cab5"},
+    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df5019e7783d14b79217ad9c56edf1ba7485d614ad5a385d1b3c768635c81c0"},
+    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"},
+    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"},
+    {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"},
+    {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"},
+]
 rules = [
     {file = "rules-2.2.tar.gz", hash = "sha256:9bae429f9d4f91a375402990da1541f9e093b0ac077221d57124d06eeeca4405"},
 ]
@@ -2952,20 +2991,20 @@ snowballstemmer = [
     {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"},
 ]
 soupsieve = [
-    {file = "soupsieve-1.9.6-py2.py3-none-any.whl", hash = "sha256:feb1e937fa26a69e08436aad4a9037cd7e1d4c7212909502ba30701247ff8abd"},
-    {file = "soupsieve-1.9.6.tar.gz", hash = "sha256:7985bacc98c34923a439967c1a602dc4f1e15f923b6fcf02344184f86cc7efaa"},
+    {file = "soupsieve-2.0.1-py3-none-any.whl", hash = "sha256:1634eea42ab371d3d346309b93df7870a88610f0725d47528be902a0d95ecc55"},
+    {file = "soupsieve-2.0.1.tar.gz", hash = "sha256:a59dc181727e95d25f781f0eb4fd1825ff45590ec8ff49eadfd7f1a537cc0232"},
 ]
 spdx-license-list = [
-    {file = "spdx_license_list-0.5.0-py3-none-any.whl", hash = "sha256:65c9f598dee3249d529300eb08800f8bf3d0d902868669146ada65192ecd0507"},
-    {file = "spdx_license_list-0.5.0.tar.gz", hash = "sha256:40cd53ff16401bab7059e6d1ef61839196b12079929a2763a50145d3b6949bc1"},
+    {file = "spdx_license_list-0.5.1-py3-none-any.whl", hash = "sha256:32f1401e0077b46ba8b3d9c648b6503ef1d49c41aab51aa13816be2dde3b4a13"},
+    {file = "spdx_license_list-0.5.1.tar.gz", hash = "sha256:64cb5de37724c64cdeccafa2ae68667ff8ccdb7b688f51c1c2be82d7ebe3a112"},
 ]
 sphinx = [
-    {file = "Sphinx-3.1.1-py3-none-any.whl", hash = "sha256:97c9e3bcce2f61d9f5edf131299ee9d1219630598d9f9a8791459a4d9e815be5"},
-    {file = "Sphinx-3.1.1.tar.gz", hash = "sha256:74fbead182a611ce1444f50218a1c5fc70b6cc547f64948f5182fb30a2a20258"},
+    {file = "Sphinx-3.2.1-py3-none-any.whl", hash = "sha256:ce6fd7ff5b215af39e2fcd44d4a321f6694b4530b6f2b2109b64d120773faea0"},
+    {file = "Sphinx-3.2.1.tar.gz", hash = "sha256:321d6d9b16fa381a5306e5a0b76cd48ffbc588e6340059a729c6fdd66087e0e8"},
 ]
 sphinx-autodoc-typehints = [
-    {file = "sphinx-autodoc-typehints-1.11.0.tar.gz", hash = "sha256:bbf0b203f1019b0f9843ee8eef0cff856dc04b341f6dbe1113e37f2ebf243e11"},
-    {file = "sphinx_autodoc_typehints-1.11.0-py3-none-any.whl", hash = "sha256:89e19370a55db4aef1be2094d8fb1fb500ca455c55b3fcc8d2600ff805227e04"},
+    {file = "sphinx-autodoc-typehints-1.11.1.tar.gz", hash = "sha256:244ba6d3e2fdb854622f643c7763d6f95b6886eba24bec28e86edf205e4ddb20"},
+    {file = "sphinx_autodoc_typehints-1.11.1-py3-none-any.whl", hash = "sha256:da049791d719f4c9813642496ee4764203e317f0697eb75446183fa2a68e3f77"},
 ]
 sphinxcontrib-applehelp = [
     {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
@@ -2996,19 +3035,19 @@ sphinxcontrib-serializinghtml = [
     {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"},
 ]
 sqlparse = [
-    {file = "sqlparse-0.3.1-py2.py3-none-any.whl", hash = "sha256:022fb9c87b524d1f7862b3037e541f68597a730a8843245c349fc93e1643dc4e"},
-    {file = "sqlparse-0.3.1.tar.gz", hash = "sha256:e162203737712307dfe78860cc56c8da8a852ab2ee33750e33aeadf38d12c548"},
+    {file = "sqlparse-0.4.1-py3-none-any.whl", hash = "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0"},
+    {file = "sqlparse-0.4.1.tar.gz", hash = "sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8"},
 ]
 stevedore = [
-    {file = "stevedore-2.0.1-py3-none-any.whl", hash = "sha256:c4724f8d7b8f6be42130663855d01a9c2414d6046055b5a65ab58a0e38637688"},
-    {file = "stevedore-2.0.1.tar.gz", hash = "sha256:609912b87df5ad338ff8e44d13eaad4f4170a65b79ae9cb0aa5632598994a1b7"},
+    {file = "stevedore-3.2.2-py3-none-any.whl", hash = "sha256:5e1ab03eaae06ef6ce23859402de785f08d97780ed774948ef16c4652c41bc62"},
+    {file = "stevedore-3.2.2.tar.gz", hash = "sha256:f845868b3a3a77a2489d226568abe7328b5c2d4f6a011cc759dfa99144a521f0"},
 ]
 termcolor = [
     {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"},
 ]
 testfixtures = [
-    {file = "testfixtures-6.14.1-py2.py3-none-any.whl", hash = "sha256:30566e24a1b34e4d3f8c13abf62557d01eeb4480bcb8f1745467bfb0d415a7d9"},
-    {file = "testfixtures-6.14.1.tar.gz", hash = "sha256:58d2b3146d93bc5ddb0cd24e0ccacb13e29bdb61e5c81235c58f7b8ee4470366"},
+    {file = "testfixtures-6.15.0-py2.py3-none-any.whl", hash = "sha256:e17f4f526fc90b0ac9bc7f8ca62b7dec17d9faf3d721f56bda4f0fd94d02f85a"},
+    {file = "testfixtures-6.15.0.tar.gz", hash = "sha256:409f77cfbdad822d12a8ce5c4aa8fb4d0bb38073f4a5444fede3702716a2cec2"},
 ]
 "testing.common.database" = [
     {file = "testing.common.database-2.0.3-py2.py3-none-any.whl", hash = "sha256:e3ed492bf480a87f271f74c53b262caf5d85c8bc09989a8f534fa2283ec52492"},
@@ -3027,11 +3066,11 @@ toml = [
     {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"},
 ]
 tqdm = [
-    {file = "tqdm-4.46.1-py2.py3-none-any.whl", hash = "sha256:07c06493f1403c1380b630ae3dcbe5ae62abcf369a93bbc052502279f189ab8c"},
-    {file = "tqdm-4.46.1.tar.gz", hash = "sha256:cd140979c2bebd2311dfb14781d8f19bd5a9debb92dcab9f6ef899c987fcf71f"},
+    {file = "tqdm-4.50.2-py2.py3-none-any.whl", hash = "sha256:43ca183da3367578ebf2f1c2e3111d51ea161ed1dc4e6345b86e27c2a93beff7"},
+    {file = "tqdm-4.50.2.tar.gz", hash = "sha256:69dfa6714dee976e2425a9aab84b622675b7b1742873041e3db8a8e86132a4af"},
 ]
 twilio = [
-    {file = "twilio-6.43.0.tar.gz", hash = "sha256:1ff3b66992ebb59411794f669eab7f11bcfaacc5549eec1afb47af1c755872ac"},
+    {file = "twilio-6.46.0.tar.gz", hash = "sha256:9d591617b22e75b26cda11a10d353e2001d990a7ca1696d92e50abfc6ecdcb73"},
 ]
 typed-ast = [
     {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"},
@@ -3057,31 +3096,27 @@ typed-ast = [
     {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"},
 ]
 typing-extensions = [
-    {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"},
-    {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"},
-    {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"},
+    {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
+    {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
+    {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
 ]
 urllib3 = [
-    {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
-    {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
+    {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"},
+    {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"},
 ]
 vine = [
     {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"},
     {file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"},
 ]
-wcwidth = [
-    {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
-    {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
-]
 webencodings = [
     {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
     {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
 ]
 yubiotp = [
-    {file = "YubiOTP-0.2.2.post1-py2.py3-none-any.whl", hash = "sha256:7e281801b24678f4bda855ce8ab975a7688a912f5a6cb22b6c2b16263a93cbd2"},
-    {file = "YubiOTP-0.2.2.post1.tar.gz", hash = "sha256:de83b1560226e38b5923f6ab919f962c8c2abb7c722104cb45b2b6db2ac86e40"},
+    {file = "YubiOTP-1.0.0.post1-py2.py3-none-any.whl", hash = "sha256:7ad57011866e0bc6c6d179ffbc3926fcc0e82d410178a6d01ba4da0f88332878"},
+    {file = "YubiOTP-1.0.0.post1.tar.gz", hash = "sha256:c13825f7b76a69afb92f19521f4dea9f5031d70f45123b505dc2e0ac03132065"},
 ]
 zipp = [
-    {file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"},
-    {file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"},
+    {file = "zipp-3.3.1-py3-none-any.whl", hash = "sha256:16522f69653f0d67be90e8baa4a46d66389145b734345d68a257da53df670903"},
+    {file = "zipp-3.3.1.tar.gz", hash = "sha256:c1532a8030c32fd52ff6a288d855fe7adef5823ba1d26a29a68fd6314aa72baa"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index f040f25c445107b92ab98dfa63885c0bbde7ddea..467272f8e9b3bfa56513df2cee88e62b5227d7f7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -37,15 +37,15 @@ django-middleware-global-request = "^0.1.2"
 django-menu-generator = "^1.0.4"
 django-tables2 = "^2.1"
 Pillow = "^7.0"
-django-phonenumber-field = {version = ">=3.0, <4.0", extras = ["phonenumbers"]}
+django-phonenumber-field = {version = "<5.1", extras = ["phonenumbers"]}
 django-sass-processor = "^0.8"
 libsass = "^0.20.0"
 colour = "^0.1.5"
-dynaconf = {version = "^2.0", extras = ["yaml", "toml", "ini"]}
+dynaconf = {version = "^3.1", extras = ["yaml", "toml", "ini"]}
 django-settings-context-processor = "^0.2"
 django-auth-ldap = { version = "^2.2", optional = true }
-django-maintenance-mode = "^0.14.0"
-django-ipware = "^2.1"
+django-maintenance-mode = "^0.15.0"
+django-ipware = "^3.0"
 easy-thumbnails = "^2.6"
 django-image-cropping = "^1.2"
 django-impersonate = "^1.4"
@@ -54,7 +54,7 @@ django-hattori = "^0.2"
 psycopg2 = "^2.8"
 django_select2 = "^7.1"
 requests = "^2.22"
-django-two-factor-auth = { version = "^1.11.0", extras = [ "yubikey", "phonenumbers", "call", "sms" ] }
+django-two-factor-auth = { version = "^1.12.1", extras = [ "yubikey", "phonenumbers", "call", "sms" ] }
 django-yarnpkg = "^6.0"
 django-material = "^1.6.0"
 django-pwa = "^1.0.8"
@@ -63,7 +63,7 @@ django_widget_tweaks = "^1.4.5"
 django-filter = "^2.2.0"
 django-templated-email = "^2.3.0"
 html2text = "^2020.0.0"
-django-ckeditor = "^5.8.0"
+django-ckeditor = "^6.0.0"
 django-js-reverse = "^0.9.1"
 calendarweek = "^0.4.3"
 Celery = {version="^4.4.0", optional=true, extras=["django", "redis"]}
@@ -71,8 +71,7 @@ django-celery-results = {version="^1.1.2", optional=true}
 django-celery-beat = {version="^2.0.0", optional=true}
 django-celery-email = {version="^3.0.0", optional=true}
 django-jsonstore = "^0.4.1"
-django-polymorphic = "^2.1.2"
-django-otp = "0.9.3"
+django-polymorphic = "^3.0.0"
 django-colorfield = "^0.3.0"
 django-bleach = "^0.6.1"
 django-guardian = "^2.2.0"
@@ -87,7 +86,7 @@ django-reversion = "^3.0.7"
 django-favicon-plus-reloaded = "^1.0.4"
 django-health-check = "^3.12.1"
 psutil = "^5.7.0"
-celery-progress = "^0.0.10"
+celery-progress = "^0.0.12"
 
 [tool.poetry.extras]
 ldap = ["django-auth-ldap"]
@@ -98,7 +97,7 @@ sphinx = "^3.0"
 sphinxcontrib-django = "^0.5.0"
 sphinx-autodoc-typehints = "^1.7"
 django-stubs = "^1.1"
-pytest = "^5.3"
+pytest = "^6.0"
 pytest-django = "^3.7"
 pytest-django-testing-postgresql = "^0.1"
 selenium = "^3.141.0"
@@ -113,8 +112,8 @@ flake8-docstrings = "^1.5.0"
 flake8-rst-docstrings = "^0.0.13"
 black = "^19.10b0"
 flake8-black = "^0.2.0"
-isort = "^4.3.21"
-flake8-isort = "^3.0.0"
+isort = "^5.0.0"
+flake8-isort = "^4.0.0"
 pytest-cov = "^2.8.1"
 pytest-sugar = "^0.9.2"
 
diff --git a/tox.ini b/tox.ini
index 3729453a385969ca89622ab38e214b4b7ae9a104..eca63a758a5f6a20b1cd11887330817fec7908d7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -23,7 +23,7 @@ setenv =
 [testenv:lint]
 commands =
     - poetry run black --check --diff aleksis/
-    - poetry run isort -c --diff --stdout -rc aleksis/
+    - poetry run isort -c --diff --stdout aleksis/
     poetry run flake8 {posargs} aleksis/
 
 [testenv:security]
@@ -40,7 +40,7 @@ commands = poetry run make -C docs/ html {posargs}
 
 [testenv:reformat]
 commands =
-    poetry run isort -rc aleksis/
+    poetry run isort aleksis/
     poetry run black aleksis/
 
 [flake8]
@@ -52,7 +52,6 @@ ignore = BLK100,E203,E231,W503,D100,D101,D102,D103,D104,D105,D106,D107,RST215,RS
 line_length = 100
 multi_line_output = 3
 include_trailing_comma = 1
-use_parantheses = 1
 default_section = THIRDPARTY
 known_first_party = aleksis
 known_django = django