diff --git a/aleksis/apps/alsijil/apps.py b/aleksis/apps/alsijil/apps.py
index dec1d99274f1511bd523a9c24239835f7d51386f..25aa203003ea54063a0e27fd531314e1ebb03b9b 100644
--- a/aleksis/apps/alsijil/apps.py
+++ b/aleksis/apps/alsijil/apps.py
@@ -9,7 +9,7 @@ class AlsijilConfig(AppConfig):
         "Repository": "https://edugit.org/AlekSIS/official/AlekSIS-App-Alsijil/",
     }
     licence = "EUPL-1.2+"
-    copyright = (
+    copyright_info = (
         ([2019], "Dominik George", "dominik.george@teckids.org"),
         ([2019], "mirabilos", "thorsten.glaser@teckids.org"),
         ([2019], "Tom Teichler", "tom.teichler@teckids.org"),
diff --git a/aleksis/apps/alsijil/forms.py b/aleksis/apps/alsijil/forms.py
index 350bf018d7a45c8d340d72df7309be9f19f699d2..48c809cdefa7847e630809e4aa10054029cabb5e 100644
--- a/aleksis/apps/alsijil/forms.py
+++ b/aleksis/apps/alsijil/forms.py
@@ -1,6 +1,8 @@
 from datetime import datetime
 
+from aleksis.apps.chronos.managers import TimetableType
 from django import forms
+from django.core.exceptions import ValidationError
 from django.db.models import Count
 from django.utils.translation import gettext_lazy as _
 
@@ -50,15 +52,24 @@ class SelectForm(forms.Form):
         required=False,
         widget=Select2Widget,
     )
-    room = forms.ModelChoiceField(
-        queryset=Room.objects.annotate(lessons_count=Count("lesson_periods")).filter(
-            lessons_count__gt=0
-        ),
-        label=_("Room"),
-        required=False,
-        widget=Select2Widget,
-    )
 
+    def clean(self) -> dict:
+        data = super().clean()
+
+        if data.get("group") and not data.get("teacher") :
+            type_ = TimetableType.GROUP
+            instance = data["group"]
+        elif data.get("teacher") and not data.get("group"):
+            type_ = TimetableType.TEACHER
+            instance = data["teacher"]
+        elif not data.get("teacher") and not data.get("group"):
+            return data
+        else:
+            raise ValidationError(_("You can't select a group and a teacher both."))
+
+        data["type_"] = type_
+        data["instance"] = instance
+        return data
 
 PersonalNoteFormSet = forms.modelformset_factory(
     PersonalNote, form=PersonalNoteForm, max_num=0, extra=0
diff --git a/aleksis/apps/alsijil/migrations/0001_initial.py b/aleksis/apps/alsijil/migrations/0001_initial.py
index f7fb4a0c056dd4af708dae04555368a3d7546fe6..3b396eaaa92bbf3bdef22379f94ad6055094eab7 100644
--- a/aleksis/apps/alsijil/migrations/0001_initial.py
+++ b/aleksis/apps/alsijil/migrations/0001_initial.py
@@ -1,9 +1,10 @@
-# Generated by Django 2.2.5 on 2019-09-03 18:30
+# Generated by Django 3.0.6 on 2020-05-29 10:29
 
-import django.db.models.deletion
+import aleksis.apps.alsijil.models
+import django.contrib.postgres.fields.jsonb
+import django.contrib.sites.managers
 from django.db import migrations, models
-
-import aleksis.core.util.core_helpers
+import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
@@ -11,114 +12,74 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ("chronos", "0001_initial"),
-        ("core", "0001_initial"),
+        ('core', '0001_initial'),
+        ('chronos', '0001_initial'),
+        ('sites', '0002_alter_domain_unique'),
     ]
 
     operations = [
         migrations.CreateModel(
-            name="PersonalNote",
+            name='PersonalNoteFilter',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
+                ('identifier', models.CharField(max_length=30, unique=True, validators=[aleksis.apps.alsijil.models.isidentifier], verbose_name='Identifier')),
+                ('description', models.CharField(blank=True, max_length=60, unique=True, verbose_name='Description')),
+                ('regex', models.CharField(max_length=100, unique=True, verbose_name='Match expression')),
+                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
+            ],
+            options={
+                'verbose_name': 'Personal note filter',
+                'verbose_name_plural': 'Personal note filters',
+                'ordering': ['identifier'],
+            },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
+        ),
+        migrations.CreateModel(
+            name='PersonalNote',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                ("week", models.IntegerField()),
-                ("absent", models.BooleanField(default=False)),
-                ("late", models.IntegerField(default=0)),
-                ("excused", models.BooleanField(default=False)),
-                ("remarks", models.CharField(blank=True, max_length=200)),
-                (
-                    "lesson_period",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="chronos.LessonPeriod",
-                    ),
-                ),
-                (
-                    "person",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="personal_notes",
-                        to="core.Person",
-                    ),
-                ),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
+                ('week', models.IntegerField()),
+                ('absent', models.BooleanField(default=False)),
+                ('late', models.IntegerField(default=0)),
+                ('excused', models.BooleanField(default=False)),
+                ('remarks', models.CharField(blank=True, max_length=200)),
+                ('lesson_period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='personal_notes', to='chronos.LessonPeriod')),
+                ('person', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='personal_notes', to='core.Person')),
+                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
             ],
             options={
-                "ordering": [
-                    "lesson_period__lesson__date_start",
-                    "week",
-                    "lesson_period__period__weekday",
-                    "lesson_period__period__period",
-                    "person__last_name",
-                    "person__first_name",
-                ],
-                "unique_together": {("school", "lesson_period", "week", "person")},
+                'verbose_name': 'Personal note',
+                'verbose_name_plural': 'Personal notes',
+                'ordering': ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', 'lesson_period__period__period', 'person__last_name', 'person__first_name'],
+                'unique_together': {('lesson_period', 'week', 'person')},
             },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
         ),
         migrations.CreateModel(
-            name="LessonDocumentation",
+            name='LessonDocumentation',
             fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                ("week", models.IntegerField()),
-                (
-                    "topic",
-                    models.CharField(
-                        blank=True, max_length=200, verbose_name="Lesson topic"
-                    ),
-                ),
-                (
-                    "homework",
-                    models.CharField(
-                        blank=True, max_length=200, verbose_name="Homework"
-                    ),
-                ),
-                (
-                    "lesson_period",
-                    models.ForeignKey(
-                        on_delete=django.db.models.deletion.CASCADE,
-                        related_name="documentations",
-                        to="chronos.LessonPeriod",
-                    ),
-                ),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('extended_data', django.contrib.postgres.fields.jsonb.JSONField(default=dict, editable=False)),
+                ('week', models.IntegerField()),
+                ('topic', models.CharField(blank=True, max_length=200, verbose_name='Lesson topic')),
+                ('homework', models.CharField(blank=True, max_length=200, verbose_name='Homework')),
+                ('lesson_period', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documentations', to='chronos.LessonPeriod')),
+                ('site', models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.CASCADE, to='sites.Site')),
             ],
             options={
-                "ordering": [
-                    "lesson_period__lesson__date_start",
-                    "week",
-                    "lesson_period__period__weekday",
-                    "lesson_period__period__period",
-                ],
-                "unique_together": {("school", "lesson_period", "week")},
+                'verbose_name': 'Lesson documentation',
+                'verbose_name_plural': 'Lesson documentations',
+                'ordering': ['lesson_period__lesson__date_start', 'week', 'lesson_period__period__weekday', 'lesson_period__period__period'],
+                'unique_together': {('lesson_period', 'week')},
             },
