diff --git a/aleksis/apps/ticdesk/filters.py b/aleksis/apps/ticdesk/filters.py
index 8cf1120f631e3e360f18551219296220c243181d..869ddbcbed5f93285e831c2d9a853ffc8c446849 100644
--- a/aleksis/apps/ticdesk/filters.py
+++ b/aleksis/apps/ticdesk/filters.py
@@ -16,9 +16,7 @@ class EventRegistrationFilter(FilterSet):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
-        self.form.layout = Layout(
-            Row("person", "event"), Row("accept_sepa", "date_registred"),
-        )
+        self.form.layout = Layout(Row("person", "event"), Row("accept_sepa", "date_registred"),)
 
 
 class TeckidsMemberFilter(FilterSet):
@@ -41,9 +39,7 @@ class TeckidsMemberFilter(FilterSet):
 
 
 class VoucherFilter(FilterSet):
-    event = MultipleCharFilter(
-        ["event__short_name__icontains",], label=_("Search by event"),
-    )
+    event = MultipleCharFilter(["event__short_name__icontains",], label=_("Search by event"),)
 
     name = MultipleCharFilter(
         ["person__first_name__icontains", "person__last_name__icontains",],
diff --git a/aleksis/apps/ticdesk/forms.py b/aleksis/apps/ticdesk/forms.py
index e5f87a1a7270f6d39f1dac80fa4481bb9e3241d8..2dae94b1f9619918bd6b49eb90769ce62b5c211f 100644
--- a/aleksis/apps/ticdesk/forms.py
+++ b/aleksis/apps/ticdesk/forms.py
@@ -5,7 +5,6 @@ from django import forms
 from django.utils.translation import ugettext_lazy as _
 
 import phonenumbers
-from django_select2.forms import ModelSelect2MultipleWidget
 from django_starfield import Stars
 from material import Fieldset, Layout, Row
 
@@ -13,13 +12,7 @@ from aleksis.core.mixins import ExtensibleForm
 from aleksis.core.models import Group, Person
 from aleksis.core.util.core_helpers import get_site_preferences
 
-from .models import (
-    EventRegistration,
-    FeedbackAspect,
-    TeckidsMember,
-    TeckidsEvent,
-    Voucher,
-)
+from .models import EventRegistration, FeedbackAspect, TeckidsEvent, TeckidsMember, Voucher
 
 COMMENT_CHOICES = [
     ("first", _("Only first name")),
@@ -56,10 +49,7 @@ def is_phonenumber(number):
 
 def is_valid_voucher_for(event_cn):
     def _is_valid_voucher(code):
-        if (
-            Voucher.objects.filter(code=code, event_cn=event_cn, used=False).count()
-            == 0
-        ):
+        if Voucher.objects.filter(code=code, event_cn=event_cn, used=False).count() == 0:
             raise forms.ValidationError(_("The voucher is invalid!"))
 
     return _is_valid_voucher
@@ -92,19 +82,13 @@ class EventAdditionalSurveyForm(forms.Form):
 
             if choices:
                 choices_map = [
-                    (re.sub(r"[^A-Za-z0-9]|^(?=\d)", "_", choice), choice)
-                    for choice in choices
+                    (re.sub(r"[^A-Za-z0-9]|^(?=\d)", "_", choice), choice) for choice in choices
                 ]
                 field_attr = forms.ChoiceField(
-                    label=label,
-                    help_text=help_text,
-                    choices=choices_map,
-                    required=False,
+                    label=label, help_text=help_text, choices=choices_map, required=False,
                 )
             else:
-                field_attr = forms.CharField(
-                    label=label, help_text=help_text, required=False
-                )
+                field_attr = forms.CharField(label=label, help_text=help_text, required=False)
 
             new_fields[var] = field_attr
 
@@ -129,10 +113,7 @@ class EventFeedbackForm(ExtensibleForm):
         fields = []
 
     layout = Layout(
-        Fieldset(
-            _("Comments"),
-            Row("comment_private", "comment_public", "comment_public_info"),
-        ),
+        Fieldset(_("Comments"), Row("comment_private", "comment_public", "comment_public_info"),),
         Fieldset(_("Photos"), Row("photos", "photos_licence"),),
         Fieldset(_("Feedback aspects"),),
     )
@@ -196,9 +177,12 @@ class EditEventForm(forms.ModelForm):
     """Form to create or edit an event."""
 
     layout = Layout(
-        Fieldset(_("Base data"), Row("group", "description", Row("place"), "published"),
-        Fieldset(_("Date data"), Row("date_event", "date_registration", "date_retraction")),
-        Fieldset(_("Feedback aspects"), "feedback_aspects")),
+        Fieldset(
+            _("Base data"),
+            Row("group", "description", Row("place"), "published"),
+            Fieldset(_("Date data"), Row("date_event", "date_registration", "date_retraction")),
+            Fieldset(_("Feedback aspects"), "feedback_aspects"),
+        ),
     )
 
     class Meta:
@@ -239,33 +223,18 @@ class RegisterEventForm(forms.ModelForm):
     """Form to register for an event."""
 
     layout = Layout(
-        Fieldset(
-            _("Address data"),
-            Row("street", "housenumber"),
-            Row("postal_code", "place"),
-        ),
+        Fieldset(_("Address data"), Row("street", "housenumber"), Row("postal_code", "place"),),
         Fieldset(_("Contact details"), Row("mobile_number", "email"),),
         Fieldset(_("Personal data"), Row("date_of_birth", "sex"),),
         Fieldset(_("School details"), Row("school", "school_place", "school_class"),),
+        Fieldset(_("Guardians personal data"), Row("guardian_first_name", "guardian_last_name"),),
+        Fieldset(_("Guardians contact details"), Row("guardian_email", "guardian_mobile_number"),),
         Fieldset(
-            _("Guardians personal data"),
-            Row("guardian_first_name", "guardian_last_name"),
+            _("General event information"), Row("event", "person"), Row("comment", "channel"),
         ),
+        Fieldset(_("Financial data"), "voucher_code", Row("iban", "donation", "accept_sepa"),),
         Fieldset(
-            _("Guardians contact details"),
-            Row("guardian_email", "guardian_mobile_number"),
-        ),
-        Fieldset(
-            _("General event information"),
-            Row("event", "person"),
-            Row("comment", "channel"),
-        ),
-        Fieldset(
-            _("Financial data"), "voucher_code", Row("iban", "donation", "accept_sepa"),
-        ),
-        Fieldset(
-            _("Declaration of consent"),
-            Row("accept_terms", "accept_data", "accept_general_terms"),
+            _("Declaration of consent"), Row("accept_terms", "accept_data", "accept_general_terms"),
         ),
     )
 
@@ -389,21 +358,16 @@ class RegisterEventForm(forms.ModelForm):
 
     school = forms.CharField(
         label=_("School"),
-        help_text=_(
-            "Please enter the name of your school as exactly as it should be written."
-        ),
+        help_text=_("Please enter the name of your school as exactly as it should be written."),
     )
 
     school_place = forms.CharField(
         label=_("School place"),
-        help_text=_(
-            "Enter the place (city) where your school is located (without a district)."
-        ),
+        help_text=_("Enter the place (city) where your school is located (without a district)."),
     )
 
     school_class = forms.CharField(
-        label=_("School class"),
-        help_text=_("Please enter the class you are going to (e.g. 8a)."),
+        label=_("School class"), help_text=_("Please enter the class you are going to (e.g. 8a)."),
     )
 
     def __init__(self, *args, **kwargs):
@@ -449,16 +413,11 @@ class EditEventRegistrationForm(forms.ModelForm):
 
     layout = Layout(
         Fieldset(
-            _("General event information"),
-            Row("event", "person"),
-            Row("comment", "channel"),
-        ),
-        Fieldset(
-            _("Financial data"), "voucher_code", Row("iban", "donation", "accept_sepa"),
+            _("General event information"), Row("event", "person"), Row("comment", "channel"),
         ),
+        Fieldset(_("Financial data"), "voucher_code", Row("iban", "donation", "accept_sepa"),),
         Fieldset(
-            _("Declaration of consent"),
-            Row("accept_terms", "accept_data", "accept_general_terms"),
+            _("Declaration of consent"), Row("accept_terms", "accept_data", "accept_general_terms"),
         ),
     )
 
diff --git a/aleksis/apps/ticdesk/menus.py b/aleksis/apps/ticdesk/menus.py
index 59582839da9fb93af4a796e28821a39a32c6a76e..bf1946a40049e6745987ff4bb056c4747c099a9c 100644
--- a/aleksis/apps/ticdesk/menus.py
+++ b/aleksis/apps/ticdesk/menus.py
@@ -9,10 +9,7 @@ MENUS = {
             "icon": "confirmation_number",
             "root": True,
             "validators": [
-                (
-                    "aleksis.core.util.predicates.permission_validator",
-                    "ticdesk.view_vouchers",
-                )
+                ("aleksis.core.util.predicates.permission_validator", "ticdesk.view_vouchers",)
             ],
             "submenu": [
                 {
@@ -45,10 +42,7 @@ MENUS = {
             "icon": "event_note",
             "root": True,
             "validators": [
-                (
-                    "aleksis.core.util.predicates.permission_validator",
-                    "ticdesk.edit_event",
-                )
+                ("aleksis.core.util.predicates.permission_validator", "ticdesk.edit_event",)
             ],
             "submenu": [
                 {
@@ -89,10 +83,7 @@ MENUS = {
                     "url": "manage_events",
                     "icon": "edit",
                     "validators": [
-                        (
-                            "aleksis.core.util.predicates.permission_validator",
-                            "ticdesk.edit_event",
-                        )
+                        ("aleksis.core.util.predicates.permission_validator", "ticdesk.edit_event",)
                     ],
                 },
                 {
diff --git a/aleksis/apps/ticdesk/model_extensions.py b/aleksis/apps/ticdesk/model_extensions.py
index 7009b57a315692f0c4bb7e075ac686bf0d06cf4c..09f8924238190ac1365e7b7e3bcb447259e5661d 100644
--- a/aleksis/apps/ticdesk/model_extensions.py
+++ b/aleksis/apps/ticdesk/model_extensions.py
@@ -4,7 +4,6 @@ from jsonstore import CharField
 
 from aleksis.core.models import Person
 
-
 # Additional fields for persons
 Person.field(school=CharField(verbose_name=_("Name of school")))
 Person.field(school_class=CharField(verbose_name=_("School class")))
diff --git a/aleksis/apps/ticdesk/models.py b/aleksis/apps/ticdesk/models.py
index e2f10aa27f7319789f7ce80f5dcc2bacf2472dc7..0a43cc03522b87372ad89ff0604ed3fe1d673770 100644
--- a/aleksis/apps/ticdesk/models.py
+++ b/aleksis/apps/ticdesk/models.py
@@ -5,26 +5,18 @@ from django.utils.translation import gettext_lazy as _
 from django_iban.fields import IBANField
 
 from aleksis.core.mixins import ExtensibleModel, PureDjangoModel
-from aleksis.core.models import Person, Group
+from aleksis.core.models import Group, Person
 
 
 class TeckidsMember(ExtensibleModel):
-    employee_number = models.PositiveIntegerField(
-        unique=True, verbose_name=_("Employee number")
-    )
+    employee_number = models.PositiveIntegerField(unique=True, verbose_name=_("Employee number"))
     member_since = models.DateField(verbose_name=_("Member since"))
-    member_until = models.DateField(
-        verbose_name=_("Member until"), blank=True, null=True
-    )
+    member_until = models.DateField(verbose_name=_("Member until"), blank=True, null=True)
     title = models.TextField(verbose_name=_("Title / Role"))
 
-    dues = models.PositiveIntegerField(
-        verbose_name=_("Membership dues in €"), default=60
-    )
+    dues = models.PositiveIntegerField(verbose_name=_("Membership dues in €"), default=60)
     dues_sepa = models.DateField(
-        verbose_name=_("Membership dues SEPA direct debit mandate"),
-        blank=True,
-        null=True,
+        verbose_name=_("Membership dues SEPA direct debit mandate"), blank=True, null=True,
     )
     person = models.ForeignKey(Person, on_delete=models.CASCADE)
 
@@ -60,7 +52,9 @@ class TeckidsEvent(ExtensibleModel):
         verbose_name_plural = _("Teckids events")
 
     # Event details
-    group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name=_("Group"), related_name="event")
+    group = models.ForeignKey(
+        Group, on_delete=models.CASCADE, verbose_name=_("Group"), related_name="event"
+    )
     description = models.CharField(max_length=500, verbose_name=_("Description"))
     published = models.BooleanField(default=False, verbose_name=_("Publish"))
     place = models.CharField(max_length=50, verbose_name="Place")
@@ -86,9 +80,7 @@ class TeckidsEvent(ExtensibleModel):
 
         if request and request.user.is_authenticated:
             if (
-                Voucher.objects.filter(
-                    event=self, person=request.user.person, used=False
-                ).count()
+                Voucher.objects.filter(event=self, person=request.user.person, used=False).count()
                 > 0
             ):
                 return True
@@ -118,7 +110,7 @@ class Voucher(ExtensibleModel):
         verbose_name = _("Vouchers")
         verbose_name_plural = _("Vouchers")
 
-    code = models.CharField(max_length=8, blank=True, null=True)
+    code = models.CharField(max_length=8, blank=True)
     event = models.ForeignKey(
         TeckidsEvent,
         related_name="vouchers",
@@ -127,15 +119,18 @@ class Voucher(ExtensibleModel):
         null=True,
     )
     person = models.ForeignKey(
-        Person,
-        related_name="vouchers",
-        verbose_name=_("Person"),
-        on_delete=models.CASCADE,
+        Person, related_name="vouchers", verbose_name=_("Person"), on_delete=models.CASCADE,
     )
     discount = models.IntegerField(default=100)
 
     used = models.BooleanField(default=False)
-    used_person_uid = models.ForeignKey(Person, on_delete=models.CASCADE, verbose_name=_("Used by"), related_name="used_vouchers", null=True)
+    used_person_uid = models.ForeignKey(
+        Person,
+        on_delete=models.CASCADE,
+        verbose_name=_("Used by"),
+        related_name="used_vouchers",
+        null=True,
+    )
     deleted = models.BooleanField(default=False)
 
     def __str__(self) -> str:
@@ -158,55 +153,33 @@ class GlobalPermissions(models.Model, PureDjangoModel):
             ("view_registrations", _("Can view registrations")),
         )
 
+    def __str__() -> str:
+        return "Global permission"
+
 
 class EventRegistration(ExtensibleModel):
     class Meta:
         verbose_name = _("Registration")
         verbose_name_plural = _("Registrations")
 
-    event = models.ForeignKey(
-        TeckidsEvent, on_delete=models.CASCADE, verbose_name=_("Event")
-    )
-    person = models.ForeignKey(
-        Person, on_delete=models.CASCADE, verbose_name=_("Person")
-    )
-    date_registred = models.DateTimeField(
-        auto_now_add=True, verbose_name=_("Registration date")
-    )
+    event = models.ForeignKey(TeckidsEvent, on_delete=models.CASCADE, verbose_name=_("Event"))
+    person = models.ForeignKey(Person, on_delete=models.CASCADE, verbose_name=_("Person"))
+    date_registred = models.DateTimeField(auto_now_add=True, verbose_name=_("Registration date"))
 
-    comment = models.TextField(
-        verbose_name=_("Comment / remarks"), blank=True, null=True
-    )
-    channel = models.CharField(
-        verbose_name=_("Channel"),
-        max_length=255,
-        blank=True,
-        null=True,
-    )
+    comment = models.TextField(verbose_name=_("Comment / remarks"), blank=True)
+    channel = models.CharField(verbose_name=_("Channel"), max_length=255, blank=True)
     voucher = models.ForeignKey(
-        Voucher,
-        on_delete=models.CASCADE,
-        verbose_name=_("Voucher"),
-        blank=True,
-        null=True,
-    )
-    donation = models.PositiveIntegerField(
-        verbose_name=_("Donation"), blank=True, null=True
+        Voucher, on_delete=models.CASCADE, verbose_name=_("Voucher"), blank=True, null=True,
     )
+    donation = models.PositiveIntegerField(verbose_name=_("Donation"), blank=True, null=True)
 
     accept_sepa = models.BooleanField(verbose_name=_("SEPA direct debit"))
     iban = IBANField(
-        verbose_name=_("IBAN (for SEPA direct debit)"),
-        enforce_database_constraint=True,
-        null=True,
+        verbose_name=_("IBAN (for SEPA direct debit)"), enforce_database_constraint=True, null=True,
     )
 
-    accept_terms = models.BooleanField(
-        verbose_name=_("Delcaration of consent by parents")
-    )
-    accept_data = models.BooleanField(
-        verbose_name=_("Declaration of consent data protection")
-    )
+    accept_terms = models.BooleanField(verbose_name=_("Delcaration of consent by parents"))
+    accept_data = models.BooleanField(verbose_name=_("Declaration of consent data protection"))
     accept_general_terms = models.BooleanField(
         verbose_name=_("Declatation of consent terms and condition")
     )
diff --git a/aleksis/apps/ticdesk/predicates.py b/aleksis/apps/ticdesk/predicates.py
index 2619055afef34cf4786486d966fd819c574c6623..7288954a4858f7508debda30ea30e331a44fa86a 100644
--- a/aleksis/apps/ticdesk/predicates.py
+++ b/aleksis/apps/ticdesk/predicates.py
@@ -5,7 +5,7 @@ from rules import predicate
 from aleksis.core.models import Group, Person
 from aleksis.core.util.predicates import check_object_permission
 
-from .models import Voucher, EventRegistration
+from .models import EventRegistration, Voucher
 
 User = get_user_model()
 
@@ -29,12 +29,10 @@ def see_owned_groups_members(user: User, person: Person) -> bool:
 @predicate
 def is_own_voucher(user: User, voucher: Voucher) -> bool:
     """Predicate which checks if the voucher belongs to the user."""
-
     return voucher.person == user.person
 
 
 @predicate
 def is_own_registration(user: User, registration: EventRegistration) -> bool:
     """Predicate which checks if the registration belongs to the user."""
-
     return registration.person == user.person
diff --git a/aleksis/apps/ticdesk/rules.py b/aleksis/apps/ticdesk/rules.py
index 102ca794f77a119618dba596ba7ec51a66c0a855..9d162f1d62361df7e29fa60435cb773f38904801 100644
--- a/aleksis/apps/ticdesk/rules.py
+++ b/aleksis/apps/ticdesk/rules.py
@@ -9,62 +9,55 @@ from aleksis.core.util.predicates import (
     is_group_member,
 )
 
-from .models import EventRegistration, FeedbackAspect, TeckidsMember, TeckidsEvent, Voucher
+from .models import EventRegistration, FeedbackAspect, TeckidsEvent, TeckidsMember, Voucher
 from .predicates import (
+    is_own_registration,
     is_own_voucher,
     see_group_by_grouptype,
     see_owned_groups_members,
-    is_own_registration,
 )
 
 # View vouchers
 view_vouchers_predicate = has_person & (
-    has_global_perm("ticdesk.view_vouchers")
-    | has_any_object("ticdesk.view_vouchers", Voucher)
+    has_global_perm("ticdesk.view_vouchers") | has_any_object("ticdesk.view_vouchers", Voucher)
 )
 add_perm("ticdesk.view_vouchers", view_vouchers_predicate)
 
 # Edit vouchers
 edit_vouchers_predicate = has_person & (
-    has_global_perm("ticdesk.edit_vouchers")
-    | has_any_object("ticdesk.edit_vouchers", Voucher)
+    has_global_perm("ticdesk.edit_vouchers") | has_any_object("ticdesk.edit_vouchers", Voucher)
 )
 add_perm("ticdesk.edit_vouchers", edit_vouchers_predicate)
 
 
 # Delete vouchers
 delete_vouchers_predicate = has_person & (
-    has_global_perm("ticdesk.delete_vouchers")
-    | has_any_object("ticdesk.delete_vouchers", Voucher)
+    has_global_perm("ticdesk.delete_vouchers") | has_any_object("ticdesk.delete_vouchers", Voucher)
 )
 add_perm("ticdesk.delete_vouchers", delete_vouchers_predicate)
 
 # Create vouchers
 create_vouchers_predicate = has_person & (
-    has_global_perm("ticdesk.create_vouchers")
-    | has_any_object("ticdesk.create_vouchers", Voucher)
+    has_global_perm("ticdesk.create_vouchers") | has_any_object("ticdesk.create_vouchers", Voucher)
 )
 add_perm("ticdesk.create_vouchers", create_vouchers_predicate)
 
 # Edit events
 edit_events_predicate = has_person & (
-    has_global_perm("ticdesk.edit_events")
-    | has_any_object("ticdesk.edit_events", TeckidsEvent)
+    has_global_perm("ticdesk.edit_events") | has_any_object("ticdesk.edit_events", TeckidsEvent)
 )
 add_perm("ticdesk.edit_events", edit_events_predicate)
 
 
 # Delete events
 delete_events_predicate = has_person & (
-    has_global_perm("ticdesk.delete_events")
-    | has_any_object("ticdesk.delete_events", TeckidsEvent)
+    has_global_perm("ticdesk.delete_events") | has_any_object("ticdesk.delete_events", TeckidsEvent)
 )
 add_perm("ticdesk.delete_events", delete_events_predicate)
 
 # Create events
 create_events_predicate = has_person & (
-    has_global_perm("ticdesk.create_events")
-    | has_any_object("ticdesk.create_events", TeckidsEvent)
+    has_global_perm("ticdesk.create_events") | has_any_object("ticdesk.create_events", TeckidsEvent)
 )
 add_perm("ticdesk.create_events", create_events_predicate)
 
diff --git a/aleksis/apps/ticdesk/tables.py b/aleksis/apps/ticdesk/tables.py
index 2723de05664759706c60a6b4e70e872b947d3695..47cac3239ad1b7ef74b3398637f18b8e9ce5c5af 100644
--- a/aleksis/apps/ticdesk/tables.py
+++ b/aleksis/apps/ticdesk/tables.py
@@ -14,10 +14,7 @@ class EventsTable(tables.Table):
     date_registration = tables.Column(verbose_name=_("Registration until"))
 
     short_name = tables.LinkColumn(
-        "register_event_by_id",
-        args=[A("id")],
-        verbose_name=_("Register"),
-        text=_("Register"),
+        "register_event_by_id", args=[A("id")], verbose_name=_("Register"), text=_("Register"),
     )
 
 
@@ -29,10 +26,7 @@ class ParticipatedEventsTable(tables.Table):
     date_event = tables.Column(verbose_name=_("Date"))
 
     short_name = tables.LinkColumn(
-        "feedback_event_by_id",
-        args=[A("id")],
-        verbose_name=_("Feedback"),
-        text=_("Feedback"),
+        "feedback_event_by_id", args=[A("id")], verbose_name=_("Feedback"), text=_("Feedback"),
     )
 
 
@@ -59,15 +53,12 @@ class VouchersTable(tables.Table):
     code = tables.Column(verbose_name=_("Code"))
     person = tables.Column(verbose_name=_("Person"))
     deleted = tables.LinkColumn(
-        "delete_voucher_by_id",
-        args=[A("id")],
-        verbose_name=_("Delete"),
-        text=_("Delete"),
+        "delete_voucher_by_id", args=[A("id")], verbose_name=_("Delete"), text=_("Delete"),
     )
     edit = tables.LinkColumn(
         "edit_voucher_by_id", args=[A("id")], verbose_name=_("Edit"), text=_("Edit")
     )
-    print = tables.LinkColumn(
+    print_voucher = tables.LinkColumn(
         "print_voucher_by_id", args=[A("id")], verbose_name=_("Print"), text=_("Print")
     )
 
@@ -80,10 +71,7 @@ class EventRegistrationsTable(tables.Table):
     event = tables.Column()
     date_registred = tables.Column()
     view = tables.LinkColumn(
-        "registration_by_id",
-        args=[A("id")],
-        verbose_name=_("View registration"),
-        text=_("View"),
+        "registration_by_id", args=[A("id")], verbose_name=_("View registration"), text=_("View"),
     )
 
 
@@ -96,10 +84,7 @@ class TeckidsMemberTable(tables.Table):
     member_since = tables.Column()
     member_until = tables.Column()
     edit = tables.LinkColumn(
-        "edit_member_by_id",
-        args=[A("id")],
-        verbose_name=_("Edit member"),
-        text=_("Edit"),
+        "edit_member_by_id", args=[A("id")], verbose_name=_("Edit member"), text=_("Edit"),
     )
 
 
@@ -110,8 +95,5 @@ class FeedbackAspectsTable(tables.Table):
     aspect = tables.Column()
 
     edit = tables.LinkColumn(
-        "edit_feedback_aspect_by_id",
-        args=[A("id")],
-        verbose_name=_("Edit"),
-        text=_("Edit"),
+        "edit_feedback_aspect_by_id", args=[A("id")], verbose_name=_("Edit"), text=_("Edit"),
     )
diff --git a/aleksis/apps/ticdesk/urls.py b/aleksis/apps/ticdesk/urls.py
index f0c731b1d06f18c5e0ea5146d46e15307287fd50..0cc63ecdf4b7a9429f14b466405bf63d8ecb8797 100644
--- a/aleksis/apps/ticdesk/urls.py
+++ b/aleksis/apps/ticdesk/urls.py
@@ -10,17 +10,13 @@ urlpatterns = [
     path("events/manage", views.ManageEvents.as_view(), name="manage_events"),
     path("events/", views.events, name="events"),
     path("vouchers/create", views.edit_voucher, name="create_vouchers"),
-    path(
-        "vouchers/<int:id_>/delete", views.delete_voucher, name="delete_voucher_by_id"
-    ),
+    path("vouchers/<int:id_>/delete", views.delete_voucher, name="delete_voucher_by_id"),
     path("vouchers/<int:id_>/edit", views.edit_voucher, name="edit_voucher_by_id"),
     path("vouchers/<int:id_>/print", views.print_voucher, name="print_voucher_by_id"),
     path("vouchers/", views.vouchers, name="vouchers"),
     path("event/lists/generate", views.generate_lists, name="generate_lists"),
     path("event/registrations/list", views.registrations, name="registrations"),
-    path(
-        "event/registrations/<int:id_>", views.registration, name="registration_by_id"
-    ),
+    path("event/registrations/<int:id_>", views.registration, name="registration_by_id"),
     path(
         "event/registrations/<int:id_>/edit",
         views.edit_registration,
@@ -34,13 +30,9 @@ urlpatterns = [
     path("members/list", views.members, name="members"),
     path("members/create", views.edit_member, name="create_member"),
     path("members/<int:id_>/edit", views.edit_member, name="edit_member_by_id"),
+    path("event/feedback_aspects/list", views.feedback_aspects, name="feedback_aspects"),
     path(
-        "event/feedback_aspects/list", views.feedback_aspects, name="feedback_aspects"
-    ),
-    path(
-        "event/feedback_aspects/create",
-        views.edit_feedback_aspect,
-        name="create_feedback_aspect",
+        "event/feedback_aspects/create", views.edit_feedback_aspect, name="create_feedback_aspect",
     ),
     path(
         "event/feedback_aspects/<int:id_>/edit",
diff --git a/aleksis/apps/ticdesk/util.py b/aleksis/apps/ticdesk/util.py
index cfc51db11ae79cd0a1fdb288eff7cbc897369cc3..b0133f6f60706d0fcca3bc3a9fb55ca4a9d54db1 100644
--- a/aleksis/apps/ticdesk/util.py
+++ b/aleksis/apps/ticdesk/util.py
@@ -17,9 +17,7 @@ def subscribe_mailinglist(listname, mail):
         "action": "subrequest",
         "via_subrequest": 1,
     }
-    return requests.post(
-        get_site_preferences()["ticdesk__wws_post_url"], data=form_data
-    )
+    return requests.post(get_site_preferences()["ticdesk__wws_post_url"], data=form_data)
 
 
 def form_to_text_table(form, width=74, sep=" | "):
@@ -28,9 +26,7 @@ def form_to_text_table(form, width=74, sep=" | "):
     for field_name, field in form.fields.items():
         # Determine field value depending on field type
         if isinstance(field, forms.ModelMultipleChoiceField):
-            value = "\n".join(
-                [choice.__str__() for choice in form.cleaned_data[field_name]]
-            )
+            value = "\n".join([choice.__str__() for choice in form.cleaned_data[field_name]])
         elif isinstance(field, forms.ModelChoiceField):
             value = dict(field.choices)[form.cleaned_data[field_name]]
         else:
@@ -85,6 +81,6 @@ def upload_file_to_media_url(file, subdir="", prefix="upload_"):
 def generate_code():
     alphabet = string.ascii_uppercase + string.digits
     length = 8
-    code = "".join(random.choice(alphabet) for _ in range(length))
+    code = "".join(random.choice(alphabet) for _ in range(length))  # noqa
 
     return code
diff --git a/aleksis/apps/ticdesk/views.py b/aleksis/apps/ticdesk/views.py
index 5affb011b040f533dd2ae518d33d4c7b608f7b36..4b06518382b1168b3816521030853d81f6336127 100644
--- a/aleksis/apps/ticdesk/views.py
+++ b/aleksis/apps/ticdesk/views.py
@@ -1,20 +1,18 @@
 import json
-import re
 from typing import Optional
 
 from django.contrib.auth.decorators import login_required
 from django.core.mail import EmailMessage
-from django.utils import timezone
 from django.http import HttpRequest, HttpResponse
 from django.shortcuts import redirect, render
+from django.utils import timezone
 from django.utils.translation import ugettext as _
 from django.views.generic.list import ListView
 
-import pytz
 import reversion
-from reversion.views import create_revision
 from django_tables2 import RequestConfig
-from rules.contrib.views import permission_required, PermissionRequiredMixin
+from reversion.views import create_revision
+from rules.contrib.views import PermissionRequiredMixin, permission_required
 from templated_email import send_templated_mail
 
 from aleksis.core.models import Activity, Person
@@ -33,23 +31,15 @@ from .forms import (
     EditFeedbackAspectForm,
     EditTeckidsMemberForm,
     EditVoucherForm,
-    EventAdditionalSurveyForm,
     EventFeedbackForm,
     GenerateListForm,
     RegisterEventForm,
 )
-from .models import (
-    EventRegistration,
-    FeedbackAspect,
-    TeckidsMember,
-    TeckidsEvent,
-    Voucher,
-)
+from .models import EventRegistration, FeedbackAspect, TeckidsEvent, TeckidsMember, Voucher
 from .tables import (
     EventRegistrationsTable,
     EventsTable,
     FeedbackAspectsTable,
-    ManageEventsTable,
     ParticipatedEventsTable,
     TeckidsMemberTable,
     VouchersTable,
@@ -81,6 +71,7 @@ def events(request):
 
     return render(request, "ticdesk/teckids_event/list.html", context)
 
+
 @create_revision
 @login_required
 def register_event(request, id_):
@@ -138,18 +129,14 @@ def register_event(request, id_):
                 or "school_place" in register_form.changed_data
                 or "mobile" in register_form.changed_data
                 or "sex" in register_form.changed_data
-                or "date_of_birth" in register_form.changed_data,
+                or "date_of_birth" in register_form.changed_data
             ):
                 request.user.person.school = register_form.cleaned_data["school"]
                 request.user.person.school_class = register_form.cleaned_data["school_class"]
                 request.user.person.school_place = register_form.cleaned_data["school_place"]
-                request.user.person.mobile_number = register_form.cleaned_data[
-                    "mobile_number"
-                ]
+                request.user.person.mobile_number = register_form.cleaned_data["mobile_number"]
                 request.user.person.sex = register_form.cleaned_data["sex"]
-                request.user.person.date_of_birth = register_form.cleaned_data[
-                    "date_of_birth"
-                ]
+                request.user.person.date_of_birth = register_form.cleaned_data["date_of_birth"]
 
                 request.user.person.save()
 
@@ -190,9 +177,7 @@ def register_event(request, id_):
 
             registration = register_form.save(commit=True)
             if "voucher_code" in register_form.changed_data:
-                voucher = Voucher.objects.get(
-                    code=register_form.cleaned_data["voucher_code"]
-                )
+                voucher = Voucher.objects.get(code=register_form.cleaned_data["voucher_code"])
                 if voucher:
                     registration.voucher = voucher
                     with reversion.create_revision():
@@ -200,17 +185,12 @@ def register_event(request, id_):
                 else:
                     messages.error(request, _("You entered an invalid voucher code!"))
 
-            send_templated_email(
+            send_templated_mail(
                 template_name="event_registred",
                 from_email=lazy_preference("mail", "address"),
-                recipient_list=[
-                    "orga@teckids.org"
-                ],
-                headers = {
-                    "reply_to": [
-                        request.person.email,
-                        request.person.guardians.first().email,
-                    ],
+                recipient_list=["orga@teckids.org"],
+                headers={
+                    "reply_to": [request.person.email, request.person.guardians.first().email,],
                 },
                 context=context,
             )
@@ -264,9 +244,7 @@ def feedback_event(request, id_):
             # Handle photo uploads, if any
             photo_urls = []
             for file in request.FILES.getlist("photos"):
-                url = upload_file_to_media_url(
-                    file, "ticdesk/teckids_events/feedback/photos"
-                )
+                url = upload_file_to_media_url(file, "ticdesk/teckids_events/feedback/photos")
                 photo_urls.append(url)
 
             # Produce e-mail to registration queue
@@ -311,9 +289,7 @@ def feedback_event(request, id_):
     return render(request, "ticdesk/teckids_event/feedback.html", context)
 
 
-@permission_required(
-    "ticdesk.edit_event", fn=objectgetter_optional(TeckidsEvent, None, False)
-)
+@permission_required("ticdesk.edit_event", fn=objectgetter_optional(TeckidsEvent, None, False))
 def edit_event(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
     """View to edit or create an event."""
     context = {}
@@ -336,12 +312,10 @@ def edit_event(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
                 if not event:
                     context["new_event"] = new_event
                     context["person"] = request.user.person
-                    send_templated_email(
+                    send_templated_mail(
                         template_name="event_created",
                         from_email=lazy_preference("mail", "address"),
-                        recipient_list=[
-                            "orga@teckids.org"
-                        ],
+                        recipient_list=["orga@teckids.org"],
                         context=context,
                     )
             messages.success(request, _("The event has been saved."))
@@ -406,9 +380,7 @@ def delete_voucher(request, id_):
     return redirect("vouchers")
 
 
-@permission_required(
-    "ticdesk.edit_voucher", fn=objectgetter_optional(Voucher, None, False)
-)
+@permission_required("ticdesk.edit_voucher", fn=objectgetter_optional(Voucher, None, False))
 def edit_voucher(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
     """View to edit or create a voucher."""
     context = {}
@@ -434,8 +406,7 @@ def edit_voucher(request: HttpRequest, id_: Optional[int] = None) -> HttpRespons
             act = Activity(
                 title=_("You have created a voucher."),
                 description=_(
-                    "You have created a voucher for %s for %s"
-                    % (voucher.person, voucher.event)
+                    "You have created a voucher for %s for %s" % (voucher.person, voucher.event)
                 ),
                 app="TIC-Desk",
                 user=request.user.person,
@@ -450,6 +421,7 @@ def edit_voucher(request: HttpRequest, id_: Optional[int] = None) -> HttpRespons
 
     return render(request, "ticdesk/voucher/edit.html", context)
 
+
 @permission_required("ticdesk.generate_lists")
 def generate_lists(request: HttpRequest) -> HttpResponse:
     context = {}
@@ -498,9 +470,9 @@ def registrations(request: HttpRequest) -> HttpResponse:
 def registration(request: HttpRequest, id_) -> HttpResponse:
     context = {}
 
-    registration = objectgetter_optional(
-        EventRegistration, "request.user.person", True
-    )(request, id_)
+    registration = objectgetter_optional(EventRegistration, "request.user.person", True)(
+        request, id_
+    )
 
     context["registration"] = registration
 
@@ -528,8 +500,7 @@ def members(request: HttpRequest) -> HttpResponse:
 
 
 @permission_required(
-    "ticdesk.manage_teckids_member",
-    fn=objectgetter_optional(TeckidsMember, None, False),
+    "ticdesk.manage_teckids_member", fn=objectgetter_optional(TeckidsMember, None, False),
 )
 def edit_member(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
     """View to edit or create a member."""
@@ -560,8 +531,7 @@ def edit_member(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse
 
 
 @permission_required(
-    "ticdesk.delete_registrations",
-    fn=objectgetter_optional(EventRegistration, None, False),
+    "ticdesk.delete_registrations", fn=objectgetter_optional(EventRegistration, None, False),
 )
 def delete_registration(request: HttpRequest, id_) -> HttpResponse:
     context = {}
@@ -581,8 +551,7 @@ def delete_registration(request: HttpRequest, id_) -> HttpResponse:
 
 
 @permission_required(
-    "ticdesk.manage_registrations",
-    fn=objectgetter_optional(EventRegistration, None, False),
+    "ticdesk.manage_registrations", fn=objectgetter_optional(EventRegistration, None, False),
 )
 def edit_registration(request: HttpRequest, id_) -> HttpResponse:
     context = {}
@@ -607,9 +576,7 @@ def edit_registration(request: HttpRequest, id_) -> HttpResponse:
     return render(request, "ticdesk/event_registration/edit.html", context)
 
 
-@permission_required(
-    "ticdesk.is_own_voucher", fn=objectgetter_optional(Voucher, None, False)
-)
+@permission_required("ticdesk.is_own_voucher", fn=objectgetter_optional(Voucher, None, False))
 def print_voucher(request: HttpRequest, id_) -> HttpResponse:
     context = {}
 
@@ -628,9 +595,7 @@ def feedback_aspects(request: HttpRequest) -> HttpResponse:
     feedback_aspects = FeedbackAspect.objects.all()
 
     # Get filter
-    feedback_aspects_filter = FeedbackAspectsFilter(
-        request.GET, queryset=feedback_aspects
-    )
+    feedback_aspects_filter = FeedbackAspectsFilter(request.GET, queryset=feedback_aspects)
     context["feedback_aspects_filter"] = feedback_aspects_filter
 
     # Build table
@@ -642,12 +607,9 @@ def feedback_aspects(request: HttpRequest) -> HttpResponse:
 
 
 @permission_required(
-    "ticdesk.edit_feedback_aspect",
-    fn=objectgetter_optional(FeedbackAspect, None, False),
+    "ticdesk.edit_feedback_aspect", fn=objectgetter_optional(FeedbackAspect, None, False),
 )
-def edit_feedback_aspect(
-    request: HttpRequest, id_: Optional[int] = None
-) -> HttpResponse:
+def edit_feedback_aspect(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
     """View to edit or create an feedback_aspect."""
     context = {}
 
diff --git a/poetry.lock b/poetry.lock
index b5bc5287b0779fb1cb70762df3453dc1d1b27614..acd560b024748d59cf61be56bfbe7b833a9ec939 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -7,77 +7,76 @@ optional = false
 python-versions = "*"
 
 [[package]]
-name = "aleksis"
-version = "2.0a3.dev0"
+name = "aleksis-core"
+version = "2.0a3.dev0+20201114132749.88d92354"
 description = "AlekSIS (School Information System) — Core"
 category = "main"
 optional = false
-python-versions = "^3.7"
-develop = false
-
-[package.dependencies]
-calendarweek = "^0.4.3"
-celery-progress = "^0.0.12"
-colour = "^0.1.5"
-Django = "^3.0"
-django-any-js = "^1.0"
-django-bleach = "^0.6.1"
-django-cache-memoize = "^0.1.6"
-django-ckeditor = "^6.0.0"
-django-colorfield = "^0.3.0"
-django-dbbackup = "^3.3.0"
-django-debug-toolbar = "^2.0"
-django-dynamic-preferences = "^1.9"
-django-easy-audit = "^1.2rc1"
-django-favicon-plus-reloaded = "^1.0.4"
-django-filter = "^2.2.0"
-django-guardian = "^2.2.0"
-django-hattori = "^0.2"
+python-versions = ">=3.7,<4.0"
+
+[package.dependencies]
+calendarweek = ">=0.4.3,<0.5.0"
+celery-progress = ">=0.0.12,<0.0.13"
+colour = ">=0.1.5,<0.2.0"
+Django = ">=3.0,<4.0"
+django-any-js = ">=1.0,<2.0"
+django-bleach = ">=0.6.1,<0.7.0"
+django-cache-memoize = ">=0.1.6,<0.2.0"
+django-ckeditor = ">=6.0.0,<7.0.0"
+django-colorfield = ">=0.3.0,<0.4.0"
+django-dbbackup = ">=3.3.0,<4.0.0"
+django-debug-toolbar = ">=2.0,<3.0"
+django-dynamic-preferences = ">=1.9,<2.0"
+django-easy-audit = ">=1.2rc1,<2.0"
+django-favicon-plus-reloaded = ">=1.0.4,<2.0.0"
+django-filter = ">=2.2.0,<3.0.0"
+django-guardian = ">=2.2.0,<3.0.0"
+django-hattori = ">=0.2,<0.3"
 django-haystack = "3.0b1"
-django-health-check = "^3.12.1"
-django-image-cropping = "^1.2"
-django-impersonate = "^1.4"
-django-ipware = "^3.0"
-django-js-reverse = "^0.9.1"
-django-jsonstore = "^0.4.1"
-django-maintenance-mode = "^0.15.0"
-django-material = "^1.6.0"
-django-menu-generator = "^1.0.4"
-django-middleware-global-request = "^0.1.2"
+django-health-check = ">=3.12.1,<4.0.0"
+django-image-cropping = ">=1.2,<2.0"
+django-impersonate = ">=1.4,<2.0"
+django-ipware = ">=3.0,<4.0"
+django-js-reverse = ">=0.9.1,<0.10.0"
+django-jsonstore = ">=0.4.1,<0.5.0"
+django-maintenance-mode = ">=0.15.0,<0.16.0"
+django-material = ">=1.6.0,<2.0.0"
+django-menu-generator = ">=1.0.4,<2.0.0"
+django-middleware-global-request = ">=0.1.2,<0.2.0"
 django-phonenumber-field = {version = "<5.1", extras = ["phonenumbers"]}
-django-polymorphic = "^3.0.0"
-django-pwa = "^1.0.8"
-django-reversion = "^3.0.7"
-django-sass-processor = "^0.8"
-django_select2 = "^7.1"
-django-settings-context-processor = "^0.2"
-django-tables2 = "^2.1"
-django-templated-email = "^2.3.0"
-django-two-factor-auth = {version = "^1.12.1", extras = ["call", "phonenumbers", "sms", "yubikey"]}
-django_widget_tweaks = "^1.4.5"
-django-yarnpkg = "^6.0"
-dynaconf = {version = "^3.1", extras = ["ini", "toml", "yaml"]}
-easy-thumbnails = "^2.6"
-html2text = "^2020.0.0"
-libsass = "^0.20.0"
-license-expression = "^1.2"
-Pillow = "^7.0"
-psutil = "^5.7.0"
-psycopg2 = "^2.8"
-python-memcached = "^1.59"
-requests = "^2.22"
-rules = "^2.2"
-spdx-license-list = "^0.5.0"
+django-polymorphic = ">=3.0.0,<4.0.0"
+django-prometheus = ">=2.1.0,<3.0.0"
+django-pwa = ">=1.0.8,<2.0.0"
+django-reversion = ">=3.0.7,<4.0.0"
+django-sass-processor = ">=0.8,<0.9"
+django_select2 = ">=7.1,<8.0"
+django-settings-context-processor = ">=0.2,<0.3"
+django-tables2 = ">=2.1,<3.0"
+django-templated-email = ">=2.3.0,<3.0.0"
+django-two-factor-auth = {version = ">=1.12.1,<2.0.0", extras = ["call", "phonenumbers", "sms", "yubikey"]}
+django_widget_tweaks = ">=1.4.5,<2.0.0"
+django-yarnpkg = ">=6.0,<7.0"
+dynaconf = {version = ">=3.1,<4.0", extras = ["ini", "toml", "yaml"]}
+easy-thumbnails = ">=2.6,<3.0"
+html2text = ">=2020.0.0,<2021.0.0"
+libsass = ">=0.20.0,<0.21.0"
+license-expression = ">=1.2,<2.0"
+Pillow = ">=7.0,<8.0"
+psutil = ">=5.7.0,<6.0.0"
+psycopg2 = ">=2.8,<3.0"
+python-memcached = ">=1.59,<2.0"
+requests = ">=2.22,<3.0"
+rules = ">=2.2,<3.0"
+spdx-license-list = ">=0.5.0,<0.6.0"
 
 [package.extras]
+celery = ["Celery[django,redis] (>=4.4.0,<5.0.0)", "celery-haystack (>=0.10.0,<0.11.0)", "django-celery-beat (>=2.0.0,<3.0.0)", "django-celery-email (>=3.0.0,<4.0.0)", "django-celery-results (>=1.1.2,<2.0.0)"]
 ldap = ["django-auth-ldap (>=2.2,<3.0)"]
-celery = ["Celery[redis,django] (>=4.4.0,<5.0.0)", "django-celery-results (>=1.1.2,<2.0.0)", "django-celery-beat (>=2.0.0,<3.0.0)", "django-celery-email (>=3.0.0,<4.0.0)", "celery-haystack (>=0.10.0,<0.11.0)"]
 
 [package.source]
-type = "git"
-url = "https://edugit.org/AlekSIS/official/AlekSIS"
-reference = "master"
-resolved_reference = "f90161bce0867c67a6de79b1b59de26a7ba37f79"
+type = "legacy"
+url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple"
+reference = "gitlab"
 
 [[package]]
 name = "appdirs"
@@ -89,7 +88,7 @@ python-versions = "*"
 
 [[package]]
 name = "asgiref"
-version = "3.3.0"
+version = "3.3.1"
 description = "ASGI specs, helper code, and adapters"
 category = "main"
 optional = false
@@ -122,7 +121,7 @@ tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>
 
 [[package]]
 name = "babel"
-version = "2.8.0"
+version = "2.9.0"
 description = "Internationalization utilities"
 category = "main"
 optional = false
@@ -204,7 +203,7 @@ python-versions = "*"
 
 [[package]]
 name = "calendarweek"
-version = "0.4.6.post2"
+version = "0.4.7"
 description = "Utilities for working with calendar weeks in Python and Django"
 category = "main"
 optional = false
@@ -228,7 +227,7 @@ websockets = ["channels"]
 
 [[package]]
 name = "certifi"
-version = "2020.6.20"
+version = "2020.11.8"
 description = "Python package for providing Mozilla's CA Bundle."
 category = "main"
 optional = false
@@ -716,6 +715,17 @@ python-versions = "*"
 [package.dependencies]
 Django = ">=2.1"
 
+[[package]]
+name = "django-prometheus"
+version = "2.1.0"
+description = "Django middlewares to monitor your application with Prometheus.io."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+prometheus-client = ">=0.7"
+
 [[package]]
 name = "django-pwa"
 version = "1.0.10"
@@ -912,8 +922,8 @@ optional = false
 python-versions = "*"
 
 [package.dependencies]
-configobj = {version = "*", optional = true, markers = "extra == \"ini\""}
-"ruamel.yaml" = {version = "*", optional = true, markers = "extra == \"yaml\""}
+configobj = {version = "*", optional = true, markers = "extra == \"all\""}
+"ruamel.yaml" = {version = "*", optional = true, markers = "extra == \"all\""}
 toml = {version = "*", optional = true, markers = "extra == \"toml\""}
 
 [package.extras]
@@ -958,7 +968,6 @@ optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
 
 [package.dependencies]
-importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
 mccabe = ">=0.6.0,<0.7.0"
 pycodestyle = ">=2.6.0a1,<2.7.0"
 pyflakes = ">=2.2.0,<2.3.0"
@@ -1076,7 +1085,7 @@ flake8 = "*"
 
 [[package]]
 name = "flake8-rst-docstrings"
-version = "0.0.13"
+version = "0.0.14"
 description = "Python docstring reStructuredText (RST) validator"
 category = "dev"
 optional = false
@@ -1148,21 +1157,6 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
-[[package]]
-name = "importlib-metadata"
-version = "2.0.0"
-description = "Read metadata from Python packages"
-category = "dev"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
-
-[package.dependencies]
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["sphinx", "rst.linker"]
-testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
-
 [[package]]
 name = "iniconfig"
 version = "1.1.1"
@@ -1334,7 +1328,7 @@ scramp = "1.2.0"
 
 [[package]]
 name = "phonenumbers"
-version = "8.12.12"
+version = "8.12.13"
 description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
 category = "main"
 optional = false
@@ -1356,12 +1350,20 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
-[package.dependencies]
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
-
 [package.extras]
 dev = ["pre-commit", "tox"]
 
+[[package]]
+name = "prometheus-client"
+version = "0.8.0"
+description = "Python client for the Prometheus monitoring system."
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.extras]
+twisted = ["twisted"]
+
 [[package]]
 name = "psutil"
 version = "5.7.3"
@@ -1473,7 +1475,6 @@ python-versions = ">=3.5"
 atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
 attrs = ">=17.4.0"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
-importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
 iniconfig = "*"
 packaging = "*"
 pluggy = ">=0.12,<1.0"
@@ -1481,7 +1482,7 @@ py = ">=1.8.2"
 toml = "*"
 
 [package.extras]
-checkqa_mypy = ["mypy (==0.780)"]
+checkqa_mypy = ["mypy (0.780)"]
 testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
 
 [[package]]
@@ -1497,7 +1498,7 @@ coverage = ">=4.4"
 pytest = ">=4.6"
 
 [package.extras]
-testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"]
+testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"]
 
 [[package]]
 name = "pytest-django"
@@ -1639,7 +1640,7 @@ redis = ">=3.1.0,<4.0.0"
 
 [[package]]
 name = "regex"
-version = "2020.10.28"
+version = "2020.11.13"
 description = "Alternative regular expression module, to replace re."
 category = "dev"
 optional = false
@@ -1647,7 +1648,7 @@ python-versions = "*"
 
 [[package]]
 name = "requests"
-version = "2.24.0"
+version = "2.25.0"
 description = "Python HTTP for Humans."
 category = "main"
 optional = false
@@ -1657,11 +1658,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 certifi = ">=2017.4.17"
 chardet = ">=3.0.2,<4"
 idna = ">=2.5,<3"
-urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
+urllib3 = ">=1.21.1,<1.27"
 
 [package.extras]
 security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
-socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
+socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
 
 [[package]]
 name = "restructuredtext-lint"
@@ -1788,7 +1789,7 @@ python-versions = "*"
 
 [[package]]
 name = "sphinx"
-version = "3.3.0"
+version = "3.3.1"
 description = "Python documentation generator"
 category = "dev"
 optional = false
@@ -1928,7 +1929,6 @@ optional = false
 python-versions = ">=3.6"
 
 [package.dependencies]
-importlib-metadata = {version = ">=1.7.0", markers = "python_version < \"3.8\""}
 pbr = ">=2.0.0,<2.1.0 || >2.1.0"
 
 [[package]]
@@ -2045,7 +2045,7 @@ python-versions = "*"
 
 [[package]]
 name = "urllib3"
-version = "1.25.11"
+version = "1.26.2"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
 category = "main"
 optional = false
@@ -2054,7 +2054,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
 [package.extras]
 brotli = ["brotlipy (>=0.6.0)"]
 secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
-socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
 
 [[package]]
 name = "webencodings"
@@ -2075,36 +2075,29 @@ python-versions = "*"
 [package.dependencies]
 pycryptodome = "*"
 
-[[package]]
-name = "zipp"
-version = "3.4.0"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=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"]
-
 [metadata]
 lock-version = "1.1"
-python-versions = "^3.7"
-content-hash = "014c8ff1cf6f39c409543d9a021dfa3514a8fb2f92d32ade9b648b1c81989e92"
+python-versions = "^3.8"
+content-hash = "4ec5a91060911dd58c3235f9aa149fa51e76fe7a9290e20f47e587cc5d58ae3b"
 
 [metadata.files]
 alabaster = [
     {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
     {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
 ]
-aleksis = []
+aleksis-core = [
+    {file = "AlekSIS-Core-2.0a3.dev0+20201114132749.88d92354.tar.gz", hash = "sha256:be16d8b6478029ec86cc92389a5f679be85112cb20d18996c8ae95adf86690ba"},
+    {file = "AlekSIS-Core-2.0a3.dev0+20201114154746.9129dcd7.tar.gz", hash = "sha256:89bf9908411953eb337cc40b702f00394d4ff137fcd5160c538608c0a867a294"},
+    {file = "AlekSIS_Core-2.0a3.dev0+20201114132749.88d92354-py3-none-any.whl", hash = "sha256:180477173a1e23f9ca42b6b79383b556dbd97868e3f3079c8b090466aeba256c"},
+    {file = "AlekSIS_Core-2.0a3.dev0+20201114154746.9129dcd7-py3-none-any.whl", hash = "sha256:a60b456a300f1fa7786567cb0b948690422c95492a0cec936a0b99d6109afed5"},
+]
 appdirs = [
     {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
     {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
 ]
 asgiref = [
-    {file = "asgiref-3.3.0-py3-none-any.whl", hash = "sha256:a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e"},
-    {file = "asgiref-3.3.0.tar.gz", hash = "sha256:cd88907ecaec59d78e4ac00ea665b03e571cb37e3a0e37b3702af1a9e86c365a"},
+    {file = "asgiref-3.3.1-py3-none-any.whl", hash = "sha256:5ee950735509d04eb673bd7f7120f8fa1c9e2df495394992c73234d526907e17"},
+    {file = "asgiref-3.3.1.tar.gz", hash = "sha256:7162a3cb30ab0609f1a4c95938fd73e8604f63bdba516a7f7d64b83ff09478f0"},
 ]
 atomicwrites = [
     {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
@@ -2115,8 +2108,8 @@ attrs = [
     {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
 ]
 babel = [
-    {file = "Babel-2.8.0-py2.py3-none-any.whl", hash = "sha256:d670ea0b10f8b723672d3a6abeb87b565b244da220d76b4dba1b66269ec152d4"},
-    {file = "Babel-2.8.0.tar.gz", hash = "sha256:1aac2ae2d0d8ea368fa90906567f5c08463d98ade155c0c4bfedd6a0f7160e38"},
+    {file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"},
+    {file = "Babel-2.9.0.tar.gz", hash = "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"},
 ]
 bandit = [
     {file = "bandit-1.6.2-py2.py3-none-any.whl", hash = "sha256:336620e220cf2d3115877685e264477ff9d9abaeb0afe3dc7264f55fa17a3952"},
@@ -2140,16 +2133,16 @@ bleach = [
     {file = "boolean.py-3.8.tar.gz", hash = "sha256:cc24e20f985d60cd4a3a5a1c0956dd12611159d32a75081dabd0c9ab981acaa4"},
 ]
 calendarweek = [
-    {file = "calendarweek-0.4.6.post2-py3-none-any.whl", hash = "sha256:17c95c15694f8ae44cac182d9023e3793fe61c54bcd36bb1aeed6dc497d62a6c"},
-    {file = "calendarweek-0.4.6.post2.tar.gz", hash = "sha256:8ddb18d32e05d8373c5ec14b9acbe99f40e0ef67aac4d74c992c62c5d6057d03"},
+    {file = "calendarweek-0.4.7-py3-none-any.whl", hash = "sha256:ee65caea113503dcdb33d96bca9f79f88b3ab4f66279d4cb568d89f1f662608a"},
+    {file = "calendarweek-0.4.7.tar.gz", hash = "sha256:7655d6a4c3b4f6a4e01aa7d23b49cd121db0399050e9c08cd8d1210155be25dd"},
 ]
 celery-progress = [
     {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"},
-    {file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
+    {file = "certifi-2020.11.8-py2.py3-none-any.whl", hash = "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd"},
+    {file = "certifi-2020.11.8.tar.gz", hash = "sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"},
 ]
 chardet = [
     {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
@@ -2348,6 +2341,10 @@ django-polymorphic = [
     {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-prometheus = [
+    {file = "django-prometheus-2.1.0.tar.gz", hash = "sha256:dd3f8da1399140fbef5c00d1526a23d1ade286b144281c325f8e409a781643f2"},
+    {file = "django_prometheus-2.1.0-py2.py3-none-any.whl", hash = "sha256:c338d6efde1ca336e90c540b5e87afe9287d7bcc82d651a778f302b0be17a933"},
+]
 django-pwa = [
     {file = "django-pwa-1.0.10.tar.gz", hash = "sha256:07ed9dd57108838e3fe44b551a82032ca4ed76e31cb3c3e8d51604e0fe7e81e9"},
     {file = "django_pwa-1.0.10-py3-none-any.whl", hash = "sha256:b1a2057b1e72c40c3a14beb90b958482da185f1d40a141fcae3d76580984b930"},
@@ -2453,7 +2450,7 @@ flake8-polyfill = [
     {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"},
 ]
 flake8-rst-docstrings = [
-    {file = "flake8-rst-docstrings-0.0.13.tar.gz", hash = "sha256:b1b619d81d879b874533973ac04ee5d823fdbe8c9f3701bfe802bb41813997b4"},
+    {file = "flake8-rst-docstrings-0.0.14.tar.gz", hash = "sha256:8f8bcb18f1408b506dd8ba2c99af3eac6128f6911d4bf6ff874b94caa70182a2"},
 ]
 funcsigs = [
     {file = "funcsigs-1.0.2-py2.py3-none-any.whl", hash = "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca"},
@@ -2482,10 +2479,6 @@ 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-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-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
     {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
@@ -2603,8 +2596,8 @@ pg8000 = [
     {file = "pg8000-1.16.6.tar.gz", hash = "sha256:8fc1e6a62ccb7c9830f1e7e9288e2d20eaf373cc8875b5c55b7d5d9b7717be91"},
 ]
 phonenumbers = [
-    {file = "phonenumbers-8.12.12-py2.py3-none-any.whl", hash = "sha256:23944f9e628f32a975d3b221b6d76e6ba8ae618d53cb3d82fc23d9e100a59b29"},
-    {file = "phonenumbers-8.12.12.tar.gz", hash = "sha256:70aa98a50ba7bc7f6bf17851f806c927107e7c44e7d21eb46bdbec07b99d23ae"},
+    {file = "phonenumbers-8.12.13-py2.py3-none-any.whl", hash = "sha256:9de2937034deb040eb9ac56519b0887e0fe89811e57f6f5c88359e3be20ae3b5"},
+    {file = "phonenumbers-8.12.13.tar.gz", hash = "sha256:96d02120a3481e22d8a8eb5e4595ceec1930855749f6e4a06ef931881f59f562"},
 ]
 pillow = [
     {file = "Pillow-7.2.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae"},
@@ -2638,6 +2631,10 @@ pluggy = [
     {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
     {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
 ]
+prometheus-client = [
+    {file = "prometheus_client-0.8.0-py2.py3-none-any.whl", hash = "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c"},
+    {file = "prometheus_client-0.8.0.tar.gz", hash = "sha256:c6e6b706833a6bd1fd51711299edee907857be10ece535126a158f911ee80915"},
+]
 psutil = [
     {file = "psutil-5.7.3-cp27-none-win32.whl", hash = "sha256:1cd6a0c9fb35ece2ccf2d1dd733c1e165b342604c67454fd56a4c12e0a106787"},
     {file = "psutil-5.7.3-cp27-none-win_amd64.whl", hash = "sha256:e02c31b2990dcd2431f4524b93491941df39f99619b0d312dfe1d4d530b08b4b"},
@@ -2682,8 +2679,6 @@ pycryptodome = [
     {file = "pycryptodome-3.9.9-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:5598dc6c9dbfe882904e54584322893eff185b98960bbe2cdaaa20e8a437b6e5"},
     {file = "pycryptodome-3.9.9-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1cfdb92dca388e27e732caa72a1cc624520fe93752a665c3b6cd8f1a91b34916"},
     {file = "pycryptodome-3.9.9-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f19e6ef750f677d924d9c7141f54bade3cd56695bbfd8a9ef15d0378557dfe4"},
-    {file = "pycryptodome-3.9.9-cp27-cp27m-win32.whl", hash = "sha256:a3d8a9efa213be8232c59cdc6b65600276508e375e0a119d710826248fd18d37"},
-    {file = "pycryptodome-3.9.9-cp27-cp27m-win_amd64.whl", hash = "sha256:50826b49fbca348a61529693b0031cdb782c39060fb9dca5ac5dff858159dc5a"},
     {file = "pycryptodome-3.9.9-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:19cb674df6c74a14b8b408aa30ba8a89bd1c01e23505100fb45f930fbf0ed0d9"},
     {file = "pycryptodome-3.9.9-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:28f75e58d02019a7edc7d4135203d2501dfc47256d175c72c9798f9a129a49a7"},
     {file = "pycryptodome-3.9.9-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:6d3baaf82681cfb1a842f1c8f77beac791ceedd99af911e4f5fabec32bae2259"},
@@ -2694,26 +2689,17 @@ pycryptodome = [
     {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7798e73225a699651888489fbb1dbc565e03a509942a8ce6194bbe6fb582a41f"},
     {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:46e96aeb8a9ca8b1edf9b1fd0af4bf6afcf3f1ca7fa35529f5d60b98f3e4e959"},
     {file = "pycryptodome-3.9.9-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:843e5f10ecdf9d307032b8b91afe9da1d6ed5bb89d0bbec5c8dcb4ba44008e11"},
-    {file = "pycryptodome-3.9.9-cp36-cp36m-win32.whl", hash = "sha256:b68794fba45bdb367eeb71249c26d23e61167510a1d0c3d6cf0f2f14636e62ee"},
-    {file = "pycryptodome-3.9.9-cp36-cp36m-win_amd64.whl", hash = "sha256:60febcf5baf70c566d9d9351c47fbd8321da9a4edf2eff45c4c31c86164ca794"},
     {file = "pycryptodome-3.9.9-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:4ed27951b0a17afd287299e2206a339b5b6d12de9321e1a1575261ef9c4a851b"},
     {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:9000877383e2189dafd1b2fc68c6c726eca9a3cfb6d68148fbb72ccf651959b6"},
     {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:faa682c404c218e8788c3126c9a4b8fbcc54dc245b5b6e8ea5b46f3b63bd0c84"},
     {file = "pycryptodome-3.9.9-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:62c488a21c253dadc9f731a32f0ac61e4e436d81a1ea6f7d1d9146ed4d20d6bd"},
-    {file = "pycryptodome-3.9.9-cp37-cp37m-win32.whl", hash = "sha256:834b790bbb6bd18956f625af4004d9c15eed12d5186d8e57851454ae76d52215"},
-    {file = "pycryptodome-3.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:70d807d11d508433daf96244ec1c64e55039e8a35931fc5ea9eee94dbe3cb6b5"},
     {file = "pycryptodome-3.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:27397aee992af69d07502126561d851ba3845aa808f0e55c71ad0efa264dd7d4"},
     {file = "pycryptodome-3.9.9-cp38-cp38-manylinux1_i686.whl", hash = "sha256:d7ec2bd8f57c559dd24e71891c51c25266a8deb66fc5f02cc97c7fb593d1780a"},
     {file = "pycryptodome-3.9.9-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:e15bde67ccb7d4417f627dd16ffe2f5a4c2941ce5278444e884cb26d73ecbc61"},
     {file = "pycryptodome-3.9.9-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5c3c4865730dfb0263f822b966d6d58429d8b1e560d1ddae37685fd9e7c63161"},
-    {file = "pycryptodome-3.9.9-cp38-cp38-win32.whl", hash = "sha256:76b1a34d74bb2c91bce460cdc74d1347592045627a955e9a252554481c17c52f"},
-    {file = "pycryptodome-3.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:6e4227849e4231a3f5b35ea5bdedf9a82b3883500e5624f00a19156e9a9ef861"},
     {file = "pycryptodome-3.9.9-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2a68df525b387201a43b27b879ce8c08948a430e883a756d6c9e3acdaa7d7bd8"},
     {file = "pycryptodome-3.9.9-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a4599c0ca0fc027c780c1c45ed996d5bef03e571470b7b1c7171ec1e1a90914c"},
     {file = "pycryptodome-3.9.9-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b4e6b269a8ddaede774e5c3adbef6bf452ee144e6db8a716d23694953348cd86"},
-    {file = "pycryptodome-3.9.9-cp39-cp39-win32.whl", hash = "sha256:a199e9ca46fc6e999e5f47fce342af4b56c7de85fae893c69ab6aa17531fb1e1"},
-    {file = "pycryptodome-3.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:6e89bb3826e6f84501e8e3b205c22595d0c5492c2f271cbb9ee1c48eb1866645"},
-    {file = "pycryptodome-3.9.9.tar.gz", hash = "sha256:910e202a557e1131b1c1b3f17a63914d57aac55cf9fb9b51644962841c3995c4"},
 ]
 pydocstyle = [
     {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"},
@@ -2799,53 +2785,51 @@ redis-collections = [
     {file = "redis-collections-0.8.1.tar.gz", hash = "sha256:b0c1213b57ed2d5a351dcec05826ce42de9bae88f74c12f2917aa7523f94269e"},
 ]
 regex = [
-    {file = "regex-2020.10.28-cp27-cp27m-win32.whl", hash = "sha256:4b5a9bcb56cc146c3932c648603b24514447eafa6ce9295234767bf92f69b504"},
-    {file = "regex-2020.10.28-cp27-cp27m-win_amd64.whl", hash = "sha256:c13d311a4c4a8d671f5860317eb5f09591fbe8259676b86a85769423b544451e"},
-    {file = "regex-2020.10.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c454ad88e56e80e44f824ef8366bb7e4c3def12999151fd5c0ea76a18fe9aa3e"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c8a2b7ccff330ae4c460aff36626f911f918555660cc28163417cb84ffb25789"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4afa350f162551cf402bfa3cd8302165c8e03e689c897d185f16a167328cc6dd"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b88fa3b8a3469f22b4f13d045d9bd3eda797aa4e406fde0a2644bc92bbdd4bdd"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f43109822df2d3faac7aad79613f5f02e4eab0fc8ad7932d2e70e2a83bd49c26"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:de7fd57765398d141949946c84f3590a68cf5887dac3fc52388df0639b01eda4"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:9b6305295b6591e45f069d3553c54d50cc47629eb5c218aac99e0f7fafbf90a1"},
-    {file = "regex-2020.10.28-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:bd904c0dec29bbd0769887a816657491721d5f545c29e30fd9d7a1a275dc80ab"},
-    {file = "regex-2020.10.28-cp36-cp36m-win32.whl", hash = "sha256:8092a5a06ad9a7a247f2a76ace121183dc4e1a84c259cf9c2ce3bbb69fac3582"},
-    {file = "regex-2020.10.28-cp36-cp36m-win_amd64.whl", hash = "sha256:49461446b783945597c4076aea3f49aee4b4ce922bd241e4fcf62a3e7c61794c"},
-    {file = "regex-2020.10.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:297116e79074ec2a2f885d22db00ce6e88b15f75162c5e8b38f66ea734e73c64"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:8ca9dca965bd86ea3631b975d63b0693566d3cc347e55786d5514988b6f5b84c"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ea37320877d56a7f0a1e6a625d892cf963aa7f570013499f5b8d5ab8402b5625"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:3a5f08039eee9ea195a89e180c5762bfb55258bfb9abb61a20d3abee3b37fd12"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:cb905f3d2e290a8b8f1579d3984f2cfa7c3a29cc7cba608540ceeed18513f520"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:96f99219dddb33e235a37283306834700b63170d7bb2a1ee17e41c6d589c8eb9"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:227a8d2e5282c2b8346e7f68aa759e0331a0b4a890b55a5cfbb28bd0261b84c0"},
-    {file = "regex-2020.10.28-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:2564def9ce0710d510b1fc7e5178ce2d20f75571f788b5197b3c8134c366f50c"},
-    {file = "regex-2020.10.28-cp37-cp37m-win32.whl", hash = "sha256:a62162be05edf64f819925ea88d09d18b09bebf20971b363ce0c24e8b4aa14c0"},
-    {file = "regex-2020.10.28-cp37-cp37m-win_amd64.whl", hash = "sha256:03855ee22980c3e4863dc84c42d6d2901133362db5daf4c36b710dd895d78f0a"},
-    {file = "regex-2020.10.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf4f896c42c63d1f22039ad57de2644c72587756c0cfb3cc3b7530cfe228277f"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux1_i686.whl", hash = "sha256:625116aca6c4b57c56ea3d70369cacc4d62fead4930f8329d242e4fe7a58ce4b"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2dc522e25e57e88b4980d2bdd334825dbf6fa55f28a922fc3bfa60cc09e5ef53"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:119e0355dbdd4cf593b17f2fc5dbd4aec2b8899d0057e4957ba92f941f704bf5"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:cfcf28ed4ce9ced47b9b9670a4f0d3d3c0e4d4779ad4dadb1ad468b097f808aa"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:b45bab9f224de276b7bc916f6306b86283f6aa8afe7ed4133423efb42015a898"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:52e83a5f28acd621ba8e71c2b816f6541af7144b69cc5859d17da76c436a5427"},
-    {file = "regex-2020.10.28-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:aacc8623ffe7999a97935eeabbd24b1ae701d08ea8f874a6ff050e93c3e658cf"},
-    {file = "regex-2020.10.28-cp38-cp38-win32.whl", hash = "sha256:06b52815d4ad38d6524666e0d50fe9173533c9cc145a5779b89733284e6f688f"},
-    {file = "regex-2020.10.28-cp38-cp38-win_amd64.whl", hash = "sha256:c3466a84fce42c2016113101018a9981804097bacbab029c2d5b4fcb224b89de"},
-    {file = "regex-2020.10.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:127a9e0c0d91af572fbb9e56d00a504dbd4c65e574ddda3d45b55722462210de"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux1_i686.whl", hash = "sha256:c2c6c56ee97485a127555c9595c069201b5161de9d05495fbe2132b5ac104786"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1ec66700a10e3c75f1f92cbde36cca0d3aaee4c73dfa26699495a3a30b09093c"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:11116d424734fe356d8777f89d625f0df783251ada95d6261b4c36ad27a394bb"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f1fce1e4929157b2afeb4bb7069204d4370bab9f4fc03ca1fbec8bd601f8c87d"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:3dfca201fa6b326239e1bccb00b915e058707028809b8ecc0cf6819ad233a740"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:b8a686a6c98872007aa41fdbb2e86dc03b287d951ff4a7f1da77fb7f14113e4d"},
-    {file = "regex-2020.10.28-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c32c91a0f1ac779cbd73e62430de3d3502bbc45ffe5bb6c376015acfa848144b"},
-    {file = "regex-2020.10.28-cp39-cp39-win32.whl", hash = "sha256:832339223b9ce56b7b15168e691ae654d345ac1635eeb367ade9ecfe0e66bee0"},
-    {file = "regex-2020.10.28-cp39-cp39-win_amd64.whl", hash = "sha256:654c1635f2313d0843028487db2191530bca45af61ca85d0b16555c399625b0e"},
-    {file = "regex-2020.10.28.tar.gz", hash = "sha256:dd3e6547ecf842a29cf25123fbf8d2461c53c8d37aa20d87ecee130c89b7079b"},
+    {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"},
+    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"},
+    {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"},
+    {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"},
+    {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"},
+    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"},
+    {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"},
+    {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"},
+    {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"},
+    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"},
+    {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"},
+    {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"},
+    {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"},
+    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"},
+    {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"},
+    {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"},
+    {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"},
 ]
 requests = [
-    {file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
-    {file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
+    {file = "requests-2.25.0-py2.py3-none-any.whl", hash = "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"},
+    {file = "requests-2.25.0.tar.gz", hash = "sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8"},
 ]
 restructuredtext-lint = [
     {file = "restructuredtext_lint-1.3.1.tar.gz", hash = "sha256:470e53b64817211a42805c3a104d2216f6f5834b22fe7adb637d1de4d6501fb8"},
@@ -2917,8 +2901,8 @@ spdx-license-list = [
     {file = "spdx_license_list-0.5.1.tar.gz", hash = "sha256:64cb5de37724c64cdeccafa2ae68667ff8ccdb7b688f51c1c2be82d7ebe3a112"},
 ]
 sphinx = [
-    {file = "Sphinx-3.3.0-py3-none-any.whl", hash = "sha256:3abdb2c57a65afaaa4f8573cbabd5465078eb6fd282c1e4f87f006875a7ec0c7"},
-    {file = "Sphinx-3.3.0.tar.gz", hash = "sha256:1c21e7c5481a31b531e6cbf59c3292852ccde175b504b00ce2ff0b8f4adc3649"},
+    {file = "Sphinx-3.3.1-py3-none-any.whl", hash = "sha256:d4e59ad4ea55efbb3c05cde3bfc83bfc14f0c95aa95c3d75346fcce186a47960"},
+    {file = "Sphinx-3.3.1.tar.gz", hash = "sha256:1e8d592225447104d1172be415bc2972bd1357e3e12fdc76edf2261105db4300"},
 ]
 sphinx-autodoc-typehints = [
     {file = "sphinx-autodoc-typehints-1.11.1.tar.gz", hash = "sha256:244ba6d3e2fdb854622f643c7763d6f95b6886eba24bec28e86edf205e4ddb20"},
@@ -3022,8 +3006,8 @@ typing-extensions = [
     {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
 ]
 urllib3 = [
-    {file = "urllib3-1.25.11-py2.py3-none-any.whl", hash = "sha256:f5321fbe4bf3fefa0efd0bfe7fb14e90909eb62a48ccda331726b4319897dd5e"},
-    {file = "urllib3-1.25.11.tar.gz", hash = "sha256:8d7eaa5a82a1cac232164990f04874c594c9453ec55eef02eab885aa02fc17a2"},
+    {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"},
+    {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"},
 ]
 webencodings = [
     {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
@@ -3033,7 +3017,3 @@ yubiotp = [
     {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.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"},
-    {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"},
-]
diff --git a/pyproject.toml b/pyproject.toml
index c1f40342e93333e9454a282aac98c764be2dd119..1fd0d4e594e9899588007be71415b2afac742b4a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,11 +19,14 @@ classifiers = [
     "Topic :: Education"
 ]
 
+[[tool.poetry.source]]
+name = "gitlab"
+url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple"
+secondary = true
+
 [tool.poetry.dependencies]
-python = "^3.7"
-AlekSIS = { git = "https://edugit.org/AlekSIS/official/AlekSIS" }
+python = "^3.8"
 latex = "^0.7.0"
-Pillow = "^7.1.1"
 django-leaflet = "^0.26.0"
 django-starfield = "^1.0.post1"
 pexpect = "^4.8.0"
@@ -32,6 +35,7 @@ python-pam = "^1.8.4"
 python-resize-image = "^1.1.19"
 redis-collections = "^0.8.0"
 django-iban-field = "^0.8"
+aleksis-core = "^2.0a3.dev0"
 
 [tool.poetry.dev-dependencies]
 sphinx = "^3.0"
@@ -50,7 +54,7 @@ flake8-mypy = "^17.8.0"
 flake8-bandit = "^2.1.2"
 flake8-builtins = "^1.4.1"
 flake8-docstrings = "^1.5.0"
-flake8-rst-docstrings = "^0.0.13"
+flake8-rst-docstrings = "^0.0.14"
 black = "^19.10b0"
 flake8-black = "^0.2.0"
 isort = "^5.0.0"
@@ -58,6 +62,10 @@ flake8-isort = "^4.0.0"
 pytest-cov = "^2.8.1"
 pytest-sugar = "^0.9.2"
 
+[tool.black]
+line-length = 100
+exclude = "/migrations/"
+
 [build-system]
 requires = ["poetry>=1.0"]
 build-backend = "poetry.masonry.api"