+            managers=[
+                ('objects', django.contrib.sites.managers.CurrentSiteManager()),
+            ],
         ),
     ]
diff --git a/aleksis/apps/alsijil/migrations/0002_add_personal_note_filter.py b/aleksis/apps/alsijil/migrations/0002_add_personal_note_filter.py
deleted file mode 100644
index 13782db55d6165bc17f3e1880164ef39e109395a..0000000000000000000000000000000000000000
--- a/aleksis/apps/alsijil/migrations/0002_add_personal_note_filter.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Generated by Django 2.2.5 on 2019-11-20 14:21
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-import aleksis.apps.alsijil.models
-import aleksis.core.util.core_helpers
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ("core", "0002_activity_notification"),
-        ("alsijil", "0001_initial"),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name="PersonalNoteFilter",
-            fields=[
-                (
-                    "id",
-                    models.AutoField(
-                        auto_created=True,
-                        primary_key=True,
-                        serialize=False,
-                        verbose_name="ID",
-                    ),
-                ),
-                (
-                    "identifier",
-                    models.CharField(
-                        max_length=30,
-                        validators=[aleksis.apps.alsijil.models.isidentifier],
-                        verbose_name="Identifier",
-                    ),
-                ),
-                (
-                    "description",
-                    models.CharField(
-                        blank=True, max_length=60, verbose_name="Description"
-                    ),
-                ),
-                (
-                    "regex",
-                    models.CharField(max_length=100, verbose_name="Match expression"),
-                ),
-                (
-                    "school",
-                    models.ForeignKey(
-                        default=1,
-                        on_delete=django.db.models.deletion.CASCADE,
-                        to="core.School",
-                    ),
-                ),
-            ],
-            options={
-                "ordering": ["identifier"],
-                "unique_together": {
-                    ("school", "regex"),
-                    ("school", "description"),
-                    ("school", "identifier"),
-                },
-            },
-        ),
-    ]
diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index bfa3dd7def75c3891f4cf32b0369ad7f6d7f0ee4..b503bbf8f552e31977e56e64709a019cff265cfc 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -1,8 +1,9 @@
 from datetime import date
-from calendarweek import CalendarWeek
 
 from django.db.models import Exists, F, OuterRef
 
+from calendarweek import CalendarWeek
+
 from aleksis.apps.chronos.models import LessonPeriod
 from aleksis.core.models import Group, Person
 
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 8874719bf414a5b8dbafa603608f0cccd836241a..3867f6c5a449977f39135e1690bb7954623a247f 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -1,14 +1,14 @@
 from django.db import models
 from django.utils.translation import gettext_lazy as _
 
-from aleksis.core.mixins import CRUDMixin
+from aleksis.core.mixins import ExtensibleModel
 
 
 def isidentifier(value: str) -> bool:
     return value.isidentifier()
 
 
-class PersonalNote(models.Model):
+class PersonalNote(ExtensibleModel):
     """ A personal note about a single person. Used in the class register to note
     absences, excuses and remarks about a student in a single lesson period.
     """
@@ -27,6 +27,8 @@ class PersonalNote(models.Model):
     remarks = models.CharField(max_length=200, blank=True)
 
     class Meta:
+        verbose_name = _("Personal note")
+        verbose_name_plural = _("Personal notes")
         unique_together = [["lesson_period", "week", "person"]]
         ordering = [
             "lesson_period__lesson__date_start",
@@ -38,7 +40,7 @@ class PersonalNote(models.Model):
         ]
 
 
-class LessonDocumentation(CRUDMixin):
+class LessonDocumentation(ExtensibleModel):
     """ A documentation on a single lesson period. Non-personal, includes
     the topic and homework of the lesson.
     """
@@ -52,6 +54,8 @@ class LessonDocumentation(CRUDMixin):
     homework = models.CharField(verbose_name=_("Homework"), max_length=200, blank=True)
 
     class Meta:
+        verbose_name = _("Lesson documentation")
+        verbose_name_plural = _("Lesson documentations")
         unique_together = [["lesson_period", "week"]]
         ordering = [
             "lesson_period__lesson__date_start",
@@ -61,7 +65,7 @@ class LessonDocumentation(CRUDMixin):
         ]
 
 
-class PersonalNoteFilter(models.Model):
+class PersonalNoteFilter(ExtensibleModel):
     """ A filter definition that can generate statistics on personal note texts. """
 
     identifier = models.CharField(
@@ -74,4 +78,6 @@ class PersonalNoteFilter(models.Model):
     regex = models.CharField(verbose_name=_("Match expression"), max_length=100, unique=True)
 
     class Meta:
+        verbose_name = _("Personal note filter")
+        verbose_name_plural = _("Personal note filters")
         ordering = ["identifier"]
diff --git a/aleksis/apps/alsijil/static/css/alsijil/full_register.css b/aleksis/apps/alsijil/static/css/alsijil/full_register.css
index fe26ef3b717889ca953bc5c052ecb817d487fcf7..e9ee93a5c93d948307ae15b9f4b146616e73279a 100644
--- a/aleksis/apps/alsijil/static/css/alsijil/full_register.css
+++ b/aleksis/apps/alsijil/static/css/alsijil/full_register.css
@@ -130,3 +130,14 @@ table.person-info td.person-img img {
 .sheet * {
     page-break-inside: avoid;
 }
+
+img.max-size-600 {
+  max-width: 600px;
+  max-height: 600px;
+}
+
+img.center{
+  position: relative;
+  left: 50%;
+  transform: translateX(-50%);
+}
diff --git a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
index b8756f4bcc1572c7335e7a56194864d19c4ab475..32069660f212b015faacd13c73d5b4689382b2b2 100644
--- a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
@@ -14,7 +14,9 @@
     <section class="sheet padding-10mm bigprint" id="titlepage">
       <div>
         <h1>{% trans 'Class register' %}</h1>
-        <img src="{% cropped_thumbnail school 'logo_cropping' max_size='600x600' %}" id="school-logo" />
+        {% static "img/aleksis-banner.svg" as aleksis_banner %}
+        <img src="{% firstof request.site.preferences.theme__logo.url aleksis_banner %}"
+             alt="{{ request.site.preferences.general__title }} – Logo" class="max-size-600 center">
         <p id="group-desc">
           {{ group.name }}
         </p>
@@ -82,7 +84,7 @@
               <td>{{ person.first_name }}</td>
               <td>{{ person.get_sex_display }}</td>
               <td>{{ person.date_of_birth }}</td>
-              <td>{{ person.absences}}</td>
+              <td>{{ person.absences_count}}</td>
               <td>{{ person.unexcused }}</td>
               <td>{{ person.tardiness }}</td>
             </tr>
@@ -204,7 +206,7 @@
 
           <tbody>
             <tr>
-              <td>{{ person.absences }}</td>
+              <td>{{ person.absences_count }}</td>
               <td>{{ person.unexcused }}</td>
               <td>{{ person.tardiness }}</td>
             </tr>
diff --git a/aleksis/apps/alsijil/urls.py b/aleksis/apps/alsijil/urls.py
index 20519ad4d60020a5ed717c00a54baf4c8e21abc9..fe40f18ee256cba2f90c48489024cdde211a9b90 100644
--- a/aleksis/apps/alsijil/urls.py
+++ b/aleksis/apps/alsijil/urls.py
@@ -11,6 +11,8 @@ urlpatterns = [
     ),
     path("week", views.week_view, name="week_view"),
     path("week/<int:year>/<int:week>", views.week_view, name="week_view_by_week"),
+    path("week/<str:type_>/<int:id_>/", views.week_view, name="week_view"),
+    path("week/<int:year>/<int:week>/<str:type_>/<int:id_>/", views.week_view, name="week_view_by_week"),
     path("print/group/<int:id_>", views.full_register_group, name="full_register_group"),
     path("absence/new", views.register_absence, name="register_absence"),
     path("filters/list", views.list_personal_note_filters, name="list_personal_note_filters",),
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 0378d727ef323684db44621f5ef2ee338315d2fd..84c12a8e2e6354ec1208537dc7a31a7f142f71b6 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -1,20 +1,20 @@
-from calendarweek import CalendarWeek
 from datetime import date, datetime, timedelta
 from typing import Optional
 
-from django.contrib.auth.decorators import login_required
+from aleksis.apps.chronos.managers import TimetableType
+from aleksis.apps.chronos.util.chronos_helpers import get_el_by_pk
 from django.core.exceptions import PermissionDenied
 from django.db.models import Count, Exists, OuterRef, Q, Sum
-from django.http import Http404, HttpRequest, HttpResponse
+from django.http import Http404, HttpRequest, HttpResponse, HttpResponseNotFound
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse
 from django.utils.translation import ugettext as _
 
+from calendarweek import CalendarWeek
 from django_tables2 import RequestConfig
 
 from aleksis.apps.chronos.models import LessonPeriod
-from aleksis.core.decorators import admin_required
-from aleksis.core.models import Group, Person, School
+from aleksis.core.models import Group, Person, SchoolTerm
 from aleksis.core.util import messages
 
 from .forms import (
@@ -28,7 +28,6 @@ from .models import LessonDocumentation, PersonalNoteFilter
 from .tables import PersonalNoteFilterTable
 
 
-@login_required
 def lesson(
     request: HttpRequest,
     year: Optional[int] = None,
@@ -77,7 +76,7 @@ def lesson(
         lesson_period=lesson_period, week=wanted_week.week
     )
     lesson_documentation_form = LessonDocumentationForm(
-        request.POST or None, instance=lesson_documentation, prefix="leson_documentation",
+        request.POST or None, instance=lesson_documentation, prefix="lesson_documentation",
     )
 
     # Create a formset that holds all personal notes for all persons in this lesson
@@ -109,9 +108,8 @@ def lesson(
     return render(request, "alsijil/class_register/lesson.html", context)
 
 
-@login_required
 def week_view(
-    request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None
+    request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None, type_: Optional[str] = None, id_: Optional[int] = None
 ) -> HttpResponse:
     context = {}
 
@@ -128,57 +126,74 @@ def week_view(
         )
     ).in_week(wanted_week)
 
-    group = None  # FIXME workaround for #38
-    if (
-        request.GET.get("group", None)
-        or request.GET.get("teacher", None)
-        or request.GET.get("room", None)
-    ):
-        lesson_periods = lesson_periods.filter_from_query(request.GET)
-        if "group" in request.GET and request.GET["group"]:
-            group = Group.objects.get(pk=request.GET["group"])
-        else:
-            group = None
+    group = None
+    if type_ and id_:
+        instance = get_el_by_pk(request, type_, id_)
+
+        if isinstance(instance, HttpResponseNotFound):
+            return HttpResponseNotFound()
+
+        type_ = TimetableType.from_string(type_)
+
+        if type_ == TimetableType.GROUP:
+            group = instance
+
+        lesson_periods = lesson_periods.filter_from_type(type_, instance)
     elif hasattr(request, "user") and hasattr(request.user, "person"):
-        group = request.user.person.owner_of.first()
-        if group:
-            lesson_periods = lesson_periods.filter_group(group)
-        elif request.user.person.lessons_as_teacher.exists():
+        instance = request.user.person
+        if request.user.person.lessons_as_teacher.exists():
             lesson_periods = lesson_periods.filter_teacher(request.user.person)
+            type_ = TimetableType.TEACHER
         else:
             lesson_periods = lesson_periods.filter_participant(request.user.person)
     else:
         lesson_periods = None
 
+    # Add a form to filter the view
+    if type_:
+        initial = {type_.value: instance}
+    else:
+        initial = {}
+    select_form = SelectForm(request.POST or None, initial=initial)
+
+    if request.method == "POST":
+        if select_form.is_valid():
+            if "type_" not in select_form.cleaned_data:
+                return redirect("week_view_by_week", wanted_week.year, wanted_week.week)
+            else:
+                return redirect("week_view_by_week", wanted_week.year, wanted_week.week,
+                                select_form.cleaned_data["type_"].value, select_form.cleaned_data["instance"].pk)
+
     if lesson_periods:
         # Aggregate all personal notes for this group and week
+        lesson_periods_pk = lesson_periods.values_list("pk", flat=True)
         persons = (
             Person.objects.filter(is_active=True)
-            .filter(member_of__lessons__lesson_periods__in=lesson_periods)
+            .filter(member_of__lessons__lesson_periods__in=lesson_periods_pk)
             .distinct()
             .prefetch_related("personal_notes")
             .annotate(
-                absences=Count(
+                absences_count=Count(
                     "personal_notes__absent",
                     filter=Q(
-                        personal_notes__lesson_period__in=lesson_periods,
+                        personal_notes__lesson_period__in=lesson_periods_pk,
                         personal_notes__week=wanted_week.week,
                         personal_notes__absent=True,
                     ),
                 ),
-                unexcused=Count(
+                unexcused_count=Count(
                     "personal_notes__absent",
                     filter=Q(
-                        personal_notes__lesson_period__in=lesson_periods,
+                        personal_notes__lesson_period__in=lesson_periods_pk,
                         personal_notes__week=wanted_week.week,
                         personal_notes__absent=True,
                         personal_notes__excused=False,
                     ),
                 ),
-                tardiness=Sum(
+                tardiness_sum=Sum(
                     "personal_notes__late",
                     filter=Q(
-                        personal_notes__lesson_period__in=lesson_periods,
+                        personal_notes__lesson_period__in=lesson_periods_pk,
                         personal_notes__week=wanted_week.week,
                     ),
                 ),
@@ -187,15 +202,15 @@ def week_view(
     else:
         persons = None
 
-    # Add a form to filter the view
-    select_form = SelectForm(request.GET or None)
+    # Resort lesson periods manually because an union queryset doesn't support order_by
+    lesson_periods = sorted(lesson_periods, key=lambda x: (x.period.weekday, x.period.period))
 
-    context["current_head"] = str(wanted_week)
     context["week"] = wanted_week
     context["lesson_periods"] = lesson_periods
     context["persons"] = persons
     context["group"] = group
     context["select_form"] = select_form
+    context["instance"] = instance
 
     week_prev = wanted_week - 1
     week_next = wanted_week + 1
@@ -211,7 +226,6 @@ def week_view(
     return render(request, "alsijil/class_register/week_view.html", context)
 
 
-@login_required
 def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     context = {}
 
@@ -220,20 +234,26 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     # Get all lesson periods for the selected group
     lesson_periods = (
         LessonPeriod.objects.filter_group(group)
-        .distinct()
-        .prefetch_related("documentations", "personal_notes")
+            .distinct()
+            .prefetch_related("documentations", "personal_notes")
     )
 
+    current_school_term = SchoolTerm.current
+
+    if not current_school_term:
+        return HttpResponseNotFound(_("There is no current school term."))
+
     weeks = CalendarWeek.weeks_within(
-        School.objects.first().current_term.date_start,
-        School.objects.first().current_term.date_end,
+        current_school_term.date_start,
+        current_school_term.date_end,
     )
+
     periods_by_day = {}
     for lesson_period in lesson_periods:
         for week in weeks:
             day = week[lesson_period.period.weekday - 1]
 
-            if lesson_period.lesson.date_start <= day and lesson_period.lesson.date_end >= day:
+            if lesson_period.lesson.date_start <= day <= lesson_period.lesson.date_end:
                 documentations = list(
                     filter(lambda d: d.week == week.week, lesson_period.documentations.all(),)
                 )
@@ -247,7 +267,7 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
                 )
 
     persons = group.members.annotate(
-        absences=Count("personal_notes__absent", filter=Q(personal_notes__absent=True)),
+        absences_count=Count("personal_notes__absent", filter=Q(personal_notes__absent=True)),
         unexcused=Count(
             "personal_notes__absent",
             filter=Q(personal_notes__absent=True, personal_notes__excused=False),
@@ -274,12 +294,10 @@ def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     context["weeks"] = weeks
     context["periods_by_day"] = periods_by_day
     context["today"] = date.today()
-    context["school"] = School.objects.first()
 
     return render(request, "alsijil/print/full_register.html", context)
 
 
-@admin_required
 def register_absence(request: HttpRequest) -> HttpResponse:
     context = {}
 
@@ -349,7 +367,6 @@ def edit_personal_note_filter(request: HttpRequest, id: Optional["int"] = None)
     return render(request, "alsijil/personal_note_filter/manage.html", context)
 
 
-@admin_required
 def delete_personal_note_filter(request: HttpRequest, id_: int) -> HttpResponse:
     context = {}
 
diff --git a/poetry.lock b/poetry.lock
index b7cb16f0d2c584260a70a2a4a84752239738287e..a64701112e831ae0da22f016db69439f5a698da7 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -68,7 +68,7 @@ extras = ["phonenumbers"]
 version = ">=3.0,<4.0"
 
 [package.dependencies.django-two-factor-auth]
-extras = ["sms", "call", "yubikey", "phonenumbers"]
+extras = ["sms", "call", "phonenumbers", "yubikey"]
 version = ">=1.11.0,<2.0.0"
 
 [package.dependencies.dynaconf]
@@ -2327,14 +2327,12 @@ jinja2 = [
     {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"},
 ]
 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"},