diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index ccc75937408fdbeb5e724bb618e223bb390182a4..0000000000000000000000000000000000000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,11 +0,0 @@
-<!-- AlekSIS is developed on EduGit. GitHub only serves as
-     backup mirror and to help people find the project. If
-	 possible, please submit your merge request on EduGit!
-	 
-	 EduGit accepts logins with GitHub accounts.
--->
-
-[ ] I have read the above and have no way to contribute on EduGit
-[ ] I understand that GitHub's terms of service exclude young and 
-    learning contributors, but still cannot contribute on EduGit
-    instead.
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index e0428a7443980df6b69b32ffd17343a33fb2978f..7680489d9c9af051329fee2a02f1576d037bd787 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -13,12 +13,27 @@ Changed
 ~~~~~~~
 
 * [Dev] Rename the "late" field in the PersonalNote model to "tardiness".
+* Use new icon set inside of models and templates
+* Run full register printout generation in background 
+
+Fixed
+~~~~~
+
+* Extra marks and excused absences were counted multiple times in some class register views.
+* Substitution teachers couldn't see any persons in the person list of a substituted lesson.
+
+`2.1.1`_ - 2022-09-01
+---------------------
 
 Fixed
 ~~~~~
 
 * Register absence form wasn't accessible without direct access to class register.
 * Printing the full group register failed when a person had no personal notes.
+* Data checks reported all Lesson Documentations as being during Holidays if there was no Holiday object.
+* Students were displayed multiple times in class register views.
+* Absences were counted multiple times in some class register views.
+* Group owners couldn't create new seating plans.
 
 `2.1`_ - 2022-06-25
 -------------------
@@ -272,3 +287,4 @@ Fixed
 .. _2.0: https://edugit.org/AlekSIS/Official/AlekSIS-App-Alsijil/-/tags/2.0
 .. _2.0.1: https://edugit.org/AlekSIS/Official/AlekSIS-App-Alsijil/-/tags/2.0.1
 .. _2.1: https://edugit.org/AlekSIS/Official/AlekSIS-App-Alsijil/-/tags/2.1
+.. _2.1.1: https://edugit.org/AlekSIS/Official/AlekSIS-App-Alsijil/-/tags/2.1.1
diff --git a/aleksis/apps/alsijil/data_checks.py b/aleksis/apps/alsijil/data_checks.py
index 864f019646411443605b0495075ba6acfb47219b..cb056e8cb3728a01c98e110f15e12da629df7ff9 100644
--- a/aleksis/apps/alsijil/data_checks.py
+++ b/aleksis/apps/alsijil/data_checks.py
@@ -113,7 +113,7 @@ class LessonDocumentationOnHolidaysDataCheck(DataCheck):
 
         documentations = LessonDocumentation.objects.not_empty().annotate_date_range()
 
-        q = Q()
+        q = Q(pk__in=[])
         for holiday in holidays:
             q = q | Q(day_end__gte=holiday.date_start, day_start__lte=holiday.date_end)
         documentations = documentations.filter(q)
@@ -147,7 +147,7 @@ class PersonalNoteOnHolidaysDataCheck(DataCheck):
 
         personal_notes = PersonalNote.objects.not_empty().annotate_date_range()
 
-        q = Q()
+        q = Q(pk__in=[])
         for holiday in holidays:
             q = q | Q(day_end__gte=holiday.date_start, day_start__lte=holiday.date_end)
         personal_notes = personal_notes.filter(q)
diff --git a/aleksis/apps/alsijil/menus.py b/aleksis/apps/alsijil/menus.py
index 71ce1d9f119ffbe23dbea6f42dbd40a83811e82a..fcf14e7cc8f8ea51eabee00abb5a75c61de42af8 100644
--- a/aleksis/apps/alsijil/menus.py
+++ b/aleksis/apps/alsijil/menus.py
@@ -5,7 +5,7 @@ MENUS = {
         {
             "name": _("Class register"),
             "url": "#",
-            "icon": "chrome_reader_mode",
+            "svg_icon": "mdi:book-open-outline",
             "root": True,
             "validators": [
                 "menu_generator.validators.is_authenticated",
@@ -15,7 +15,7 @@ MENUS = {
                 {
                     "name": _("Current lesson"),
                     "url": "lesson_period",
-                    "icon": "alarm",
+                    "svg_icon": "mdi:alarm",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -26,7 +26,7 @@ MENUS = {
                 {
                     "name": _("Current week"),
                     "url": "week_view",
-                    "icon": "view_week",
+                    "svg_icon": "mdi:view-week-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -37,7 +37,7 @@ MENUS = {
                 {
                     "name": _("My groups"),
                     "url": "my_groups",
-                    "icon": "people",
+                    "svg_icon": "mdi:account-multiple-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -48,7 +48,7 @@ MENUS = {
                 {
                     "name": _("My overview"),
                     "url": "overview_me",
-                    "icon": "insert_chart",
+                    "svg_icon": "mdi:chart-box-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -59,7 +59,7 @@ MENUS = {
                 {
                     "name": _("My students"),
                     "url": "my_students",
-                    "icon": "people",
+                    "svg_icon": "mdi:account-school-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -70,7 +70,7 @@ MENUS = {
                 {
                     "name": _("Assign group role"),
                     "url": "assign_group_role_multiple",
-                    "icon": "assignment_ind",
+                    "svg_icon": "mdi:clipboard-account-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -81,7 +81,7 @@ MENUS = {
                 {
                     "name": _("All lessons"),
                     "url": "all_register_objects",
-                    "icon": "list",
+                    "svg_icon": "mdi:format-list-text",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -96,14 +96,14 @@ MENUS = {
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
-                            "alsijil.register_absence_rule",
+                            "alsijil.view_register_absence_rule",
                         ),
                     ],
                 },
                 {
                     "name": _("Excuse types"),
                     "url": "excuse_types",
-                    "icon": "label",
+                    "svg_icon": "mdi:label-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -114,7 +114,7 @@ MENUS = {
                 {
                     "name": _("Extra marks"),
                     "url": "extra_marks",
-                    "icon": "label",
+                    "svg_icon": "mdi:label-variant-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
@@ -125,7 +125,7 @@ MENUS = {
                 {
                     "name": _("Manage group roles"),
                     "url": "group_roles",
-                    "icon": "assignment_ind",
+                    "svg_icon": "mdi:clipboard-plus-outline",
                     "validators": [
                         (
                             "aleksis.core.util.predicates.permission_validator",
diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index 5fd9b1b248e73fc91294efca5cdfc091944a9261..2c94f1fd980f54de9a18f2d7eb8f8424c241699a 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -434,6 +434,7 @@ def generate_person_list_with_class_register_statistics(
             "filtered_personal_notes",
             filter=Q(filtered_personal_notes__absent=True)
             & ~Q(filtered_personal_notes__excuse_type__count_as_absent=False),
+            distinct=True,
         ),
         excused=Count(
             "filtered_personal_notes",
@@ -442,6 +443,7 @@ def generate_person_list_with_class_register_statistics(
                 filtered_personal_notes__excused=True,
             )
             & ~Q(filtered_personal_notes__excuse_type__count_as_absent=False),
+            distinct=True,
         ),
         excused_without_excuse_type=Count(
             "filtered_personal_notes",
@@ -450,15 +452,16 @@ def generate_person_list_with_class_register_statistics(
                 filtered_personal_notes__excused=True,
                 filtered_personal_notes__excuse_type__isnull=True,
             ),
+            distinct=True,
         ),
         unexcused=Count(
             "filtered_personal_notes",
             filter=Q(filtered_personal_notes__absent=True, filtered_personal_notes__excused=False),
+            distinct=True,
         ),
         tardiness=Sum("filtered_personal_notes__tardiness"),
         tardiness_count=Count(
-            "filtered_personal_notes",
-            filter=Q(filtered_personal_notes__tardiness__gt=0),
+            "filtered_personal_notes", filter=Q(filtered_personal_notes__late__gt=0), distinct=True
         ),
     )
 
@@ -468,6 +471,7 @@ def generate_person_list_with_class_register_statistics(
                 extra_mark.count_label: Count(
                     "filtered_personal_notes",
                     filter=Q(filtered_personal_notes__extra_marks=extra_mark),
+                    distinct=True,
                 )
             }
         )
@@ -481,6 +485,7 @@ def generate_person_list_with_class_register_statistics(
                         filtered_personal_notes__absent=True,
                         filtered_personal_notes__excuse_type=excuse_type,
                     ),
+                    distinct=True,
                 )
             }
         )
diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 917a6d5b1b94fa7882302eecd3ad7f9088a86710..b504a294164a6388099148fda5149091767577a7 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -5,6 +5,7 @@ from urllib.parse import urlparse
 from django.db import models
 from django.db.models.constraints import CheckConstraint
 from django.db.models.query_utils import Q
+from django.urls import reverse
 from django.utils.formats import date_format
 from django.utils.translation import gettext_lazy as _
 
@@ -31,6 +32,7 @@ from aleksis.apps.alsijil.managers import (
 from aleksis.apps.chronos.managers import GroupPropertiesMixin
 from aleksis.apps.chronos.mixins import WeekRelatedMixin
 from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod, TimePeriod
+from aleksis.core.data_checks import field_validation_data_check_factory
 from aleksis.core.mixins import ExtensibleModel, GlobalPermissionModel
 from aleksis.core.models import SchoolTerm
 from aleksis.core.util.core_helpers import get_site_preferences
@@ -450,6 +452,8 @@ class ExtraMark(ExtensibleModel):
 
 
 class GroupRole(ExtensibleModel):
+    data_checks = [field_validation_data_check_factory("alsijil", "GroupRole", "icon")]
+
     objects = GroupRoleManager.from_queryset(GroupRoleQuerySet)()
 
     name = models.CharField(max_length=255, verbose_name=_("Name"))
@@ -467,6 +471,9 @@ class GroupRole(ExtensibleModel):
         ]
         permissions = (("assign_group_role", _("Can assign group role")),)
 
+    def get_absolute_url(self) -> str:
+        return reverse("edit_group_role", args=[self.id])
+
 
 class GroupRoleAssignment(GroupPropertiesMixin, ExtensibleModel):
     objects = GroupRoleAssignmentManager.from_queryset(GroupRoleAssignmentQuerySet)()
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index b2640b8cfbf2eb8a1874926ee5a5bce2809ef1dd..e9011c6c2b33ed58a21b6412f6c7e366b1b5e49e 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -156,15 +156,20 @@ view_week_personal_notes_predicate = has_person & (
 add_perm("alsijil.view_week_personalnote_rule", view_week_personal_notes_predicate)
 
 # Register absence
-register_absence_predicate = has_person & (
+view_register_absence_predicate = has_person & (
     (
         is_person_group_owner
         & is_site_preference_set("alsijil", "register_absence_as_primary_group_owner")
     )
     | has_global_perm("alsijil.register_absence")
+)
+
+register_absence_predicate = has_person & (
+    view_register_absence_predicate
     | has_object_perm("core.register_absence_person")
     | has_person_group_object_perm("core.register_absence_group")
 )
+add_perm("alsijil.view_register_absence_rule", view_register_absence_predicate)
 add_perm("alsijil.register_absence_rule", register_absence_predicate)
 
 # View full register for group
diff --git a/aleksis/apps/alsijil/tasks.py b/aleksis/apps/alsijil/tasks.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa8de7b5a075b9a1ae37b129b1870482966577a5
--- /dev/null
+++ b/aleksis/apps/alsijil/tasks.py
@@ -0,0 +1,182 @@
+from copy import deepcopy
+from datetime import date, timedelta
+
+from django.db.models import Q
+from django.utils.translation import gettext as _
+
+from calendarweek import CalendarWeek
+from celery.result import allow_join_result
+from celery.states import SUCCESS
+
+from aleksis.apps.chronos.models import Event, ExtraLesson, LessonPeriod
+from aleksis.core.models import Group, PDFFile
+from aleksis.core.util.celery_progress import ProgressRecorder, recorded_task
+from aleksis.core.util.pdf import generate_pdf_from_template
+
+from .models import ExcuseType, ExtraMark, LessonDocumentation, PersonalNote
+
+
+@recorded_task
+def generate_full_register_printout(group: int, file_object: int, recorder: ProgressRecorder):
+    """Generate a full register printout as PDF for a group."""
+    context = {}
+
+    _number_of_steps = 8
+
+    recorder.set_progress(1, _number_of_steps, _("Load data ..."))
+
+    group = Group.objects.get(pk=group)
+    file_object = PDFFile.objects.get(pk=file_object)
+
+    groups_q = (
+        Q(lesson_period__lesson__groups=group)
+        | Q(lesson_period__lesson__groups__parent_groups=group)
+        | Q(extra_lesson__groups=group)
+        | Q(extra_lesson__groups__parent_groups=group)
+        | Q(event__groups=group)
+        | Q(event__groups__parent_groups=group)
+    )
+    personal_notes = (
+        PersonalNote.objects.prefetch_related(
+            "lesson_period__substitutions", "lesson_period__lesson__teachers"
+        )
+        .not_empty()
+        .filter(groups_q)
+        .filter(groups_of_person=group)
+    )
+    documentations = LessonDocumentation.objects.not_empty().filter(groups_q)
+
+    recorder.set_progress(2, _number_of_steps, _("Sort data ..."))
+
+    sorted_documentations = {"extra_lesson": {}, "event": {}, "lesson_period": {}}
+    sorted_personal_notes = {"extra_lesson": {}, "event": {}, "lesson_period": {}, "person": {}}
+    for documentation in documentations:
+        key = documentation.register_object.label_
+        sorted_documentations[key][documentation.register_object_key] = documentation
+
+    for note in personal_notes:
+        key = note.register_object.label_
+        sorted_personal_notes[key].setdefault(note.register_object_key, [])
+        sorted_personal_notes[key][note.register_object_key].append(note)
+        sorted_personal_notes["person"].setdefault(note.person.pk, [])
+        sorted_personal_notes["person"][note.person.pk].append(note)
+
+    recorder.set_progress(3, _number_of_steps, _("Load lesson data ..."))
+
+    # Get all lesson periods for the selected group
+    lesson_periods = LessonPeriod.objects.filter_group(group).distinct()
+    events = Event.objects.filter_group(group).distinct()
+    extra_lessons = ExtraLesson.objects.filter_group(group).distinct()
+    weeks = CalendarWeek.weeks_within(group.school_term.date_start, group.school_term.date_end)
+
+    register_objects_by_day = {}
+    for extra_lesson in extra_lessons:
+        day = extra_lesson.date
+        register_objects_by_day.setdefault(day, []).append(
+            (
+                extra_lesson,
+                sorted_documentations["extra_lesson"].get(extra_lesson.pk),
+                sorted_personal_notes["extra_lesson"].get(extra_lesson.pk, []),
+                None,
+            )
+        )
+
+    for event in events:
+        day_number = (event.date_end - event.date_start).days + 1
+        for i in range(day_number):
+            day = event.date_start + timedelta(days=i)
+            event_copy = deepcopy(event)
+            event_copy.annotate_day(day)
+            register_objects_by_day.setdefault(day, []).append(
+                (
+                    event_copy,
+                    sorted_documentations["event"].get(event.pk),
+                    sorted_personal_notes["event"].get(event.pk, []),
+                    None,
+                )
+            )
+
+    recorder.set_progress(4, _number_of_steps, _("Sort lesson data ..."))
+
+    weeks = CalendarWeek.weeks_within(
+        group.school_term.date_start,
+        group.school_term.date_end,
+    )
+
+    for lesson_period in lesson_periods:
+        for week in weeks:
+            day = week[lesson_period.period.weekday]
+
+            if (
+                lesson_period.lesson.validity.date_start
+                <= day
+                <= lesson_period.lesson.validity.date_end
+            ):
+                filtered_documentation = sorted_documentations["lesson_period"].get(
+                    f"{lesson_period.pk}_{week.week}_{week.year}"
+                )
+                filtered_personal_notes = sorted_personal_notes["lesson_period"].get(
+                    f"{lesson_period.pk}_{week.week}_{week.year}", []
+                )
+
+                substitution = lesson_period.get_substitution(week)
+
+                register_objects_by_day.setdefault(day, []).append(
+                    (lesson_period, filtered_documentation, filtered_personal_notes, substitution)
+                )
+
+    recorder.set_progress(5, _number_of_steps, _("Load statistics ..."))
+
+    persons = group.members.prefetch_related(None).select_related(None)
+    persons = group.generate_person_list_with_class_register_statistics(persons)
+
+    prefetched_persons = []
+    for person in persons:
+        person.filtered_notes = sorted_personal_notes["person"].get(person.pk, [])
+        prefetched_persons.append(person)
+
+    context["school_term"] = group.school_term
+    context["persons"] = prefetched_persons
+    context["excuse_types"] = ExcuseType.objects.filter(count_as_absent=True)
+    context["excuse_types_not_absent"] = ExcuseType.objects.filter(count_as_absent=False)
+    context["extra_marks"] = ExtraMark.objects.all()
+    context["group"] = group
+    context["weeks"] = weeks
+    context["register_objects_by_day"] = register_objects_by_day
+    context["register_objects"] = list(lesson_periods) + list(events) + list(extra_lessons)
+    context["today"] = date.today()
+    context["lessons"] = (
+        group.lessons.all()
+        .select_related(None)
+        .prefetch_related(None)
+        .select_related("validity", "subject")
+        .prefetch_related("teachers", "lesson_periods")
+    )
+    context["child_groups"] = (
+        group.child_groups.all()
+        .select_related(None)
+        .prefetch_related(None)
+        .prefetch_related(
+            "lessons",
+            "lessons__validity",
+            "lessons__subject",
+            "lessons__teachers",
+            "lessons__lesson_periods",
+        )
+    )
+
+    recorder.set_progress(6, _number_of_steps, _("Generate template ..."))
+
+    file_object, result = generate_pdf_from_template(
+        "alsijil/print/full_register.html", context, file_object=file_object
+    )
+
+    recorder.set_progress(7, _number_of_steps, _("Generate PDF ..."))
+
+    with allow_join_result():
+        result.wait()
+        file_object.refresh_from_db()
+        if not result.status == SUCCESS and file_object.file:
+            raise Exception(_("PDF generation failed"))
+
+    recorder.set_progress(8, _number_of_steps)
diff --git a/aleksis/apps/alsijil/templates/alsijil/absences/register_confirm.html b/aleksis/apps/alsijil/templates/alsijil/absences/register_confirm.html
index dc069357060d16e16983d7e913c9881e9e394537..2c427ef2fa701a4e1beb36b40fc5c1de09ca8e44 100644
--- a/aleksis/apps/alsijil/templates/alsijil/absences/register_confirm.html
+++ b/aleksis/apps/alsijil/templates/alsijil/absences/register_confirm.html
@@ -18,11 +18,11 @@
       </div>
       <div class="collection">
         <div class="collection-item">
-          <i class="material-icons left">date_range</i>
+          <i class="material-icons iconify left" data-icon="mdi:calendar-range"></i>
           {{ form_data.date_start }}, {{ form_data.from_period }}. – {{ form_data.date_end }}, {{ form_data.to_period }}.
           {% if form_data.date_start != form_data.date_end %}
             <figure class="alert warning">
-              <i class="material-icons left">warning</i>
+              <i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>
               {% blocktrans %}
                 As the length of this absence is longer than one day,
                 please double check the correctness of your entry.
@@ -31,12 +31,12 @@
           {% endif %}
         </div>
         <div class="collection-item">
-          <i class="material-icons left">list</i>
+          <i class="material-icons iconify left" data-icon="mdi:format-list-bulleted"></i>
           {% blocktrans with count=affected_lessons %} {{ count }} affected lessons {% endblocktrans %}
           {% if affected_lessons == 0 %}
             <div class="alert error">
               <div>
-                <i class="material-icons left">error</i>
+                <i class="material-icons iconify left" data-icon="mdi:alert-octagon-outline"></i>
                 {% blocktrans %}
                   There are no affected lessons. Registering this absence won't have any effect.
                 {% endblocktrans %}
@@ -45,7 +45,7 @@
           {% endif %}
         </div>
         <div class="collection-item">
-          <i class="material-icons left">label</i>
+          <i class="material-icons iconify left" data-icon="mdi:label-outline"></i>
           {% if form_data.absent %}
             <span class="chip red white-text">{% trans "Absent" %}</span>
             {% if form_data.excused and form_data.excuse_type %}
@@ -59,7 +59,7 @@
         </div>
         {% if form_data.remarks %}
           <div class="collection-item">
-            <i class="material-icons left">edit</i>
+            <i class="material-icons iconify left" data-icon="mdi:pencil-outline"></i>
             {{ form_data.remarks }}
           </div>
         {% endif %}
@@ -75,7 +75,7 @@
     <input type="hidden" name="confirmed" value="1">
     {% include "core/partials/save_button.html" %}
     <a class="btn red waves-effect waves-light" href="{% url "register_absence" person.pk %}">
-      <i class="material-icons left">cancel</i>
+      <i class="material-icons iconify left" data-icon="mdi:close"></i>
       {% trans "Cancel" %}
     </a>
   </form>
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/groups.html b/aleksis/apps/alsijil/templates/alsijil/class_register/groups.html
index 8c6254cdbd54ea045ec16df9684b6e65171a9d33..43a6eeeb9349969b58c61111e6017b7d24e74f60 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/groups.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/groups.html
@@ -31,23 +31,23 @@
         <td>
           <div class="right">
             <a class="btn primary-color waves-effect waves-light" href="{% url "students_list" group.pk %}">
-              <i class="material-icons left">people</i>
+              <i class="material-icons iconify left" data-icon="mdi:account-multiple-outline"></i>
               {% trans "Students list" %}
             </a>
             <a class="btn secondary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
-              <i class="material-icons left">view_week</i>
+              <i class="material-icons iconify left" data-icon="mdi:view-week-outline"></i>
               {% trans "Week view" %}
             </a>
             {% has_perm "alsijil.view_assigned_grouproles_rule" user group as can_view_assigned_group_roles %}
             {% if can_view_assigned_group_roles %}
               <a class="btn primary waves-effect waves-light" href="{% url 'assigned_group_roles' group.pk %}">
-                <i class="material-icons left">assignment_ind</i>
+                <i class="material-icons iconify left" data-icon="mdi:clipboard-account-outline"></i>
                 {% trans "Roles" %}
               </a>
             {% endif %}
             <a class="btn primary waves-effect waves-light" href="{% url "full_register_group" group.pk %}"
                target="_blank">
-              <i class="material-icons left">print</i>
+              <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
               {% trans "Generate printout" %}
             </a>
           </div>
@@ -72,13 +72,13 @@
           </p>
           <p>
             <a class="btn primary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
-              <i class="material-icons left">people</i>
+              <i class="material-icons iconify left" data-icon="mdi:account-multiple-outline"></i>
               {% trans "Students list" %}
             </a>
           </p>
           <p>
             <a class="btn secondary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
-              <i class="material-icons left">view_week</i>
+              <i class="material-icons iconify left" data-icon="mdi:view-week-outline"></i>
               {% trans "Week view" %}
             </a>
           </p>
@@ -86,7 +86,7 @@
           {% if can_view_assigned_group_roles %}
             <p>
               <a class="btn primary waves-effect waves-light" href="{% url 'assigned_group_roles' group.pk %}">
-                <i class="material-icons left">assignment_ind</i>
+                <i class="material-icons iconify left" data-icon="mdi:clipboard-account-outline"></i>
                 {% trans "Roles" %}
               </a>
             </p>
@@ -94,7 +94,7 @@
           <p>
             <a class="btn primary waves-effect waves-light" href="{% url "full_register_group" group.pk %}"
                target="_blank">
-              <i class="material-icons left">print</i>
+              <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
               {% trans "Generate printout" %}
             </a>
           </p>
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
index 6de367aee293d9a4c74708ebc2bdaabff775ed88..fd376568067136e72107ec5f9363b4dc68ab4040 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/lesson.html
@@ -17,14 +17,14 @@
   <ul class="tabs tabs-transparent tabs-icons tabs-fixed-width">
     <li class="tab">
       <a href="#lesson-documentation">
-        <i class="material-icons">speaker_notes</i>
+        <i class="material-icons iconify" data-icon="mdi:message-bulleted"></i>
         {% trans "Period" %}
       </a>
     </li>
     {% if register_object.label_ != "lesson_period" or not register_object.get_substitution.cancelled or not request.site.preferences.alsijil__block_personal_notes_for_cancelled %}
       <li class="tab">
         <a href="#personal-notes">
-          <i class="material-icons">people</i>
+          <i class="material-icons iconify" data-icon="mdi:account-multiple-outline"></i>
           {% trans "Persons" %}
         </a>
       </li>
@@ -32,7 +32,7 @@
     {% if with_seating_plan %}
       <li class="tab">
         <a href="#seating-plan">
-          <i class="material-icons">event_seat</i>
+          <i class="material-icons iconify" data-icon="mdi:seat-outline"></i>
           {% trans "Seating plan" %}
         </a>
       </li>
@@ -42,7 +42,7 @@
       {% if prev_lesson.get_lesson_documentation and can_view_prev_lesson_documentation %}
         <li class="tab">
           <a href="#previous-lesson">
-            <i class="material-icons">history</i>
+            <i class="material-icons iconify" data-icon="mdi:history"></i>
             {% trans "Previous" %}
           </a>
         </li>
@@ -50,7 +50,7 @@
     {% endif %}
     <li class="tab">
       <a href="#more">
-        <i class="material-icons">more_horiz</i>
+        <i class="material-icons iconify" data-icon="mdi:dots-horizontal"></i>
         {% trans "More" %}
       </a>
     </li>
@@ -69,7 +69,7 @@
         {% if back_to_week_url %}
           <a href="{{ back_to_week_url }}"
              class="btn secondary-color waves-light waves-effect margin-bottom {% if prev_lesson_person or next_lesson_person %}hide-on-extra-large-only{% endif %}">
-            <i class="material-icons left">chevron_left</i> {% trans "Week view" %}
+            <i class="material-icons iconify left" data-icon="mdi:chevron-left"></i> {% trans "Week view" %}
           </a>
         {% endif %}
 
@@ -78,7 +78,7 @@
             {% if back_to_week_url %}
               <a href="{{ back_to_week_url }}"
                  class="btn-flat secondary-color-text waves-light waves-effect left hide-on-med-and-down hide-on-large-only show-on-extra-large">
-                <i class="material-icons left">chevron_left</i> {% trans "Week view" %}
+                <i class="material-icons iconify left" data-icon="mdi:chevron-left"></i> {% trans "Week view" %}
               </a>
             {% endif %}
 
@@ -89,7 +89,7 @@
                href="{% url "lesson_period" prev_lesson_person.week.year prev_lesson_person.week.week prev_lesson_person.id %}"
                 {% endif %}
             >
-              <i class="material-icons left">navigate_before</i>
+              <i class="material-icons iconify left" data-icon="mdi:chevron-left"></i>
               <span class="hide-on-small-only">{% trans "My previous lesson" %}</span>
               <span class="hide-on-med-and-up">{% trans "Previous" %}</span>
             </a>
@@ -100,7 +100,7 @@
                href="{% url "lesson_period" next_lesson_person.week.year next_lesson_person.week.week next_lesson_person.id %}"
                 {% endif %}
             >
-              <i class="material-icons right">navigate_next</i>
+              <i class="material-icons iconify right" data-icon="mdi:chevron-right"></i>
               <span class="hide-on-small-only">{% trans "My next lesson" %}</span>
               <span class="hide-on-med-and-up">{% trans "Next" %}</span>
             </a>
@@ -155,7 +155,7 @@
           <div class="card">
             <div class="card-content center-align">
               <p>
-                <i class="material-icons medium orange-text">warning</i>
+                <i class="material-icons iconify medium orange-text" data-icon="mdi:alert-outline"></i>
               </p>
               <p class="card-title">
                 {% blocktrans %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
index d11b192fbecb27004b1cb850e0e3070239975187..78792a793cce1b93577d7bf6ca55da771a43a7df 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/person.html
@@ -15,7 +15,7 @@
   {% if has_students %}
     <a href="{% url "my_students" %}"
        class="btn-flat primary-color-text waves-light waves-effect">
-      <i class="material-icons left">chevron_left</i> {% trans "Back" %}
+      <i class="material-icons iconify left" data-icon="mdi:chevron-left"></i> {% trans "Back" %}
     </a>
   {% endif %}
   <span id="heading">
@@ -26,7 +26,7 @@
   {% has_perm "alsijil.register_absence_rule" user person as can_register_absence %}
   {% if can_register_absence %}
     <a class="btn primary-color waves-effect waves-light right" href="{% url "register_absence" person.pk %}">
-      <i class="material-icons left">rate_review</i>
+      <i class="material-icons iconify left" data-icon="mdi:message-draw"></i>
       {% trans "Register absence" %}
     </a>
   {% endif %}
@@ -70,13 +70,13 @@
         </figure>
         <div class="modal-footer">
           <button type="button" class="btn-flat secondary-color-text waves-effect waves-ripple" id="remove-filters">
-            <i class="material-icons left">clear</i>{% trans "Clear all filters" %}
+            <i class="material-icons iconify left" data-icon="mdi:close"></i>{% trans "Clear all filters" %}
           </button>
           <button type="button" class="modal-close btn-flat red-text waves-effect waves-ripple waves-red">
-            <i class="material-icons left">cancel</i>{% trans "Close" %}
+            <i class="material-icons iconify left" data-icon="mdi:close-circle-outline"></i>{% trans "Close" %}
           </button>
           <button type="submit" class="modal-close btn-flat primary-color-text waves-effect waves-ripple waves-light">
-            <i class="material-icons left">filter_alt</i>{% trans "Filter" %}
+            <i class="material-icons iconify left" data-icon="mdi:filter-outline"></i>{% trans "Filter" %}
           </button>
         </div>
       </form>
@@ -88,7 +88,8 @@
               {% if can_mark_all_as_excused %} medium-high-right {% endif %}"
               data-target="filter-modal"
               type="button">
-            {% trans "Filter results" %} ({{ num_filters }})<i class="material-icons right">filter_alt</i>
+            {% trans "Filter results" %} ({{ num_filters }})
+            <i class="material-icons iconify right" data-icon="mdi:filter-outline"></i>
           </button>
         </div>
         <form action="" method="post" class="">
@@ -100,7 +101,7 @@
               </div>
               <div class="col s12 m3">
                 <button type="submit" class="btn waves-effect waves-light medium-high full-width-s">
-                  Run <i class="material-icons right">send</i>
+                  Run <i class="material-icons iconify right" data-icon="mdi:send-outline"></i>
                 </button>
               </div>
             {% endif %}
@@ -121,7 +122,7 @@
         {% for school_term, stat in stats %}
           <li {% if forloop.first %}class="active"{% endif %}>
             <div class="collapsible-header">
-              <i class="material-icons">date_range</i>{{ school_term }}</div>
+              <i class="material-icons iconify" data-icon="mdi:calendar-range"></i>{{ school_term }}</div>
             <div class="collapsible-body">
               <table>
                 <tr>
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html b/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html
index f2c8394912a6f9bd7ddd15d734870168e08b0ee1..6873ddc84a1cdbad62ff43b09d1d50ece163a01a 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/persons.html
@@ -23,11 +23,11 @@
           <div class="hundred-percent">
             <span class="right show-on-active hide-on-small-and-down">
               <a class="btn primary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
-                <i class="material-icons left">view_week</i>
+                <i class="material-icons iconify left" data-icon="mdi:view-week-outline"></i>
                 {% trans "Week view" %}
               </a>
               <a class="btn waves-effect waves-light" href="{% url "full_register_group" group.pk %}" target="_blank">
-                <i class="material-icons left">print</i>
+                <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
                 {% trans "Generate printout" %}
               </a>
             </span>
@@ -39,14 +39,14 @@
             <p class="show-on-active hide-on-med-and-up">
               <a class="btn primary-color waves-effect waves-light hundred-percent"
                  href="{% url "week_view" "group" group.pk %}">
-                <i class="material-icons left">view_week</i>
+                <i class="material-icons iconify left" data-icon="mdi:view-week-outline"></i>
                 {% trans "Week view" %}
               </a>
             </p>
             <p class="show-on-active hide-on-med-and-up">
               <a class="btn waves-effect waves-light hundred-percent" href="{% url "full_register_group" group.pk %}"
                  target="_blank">
-                <i class="material-icons left">print</i>
+                <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
                 {% trans "Generate printout" %}
               </a>
             </p>
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/students_list.html b/aleksis/apps/alsijil/templates/alsijil/class_register/students_list.html
index 245addc839dfb2991eb535b46017aa5866def7d2..72bb8071f1b05f7e911bf75776a1740a9a5d5ae9 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/students_list.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/students_list.html
@@ -7,16 +7,16 @@
 {% block page_title %}
   <a href="{% url "my_groups" %}"
      class="btn-flat primary-color-text waves-light waves-effect">
-    <i class="material-icons left">chevron_left</i> {% trans "Back" %}
+    <i class="material-icons iconify left" data-icon="mdi:chevron-left"></i> {% trans "Back" %}
   </a>
   {% blocktrans with group=group %}Students list: {{ group }}{% endblocktrans %}
   <span class="right show-on-active hide-on-small-and-down">
     <a class="btn primary-color waves-effect waves-light" href="{% url "week_view" "group" group.pk %}">
-      <i class="material-icons left">view_week</i>
+      <i class="material-icons iconify left" data-icon="mdi:view-week-outline"></i>
       {% trans "Week view" %}
     </a>
     <a class="btn waves-effect waves-light" href="{% url "full_register_group" group.pk %}" target="_blank">
-      <i class="material-icons left">print</i>
+      <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
       {% trans "Generate printout" %}
     </a>
   </span>
@@ -31,14 +31,14 @@
   <p class="show-on-active hide-on-med-and-up">
     <a class="btn primary-color waves-effect waves-light hundred-percent"
        href="{% url "week_view" "group" group.pk %}">
-      <i class="material-icons left">view_week</i>
+       <i class="material-icons iconify left" data-icon="mdi:view-week-outline"></i>
       {% trans "Week view" %}
     </a>
   </p>
   <p class="show-on-active hide-on-med-and-up">
     <a class="btn waves-effect waves-light hundred-percent" href="{% url "full_register_group" group.pk %}"
        target="_blank">
-      <i class="material-icons left">print</i>
+      <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
       {% trans "Generate printout" %}
     </a>
   </p>
diff --git a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
index 4742b43208a86a35e4fcd51ea7e3ef07ddc4dee2..ce38ee671b6e51a9f4417cb8507dc530b2b81a48 100644
--- a/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
+++ b/aleksis/apps/alsijil/templates/alsijil/class_register/week_view.html
@@ -17,20 +17,20 @@
       <ul class="tabs tabs-transparent tabs-icons tabs-fixed-width">
         <li class="tab col">
           <a class="active" href="#week-overview">
-            <i class="material-icons">speaker_notes</i>
+            <i class="material-icons iconify" data-icon="mdi:message-bulleted"></i>
             {% trans "Lesson documentations" %}
           </a>
         </li>
         <li class="tab col">
           <a href="#personal-notes">
-            <i class="material-icons">people</i>
+            <i class="material-icons iconify" data-icon="mdi:account-multiple-outline"></i>
             {% trans "Persons" %}
           </a>
         </li>
         {% if group_roles %}
           <li class="tab col">
             <a href="#group-roles">
-              <i class="material-icons">assignment_ind</i>
+              <i class="material-icons iconify" data-icon="mdi:clipboard-account-outline"></i>
               {% trans "Group roles" %}
             </a>
           </li>
@@ -50,16 +50,14 @@
         {% csrf_token %}
         {% form form=select_form %}{% endform %}
         <button type="submit" class="btn waves-effect waves-light primary-color">
-          <i class="material-icons left">check</i>
+          <i class="material-icons iconify left" data-icon="mdi:check"></i>
           {% blocktrans %}Select{% endblocktrans %}
         </button>
       </form>
     </div>
     <div class="col s12 m4 l2 right">
       <button type="button" class="btn waves-effect waves-light hundred-percent" id="toggle-button">
-        <i class="material-icons left">
-          filter_alt
-        </i> {% trans "Toggle filters" %}
+        <i class="material-icons iconify left" data-icon="mdi:filter-outline"></i> {% trans "Toggle filters" %}
       </button>
     </div>
   </div>
@@ -74,11 +72,11 @@
   {% if group %}
     <p class="hide-on-med-and-down">
       <a class="btn primary-color waves-effect waves-light" href="{% url "students_list" group.pk %}">
-        <i class="material-icons left">people</i>
+        <i class="material-icons iconify left" data-icon="mdi:account-multiple-outline"></i>
         {% trans "Students list" %}
       </a>
       <a class="btn waves-effect waves-light" href="{% url "full_register_group" group.pk %}" target="_blank">
-        <i class="material-icons left">print</i>
+        <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
         {% trans "Generate printout" %}
       </a>
     </p>
@@ -86,14 +84,14 @@
     <p class="hide-on-med-and-up">
       <a class="btn primary-color waves-effect waves-light hundred-percent"
          href="{% url "students_list" group.pk %}">
-        <i class="material-icons left">people</i>
+        <i class="material-icons iconify left" data-icon="mdi:account-multiple-outline"></i>
         {% trans "Students list" %}
       </a>
     </p>
     <p class="hide-on-med-and-up">
       <a class="btn waves-effect waves-light hundred-percent" href="{% url "full_register_group" group.pk %}"
          target="_blank">
-        <i class="material-icons left">print</i>
+        <i class="material-icons iconify left" data-icon="mdi:printer-outline"></i>
         {% trans "Generate printout" %}
       </a>
     </p>
@@ -212,7 +210,7 @@
                 <li class="">
                   <div class="collapsible-header flow-text">
                     {{ advanced_weekday.name }}, {{ advanced_weekday.date }} <i
-                    class="material-icons collapsible-icon-right">expand_more</i>
+                    class="material-icons iconify collapsible-icon-right" data-icon="mdi:unfold-more-horizontal"></i>
                   </div>
                   <div class="collapsible-body">
                     <div class="collection">
@@ -290,9 +288,8 @@
                 <p class="subtitle">
                   <span>{{ advanced_weekday.date }}</span>
                   <button class="btn-superflat right waves-effect unfold-trigger">
-                    {% trans "Unfold" %} <i class="material-icons">
-                    expand_less
-                  </i>
+                    {% trans "Unfold" %}
+                    <i class="material-icons iconify" data-icon="mdi:unfold-less-horizontal"></i>
                   </button>
                 </p>
                 <div class="horizontal-scroll-container">
@@ -381,7 +378,7 @@
                 {% if can_register_absence %}
                   <a class="btn primary-color waves-effect waves-light right"
                      href="{% url "register_absence" person.person.pk %}">
-                    <i class="material-icons left">rate_review</i>
+                    <i class="material-icons iconify left" data-icon="mdi:message-draw"></i>
                     {% trans "Register absence" %}
                   </a>
                 {% endif %}
@@ -432,7 +429,7 @@
     <div class="card">
       <div class="card-content">
         <span class="card-title">
-          <i class="material-icons red-text left">warning</i>
+          <i class="material-icons iconify red-text left" data-icon="mdi:alert-outline"></i>
           {% blocktrans %}No lessons available{% endblocktrans %}
         </span>
         <p>
diff --git a/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html b/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html
index c394784f0a9bfbb681a33c5f6875206f8d94b42a..e6235a32f382aa9cf80ae3d8ad0ad1704e25e2e9 100644
--- a/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html
+++ b/aleksis/apps/alsijil/templates/alsijil/excuse_type/list.html
@@ -14,7 +14,7 @@
   {% has_perm "alsijil.add_excusetype_rule" user as add_excusetype %}
   {% if add_excusetype %}
     <a class="btn green waves-effect waves-light" href="{% url 'create_excuse_type' %}">
-      <i class="material-icons left">add</i>
+      <i class="material-icons iconify left"data-icon="mdi:plus"></i>
       {% trans "Create excuse type" %}
     </a>
   {% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html b/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html
index 9ff8af6e9c6f3c2e81970e40067a82c772e5c54c..811b90b33381c578469552154092333b2b38624d 100644
--- a/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html
+++ b/aleksis/apps/alsijil/templates/alsijil/excuse_type/warning.html
@@ -1,6 +1,6 @@
 {% load i18n %}
 <figure class="alert warning">
-  <i class="material-icons left">warning</i>
+  <i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>
   {% blocktrans %}
     This function should only be used to define alternatives to the default excuse which also will be counted extra.
     Don't use this to create a default excuse or if you don't divide between different types of excuse.
diff --git a/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html b/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html
index a1a12b38096de60bae34d61425a1da9c688ab9d6..9eeb63b1a81162e6490072ca7184059be7a5193a 100644
--- a/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html
+++ b/aleksis/apps/alsijil/templates/alsijil/extra_mark/list.html
@@ -10,7 +10,7 @@
 
 {% block content %}
   <a class="btn green waves-effect waves-light" href="{% url 'create_extra_mark' %}">
-    <i class="material-icons left">add</i>
+    <i class="material-icons iconify left" data-icon="mdi:plus"></i>
     {% trans "Create extra mark" %}
   </a>
 
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/assign.html b/aleksis/apps/alsijil/templates/alsijil/group_role/assign.html
index a4a5ac137179ea12278d16029c06428221c0ef25..194c45e8871716491635c2b1a9da670c38b8c729 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/assign.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/assign.html
@@ -30,7 +30,7 @@
     {% form form=form %}{% endform %}
 
     <button type="submit" class="btn green waves-effect waves-light">
-      <i class="material-icons left">assignment_ind</i>
+      <i class="material-icons iconify left" data-icon="mdi:clipboard-account-outline"></i>
       {% trans "Assign" %}
     </button>
   </form>
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/assigned_list.html b/aleksis/apps/alsijil/templates/alsijil/group_role/assigned_list.html
index a5533b444615836ccddefed3b45f009ced5b987c..bed7ae1c9a4f061f71ca19dcd5e87e2625ae6f48 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/assigned_list.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/assigned_list.html
@@ -24,7 +24,7 @@
     {% has_perm "alsijil.view_my_groups_rule" user as can_view_group_overview %}
     {% if can_view_group_overview %}
       <a class="btn waves-effect waves-light" href="{% url "my_groups" %}">
-        <i class="material-icons left">arrow_back</i>
+        <i class="material-icons iconify left" data-icon="mdi:arrow-left"></i>
         {% trans "Back to my groups" %}
       </a>
     {% endif %}
@@ -32,7 +32,7 @@
     {% has_perm "alsijil.assign_grouprole_for_group_rule" user object as can_assign_group_role %}
     {% if can_assign_group_role %}
       <a class="btn green waves-effect waves-light" href="{% url "assign_group_role" object.pk %}">
-        <i class="material-icons left">assignment_ind</i>
+        <i class="material-icons iconify left" data-icon="mdi:clipboard-account-outline"></i>
         {% trans "Assign a role to a person" %}
       </a>
     {% endif %}
@@ -79,7 +79,7 @@
             <td>
               <a class="btn waves-effect waves-light dropdown-trigger" href="#"
                  data-target="dropdown-{{ assignment.pk }}-d2">
-                <i class="material-icons left">list</i>
+                <i class="material-icons iconify left" data-icon="mdi:format-list-bulleted"></i>
                 {% trans "Actions" %}
               </a>
               {% include "alsijil/group_role/partials/assignment_options.html" with assignment=assignment back_url=back_url suffix="-d2" %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/chip.html b/aleksis/apps/alsijil/templates/alsijil/group_role/chip.html
index 530ffa05b531acd34bfa7726b374e56ee703298b..41e520302a9d3cac6b7f1d3e3b145c8c7692bde4 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/chip.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/chip.html
@@ -1,7 +1,7 @@
 {# -*- engine:django -*- #}
 
 <div class="chip white-text" style="background-color: {{ role.colour|default:"black" }};">
-  <i class="material-icons left">{{ role.icon|default:"assignment_ind" }}</i>
+  <i class="material-icons iconify left" data-icon="mdi:{{ role.icon|default:"clipboard-account-outline" }}"></i>
   {{ role.name }}
   {% if small %}
     <small>({{ small }})</small>
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/list.html b/aleksis/apps/alsijil/templates/alsijil/group_role/list.html
index 73606d95b0f2cef8b24939dc7ab55a80d0a8721a..3b10aadb2fc1db3d3c1e37fc11a168be19e550eb 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/list.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/list.html
@@ -12,7 +12,7 @@
   {% has_perm "alsijil.add_grouprole_rule" user as add_group_role %}
   {% if add_group_role %}
     <a class="btn green waves-effect waves-light" href="{% url 'create_group_role' %}">
-      <i class="material-icons left">add</i>
+      <i class="material-icons iconify left" data-icon="mdi:plus"></i>
       {% trans "Create group role" %}
     </a>
   {% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assigned_roles.html b/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assigned_roles.html
index fddec1113e80669262402327a7ba3ff23fa45373..f1955e749e67325ee1195fe7831bacf0157c9be3 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assigned_roles.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assigned_roles.html
@@ -8,7 +8,7 @@
           {% if can_assign_group_role %}
             <a class="btn waves-effect waves-light right hide-on-med-and-up"
                href="{% url "assign_group_role" group.pk role.pk %}?next={{ back_url }}">
-              <i class="material-icons center">add</i>
+              <i class="material-icons iconify center" data-icon="mdi:plus"></i>
             </a>
           {% endif %}
 
@@ -21,7 +21,7 @@
           {% if can_assign_group_role %}
             <a class="btn waves-effect waves-light right hide-on-small-only"
                href="{% url "assign_group_role" group.pk role.pk %}?next={{ back_url }}">
-              <i class="material-icons center">add</i>
+              <i class="material-icons iconify center" data-icon="mdi:plus"></i>
             </a>
           {% endif %}
 
@@ -37,7 +37,7 @@
 </div>
 
 <figure class="alert primary">
-  <i class="material-icons left">info</i>
+  <i class="material-icons iconify left" data-icon="information-outline"></i>
   {% blocktrans %}
     You can get some additional actions for each group role assignment if you click on the name of the
     corresponding person.
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assignment_options.html b/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assignment_options.html
index 6c6928934229e4b1f721fa98a7df49683d77d556..3fcd3f57b4aa4cb47702515eaaab5eae1b40190f 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assignment_options.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/partials/assignment_options.html
@@ -10,7 +10,7 @@
   {% if can_edit %}
     <li>
       <a href="{% url "edit_group_role_assignment" assignment.pk %}?next={{ back_url }}">
-        <i class="material-icons left">edit</i> {% trans "Edit" %}
+        <i class="material-icons iconify left" data-icon="mdi:pencil-outline"></i> {% trans "Edit" %}
       </a>
     </li>
   {% endif %}
@@ -18,7 +18,7 @@
   {% if not assignment.date_end and can_stop %}
     <li>
       <a href="#">
-        <i class="material-icons left">stop</i> {% trans "Stop" %}
+        <i class="material-icons iconify left" data-icon="mdi:stop"></i> {% trans "Stop" %}
       </a>
     </li>
   {% endif %}
@@ -26,7 +26,7 @@
   {% if can_delete %}
     <li>
       <a href="{% url "delete_group_role_assignment" assignment.pk %}?next={{ back_url }}" class="red-text">
-        <i class="material-icons left">delete</i> {% trans "Delete" %}
+        <i class="material-icons iconify left" data-icon="mdi:delete-outline"></i> {% trans "Delete" %}
       </a>
     </li>
   {% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/group_role/warning.html b/aleksis/apps/alsijil/templates/alsijil/group_role/warning.html
index 9ff8af6e9c6f3c2e81970e40067a82c772e5c54c..811b90b33381c578469552154092333b2b38624d 100644
--- a/aleksis/apps/alsijil/templates/alsijil/group_role/warning.html
+++ b/aleksis/apps/alsijil/templates/alsijil/group_role/warning.html
@@ -1,6 +1,6 @@
 {% load i18n %}
 <figure class="alert warning">
-  <i class="material-icons left">warning</i>
+  <i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>
   {% blocktrans %}
     This function should only be used to define alternatives to the default excuse which also will be counted extra.
     Don't use this to create a default excuse or if you don't divide between different types of excuse.
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html
index 07c14a649a96892987b984aa315e955df856cbf7..4b768265a510df03c6fab59b40cb4e356f90290a 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/heading.html
@@ -10,14 +10,14 @@
      href="{% url "lesson_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}"
       {% endif %}
   >
-    <i class="material-icons center">navigate_before</i>
+    <i class="material-icons iconify center" data-icon="mdi:chevron-left"></i>
   </a>
   <a class="btn-flat waves-effect waves-light primary-color-text right alsijil-header-nav-button hide-on-med-and-up {% if not next_lesson %}disabled{% endif %}"
       {% if next_lesson %}
      href="{% url "lesson_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}"
       {% endif %}
   >
-    <i class="material-icons center">navigate_next</i>
+    <i class="material-icons iconify center" data-icon="mdi:chevron-right"></i>
   </a>
 
   <span class="alsijil-time-head">
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html
index dcddcfcc13a6437bf1982f9e3ce20930e9aaf774..a12cf71e843ada4d1caeec54a82c8ca1876cb7ec 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/prev_next.html
@@ -5,7 +5,8 @@
     {% if not blocked_because_holidays and with_save %}
       {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
         <button type="submit" class="btn waves-effect waves-light green margin-bottom">
-          <i class="material-icons left">save</i> {% trans "Save" %}
+          <i class="material-icons iconify left" data-icon="mdi:content-save-outline"></i>
+          {% trans "Save" %}
         </button>
       {% endif %}
     {% endif %}
@@ -15,7 +16,7 @@
        href="{% url "lesson_period" prev_lesson.week.year prev_lesson.week.week prev_lesson.id %}"
         {% endif %}
     >
-      <i class="material-icons left">arrow_back</i>
+      <i class="material-icons iconify left" data-icon="mdi:arrow-left"></i>
       {% blocktrans with subject=register_object.get_subject.short_name %}
         Previous {{ subject }} lesson
       {% endblocktrans %}
@@ -26,7 +27,7 @@
        href="{% url "lesson_period" next_lesson.week.year next_lesson.week.week next_lesson.id %}"
         {% endif %}
     >
-      <i class="material-icons right">arrow_forward</i>
+      <i class="material-icons iconify right" data-icon="mdi:arrow-right"></i>
       {% blocktrans with subject=register_object.get_subject.short_name %}
         Next {{ subject }} lesson
       {% endblocktrans %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html
index 3147e1fcf97b9c0665cf90f552eadd40e80247f2..e94fb66d7632272eacbdbc0b09ba868127fc9f84 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/notes.html
@@ -7,7 +7,7 @@
   {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
     <button type="submit"
             class="btn waves-effect waves-light green margin-bottom hundred-percent hide-on-med-and-up">
-      <i class="material-icons left">save</i> {% trans "Save" %}
+      <i class="material-icons iconify left" data-icon="mdi:content-save-outline"></i> {% trans "Save" %}
     </button>
   {% endif %}
 {% endif %}
@@ -105,14 +105,18 @@
                 {% endfor %}
               </p>
             </td>
-            <td><i class="material-icons center">{{ form.absent.value|yesno:"check,clear" }}</i></td>
             <td>
-              <i class="material-icons center">{{ form.tardiness.value|yesno:"check,clear" }}</i>
+              <i class="material-icons iconify center" data-icon="mdi:{{ form.absent.value|yesno:"check,close" }}"></i>
+            </td>
+            <td>
+              <i class="material-icons iconify center" data-icon="mdi:{{ form.tardiness.value|yesno:"check,close" }}"></i>
               <span class="alsijil-tardiness-text">
                 {% if form.tardiness.value %}{{ form.tardiness.value|to_time|time:"i\m" }}{% endif %}
               </span>
             </td>
-            <td><i class="material-icons center">{{ form.excused.value|yesno:"check,clear" }}</i></td>
+            <td>
+              <i class="material-icons iconify center" data-icon="mdi:{{ form.excused.value|yesno:"check,close" }}"></i>
+              </td>
             <td>{% firstof form.instance.excuse_type "–" %}</td>
             <td>
               {% for extra_mark in form.instance.extra_marks.all %}
@@ -133,7 +137,7 @@
   {% if can_edit_lesson_documentation or can_edit_register_object_personalnote %}
     <button type="submit"
             class="btn waves-effect waves-light green margin-bottom hundred-percent hide-on-med-and-up">
-      <i class="material-icons left">save</i> {% trans "Save" %}
+      <i class="material-icons iconify left" data-icon="mdi:content-save-outline"></i> {% trans "Save" %}
     </button>
   {% endif %}
 {% endif %}
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/seating_plan.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/seating_plan.html
index 1dcfbed7d043b1f068e8e8f7f2f74e9028aa8de7..de5e9f44f947ac49a951d30b6de58a02e844f044 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/seating_plan.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson/tabs/seating_plan.html
@@ -10,7 +10,7 @@
       </div>
       {% if seating_plan_parent %}
         <figure class="alert primary">
-          <i class="material-icons left">info</i>
+          <i class="material-icons iconify left" data-icon="information-outline"></i>
           {% blocktrans with child_group=first_group %}
             This seating plan is taken from the parent group of {{ child_group }}.
             If you want, you can take it over for your group and then customize it.
@@ -26,14 +26,14 @@
           {% if can_edit %}
             <a class="btn orange waves-effect waves-light"
                href="{% url "edit_seating_plan" seating_plan.pk %}?next={{ back_url }}#seating-plan">
-              <i class="material-icons left">edit</i>
+              <i class="material-icons iconify left" data-icon="mdi:pencil-outline"></i>
               {% trans "Edit seating plan" %}
             </a>
           {% endif %}
           {% if can_copy and seating_plan_parent %}
             <a class="btn orange waves-effect waves-light"
                href="{% url "copy_seating_plan" seating_plan.pk %}?next={{ back_url }}#seating-plan">
-              <i class="material-icons left">content_copy</i>
+              <i class="material-icons iconify left" data-icon="mdi:content-copy"></i>
               {% trans "Copy plan and edit" %}
             </a>
           {% endif %}
@@ -52,15 +52,15 @@
     <div class="card">
       <div class="card-content">
         <div class="card-title">
-          <i class="material-icons left small orange-text">warning</i>
+          <i class="material-icons iconify left small orange-text" data-icon="mdi:alert-outline"></i>
           {% trans "There is no seating plan for this lesson." %}
         </div>
-        {% has_perm "stoelindeling.add_seatingplan_rule" user first_group as can_add %}
+        {% has_perm "stoelindeling.create_seatingplan_rule" user first_group as can_add %}
         {% if can_add %}
           <div class="row margin-bottom">
             <div class="col s12">
               <a class="btn waves-effect waves-light" href="{% url "create_seating_plan" %}?group={{ first_group.pk }}&subject={{ register_object.get_subject.pk }}&room={{ register_object.get_room.pk }}&next={{ back_url }}#seating-plan">
-                <i class="material-icons left">add</i>
+                <i class="material-icons iconify left" data-icon="mdi:plus"></i>
                 {% blocktrans with group=first_group.name subject=register_object.get_subject.name room=register_object.get_room.name %}
                   Create a new seating plan for {{ group }} ({{ subject }}) in {{ room }}
                 {% endblocktrans %}
@@ -69,12 +69,12 @@
           </div>
         {% endif %}
         {% for parent_group in first_group.parent_groups.all %}
-          {% has_perm "stoelindeling.add_seatingplan_rule" user parent_group as can_add %}
+          {% has_perm "stoelindeling.create_seatingplan_rule" user parent_group as can_add %}
           {% if can_add %}
             <div class="row">
               <div class="col s12">
                 <a class="btn waves-effect waves-light" href="{% url "create_seating_plan" %}?group={{ parent_group.pk }}&subject={{ register_object.get_subject.pk }}&room={{ register_object.get_room.pk }}&next={{ back_url }}#seating-plan">
-                  <i class="material-icons left">add</i>
+                  <i class="material-icons iconify left" data-icon="mdi:plus"></i>
                   {% blocktrans with group=parent_group.name room=register_object.get_room.name %}
                     Create a new seating plan for {{ group }} in {{ room }}
                   {% endblocktrans %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html
index 41c80fd25d208e34f38bbcd9e4137016a0734301..acd8d283d6ecc9fe7ed84234600444e1424a0e49 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status.html
@@ -3,7 +3,7 @@
 {% now_datetime as now_dt %}
 
 {% if has_documentation or register_object.has_documentation %}
-  {% include "alsijil/partials/lesson_status_icon.html" with text=_("Data complete") icon="check_circle" color="green" %}
+  {% include "alsijil/partials/lesson_status_icon.html" with text=_("Data complete") icon="mdi:check-circle-outline" color="green" %}
 {% elif not register_object.period %}
   {% if week %}
     {% period_to_time_start week register_object.raw_period_from_on_day as time_start %}
@@ -14,23 +14,23 @@
   {% endif %}
 
   {% if now_dt > time_end %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="warning" color="red" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="mdi:alert-outline" color="red" %}
   {% elif now_dt > time_start and now_dt < time_end %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="more_horiz" color="orange" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="mdi:dots-horizontal" color="orange" %}
   {% else %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Event") icon="event" color="purple" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Event") icon="mdi:calendar" color="purple" %}
   {% endif %}
 {% else %}
   {% period_to_time_start week register_object.period as time_start %}
   {% period_to_time_end week register_object.period as time_end %}
 
   {% if substitution.cancelled or register_object.get_substitution.cancelled %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Lesson cancelled") icon="cancel" color="red" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Lesson cancelled") icon="mdi:close" color="red" %}
   {% elif now_dt > time_end %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="warning" color="red" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Missing data") icon="mdi:alert-outline" color="red" %}
   {% elif now_dt > time_start and now_dt < time_end %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="more_horiz" color="orange" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Pending") icon="mdi:dots-horizontal" color="orange" %}
   {% elif substitution or register_object.get_substitution %}
-    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Substitution") icon="update" color="orange" %}
+    {% include "alsijil/partials/lesson_status_icon.html" with text=_("Substitution") icon="mdi:update" color="orange" %}
   {% endif %}
 {% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html
index 046b3ffbdacbbb5f18232668363fae195457faa1..2c016c685bb89e8edca9e75408fd11109f655e0b 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/lesson_status_icon.html
@@ -1,14 +1,12 @@
 {% if chip %}
   <span class="{% if chip %}chip{% endif %} {{ color }} white-text {{ css_class }}">
-    <i class="material-icons left">
-      {{ icon }}
-    </i>
+    <i class="material-icons iconify left" data-icon="{{ icon }}"></i>
     {{ text }}
   </span>
 {% else %}
-  <i class="material-icons {{ color }}{% firstof color_suffix "-text" %} tooltipped {{ css_class }}"
+  <i class="material-icons iconify {{ color }}{% firstof color_suffix "-text" %} tooltipped {{ css_class }}"
+     data-icon="{{ icon }}"
      data-position="bottom"
      data-tooltip="{{ text }}" title="{{ text }}">
-    {{ icon }}
   </i>
 {% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html b/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html
index f13e6043935b6fe5b1e91915158cc12d39a8f2e0..e2053816e4a682b5de56596f0cf998e2b4e0a371 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/objects_table.html
@@ -5,7 +5,7 @@
     <form action="" method="get">
       {% form form=filter_form %}{% endform %}
       <button type="submit" class="btn waves-effect waves-light">
-        <i class="material-icons left">refresh</i>
+        <i class="material-icons iconify left" data-icon="mdi:refresh"></i>
         {% trans "Update filters" %}
       </button>
     </form>
@@ -29,7 +29,7 @@
               <div class="col s12 m4">
                 <button type="submit" class="btn waves-effect waves-primary">
                   {% trans "Execute" %}
-                  <i class="material-icons right">send</i>
+                  <i class="material-icons iconify right" data-icon="mdi:send-outline"></i>
                 </button>
               </div>
             </div>
diff --git a/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html b/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html
index efa5bc3a89d72c75fbf5f3d1c9de5426c668270f..bb60dbbd0984d1dab0130ada052cb423288aee2e 100644
--- a/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html
+++ b/aleksis/apps/alsijil/templates/alsijil/partials/persons_with_stats.html
@@ -2,7 +2,7 @@
 
 {% if not persons %}
   <figure class="alert primary">
-    <i class="material-icons left">warning</i>
+    <i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>
     {% blocktrans %}No students available.{% endblocktrans %}
   </figure>
 {% else %}
@@ -126,7 +126,7 @@
 
       <td>
         <a class="btn primary waves-effect waves-light" href="{% url "overview_person" person.pk %}">
-          <i class="material-icons left">insert_chart</i>
+          <i class="material-icons iconify left" data-icon="mdi:chart-box-outline"></i>
           <span class="hide-on-med-and-down"> {% trans "Show more details" %}</span>
           <span class="hide-on-large-only">{% trans "Details" %}</span>
         </a>
@@ -134,7 +134,7 @@
         {% has_perm "alsijil.register_absence_rule" user person as can_register_absence %}
         {% if can_register_absence %}
           <a class="btn primary-color waves-effect waves-light" href="{% url "register_absence" person.pk %}">
-            <i class="material-icons left">rate_review</i>
+            <i class="material-icons iconify left" data-icon="mdi:message-draw"></i>
             {% trans "Register absence" %}
           </a>
         {% endif %}
diff --git a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
index 258ed824beb7222f6bd1c764e072dbafaedf75ee..c699287a00987ad99c1fd0c2d4617827670fae2f 100644
--- a/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
+++ b/aleksis/apps/alsijil/templates/alsijil/print/full_register.html
@@ -17,8 +17,8 @@
     <h5>{{ school_term }}</h5>
     <p>({{ school_term.date_start }}–{{ school_term.date_end }})</p>
     {% 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">
+    <img src="{% firstof SITE_PREFERENCES.theme__logo.url aleksis_banner %}"
+         alt="{{ SITE_PREFERENCES.general__title }} – Logo" class="max-size-600 center">
     <h4 id="group-desc">
       {{ group.name }}
     </h4>
@@ -256,29 +256,29 @@
             <img src="{% static 'img/fallback.png' %}" alt="{{ person.first_name }} {{ person.last_name }}"/>
           {% endif %}
         </td>
-        <td><i class="material-icons">person</i></td>
+        <td><i class="material-icons iconify" data-icon="mdi:account-outline"></i></td>
         <td colspan="2">{{ person.first_name }} {{ person.additional_name }} {{ person.last_name }}</td>
       </tr>
       <tr>
-        <td><i class="material-icons">face</i></td>
+        <td><i class="material-icons iconify" data-icon="mdi:human-non-binary"></i></td>
         <td colspan="2">{{ person.get_sex_display }}</td>
       </tr>
       <tr>
-        <td><i class="material-icons">home</i></td>
+        <td><i class="material-icons iconify" data-icon="mdi:map-marker-outline"></i></td>
         <td>{{ person.street }} {{ person.housenumber }}</td>
         <td>{{ person.postal_code }} {{ person.place }}</td>
       </tr>
       <tr>
-        <td><i class="material-icons">phone</i></td>
+        <td><i class="material-icons iconify" data-icon="mdi:phone-outline"></i></td>
         <td>{{ person.phone_number }}</td>
         <td>{{ person.mobile_number }}</td>
       </tr>
       <tr>
-        <td><i class="material-icons">email</i></td>
+        <td><i class="material-icons iconify" data-icon="mdi:email-outline"></i></td>
         <td colspan="2">{{ person.email }}</td>
       </tr>
       <tr>
-        <td><i class="material-icons">cake</i></td>
+        <td><i class="material-icons iconify" data-icon="mdi:cake"></i></td>
         <td colspan="2">{{ person.date_of_birth|date }}</td>
       </tr>
     </table>
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index 2f6a2b14a5e33ef953382cb99e68d21cb501073d..eabce1ff687ec433c943d5954f03ece20bb01877 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -1,6 +1,6 @@
 from contextlib import nullcontext
 from copy import deepcopy
-from datetime import date, datetime, timedelta
+from datetime import datetime, timedelta
 from typing import Any, Dict, Optional
 
 from django.apps import apps
@@ -37,10 +37,10 @@ from aleksis.core.mixins import (
     AdvancedEditView,
     SuccessNextMixin,
 )
-from aleksis.core.models import Group, Person, SchoolTerm
+from aleksis.core.models import Group, PDFFile, Person, SchoolTerm
 from aleksis.core.util import messages
+from aleksis.core.util.celery_progress import render_progress_page
 from aleksis.core.util.core_helpers import get_site_preferences, objectgetter_optional
-from aleksis.core.util.pdf import render_pdf
 from aleksis.core.util.predicates import check_global_permission
 
 from .filters import PersonalNoteFilter
@@ -58,14 +58,7 @@ from .forms import (
     RegisterObjectActionForm,
     SelectForm,
 )
-from .models import (
-    ExcuseType,
-    ExtraMark,
-    GroupRole,
-    GroupRoleAssignment,
-    LessonDocumentation,
-    PersonalNote,
-)
+from .models import ExcuseType, ExtraMark, GroupRole, GroupRoleAssignment, PersonalNote
 from .tables import (
     ExcuseTypeTable,
     ExtraMarkTable,
@@ -74,6 +67,7 @@ from .tables import (
     RegisterObjectSelectTable,
     RegisterObjectTable,
 )
+from .tasks import generate_full_register_printout
 from .util.alsijil_helpers import (
     annotate_documentations,
     generate_list_of_all_register_objects,
@@ -236,13 +230,14 @@ def register_object(
         if not request.user.has_perm(
             "alsijil.view_register_object_personalnote_rule", register_object
         ):
-            persons = Person.objects.filter(pk=request.user.person.pk)
+            persons = Person.objects.filter(
+                Q(pk=request.user.person.pk)
+                | Q(person__member_of__in=request.user.person.owner_of.all())
+            ).distinct()
         else:
             persons = Person.objects.all()
 
-        persons_qs = register_object.get_personal_notes(persons, wanted_week).filter(
-            person__member_of__in=request.user.person.owner_of.all()
-        )
+        persons_qs = register_object.get_personal_notes(persons, wanted_week).distinct()
 
         # Annotate group roles
         if show_group_roles:
@@ -476,12 +471,16 @@ def week_view(
         if not request.user.has_perm("alsijil.view_week_personalnote_rule", instance):
             persons_qs = persons_qs.filter(pk=request.user.person.pk)
         elif group:
-            persons_qs = persons_qs.filter(member_of=group).filter(
-                member_of__in=request.user.person.owner_of.all()
+            persons_qs = (
+                persons_qs.filter(member_of=group)
+                .filter(member_of__in=request.user.person.owner_of.all())
+                .distinct()
             )
         else:
-            persons_qs = persons_qs.filter(member_of__in=groups).filter(
-                member_of__in=request.user.person.owner_of.all()
+            persons_qs = (
+                persons_qs.filter(member_of__in=groups)
+                .filter(member_of__in=request.user.person.owner_of.all())
+                .distinct()
             )
 
         # Prefetch object permissions for persons and groups the persons are members of
@@ -637,138 +636,36 @@ def week_view(
     "alsijil.view_full_register_rule", fn=objectgetter_optional(Group, None, False)
 )
 def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
-    context = {}
-
     group = get_object_or_404(Group, pk=id_)
-    groups_q = (
-        Q(lesson_period__lesson__groups=group)
-        | Q(lesson_period__lesson__groups__parent_groups=group)
-        | Q(extra_lesson__groups=group)
-        | Q(extra_lesson__groups__parent_groups=group)
-        | Q(event__groups=group)
-        | Q(event__groups__parent_groups=group)
-    )
-    personal_notes = (
-        PersonalNote.objects.prefetch_related(
-            "lesson_period__substitutions", "lesson_period__lesson__teachers"
-        )
-        .not_empty()
-        .filter(groups_q)
-        .filter(groups_of_person=group)
-    )
-    documentations = LessonDocumentation.objects.not_empty().filter(groups_q)
 
-    sorted_documentations = {"extra_lesson": {}, "event": {}, "lesson_period": {}}
-    sorted_personal_notes = {"extra_lesson": {}, "event": {}, "lesson_period": {}, "person": {}}
-    for documentation in documentations:
-        key = documentation.register_object.label_
-        sorted_documentations[key][documentation.register_object_key] = documentation
+    file_object = PDFFile.objects.create()
 
-    for note in personal_notes:
-        key = note.register_object.label_
-        sorted_personal_notes[key].setdefault(note.register_object_key, [])
-        sorted_personal_notes[key][note.register_object_key].append(note)
-        sorted_personal_notes["person"].setdefault(note.person.pk, [])
-        sorted_personal_notes["person"][note.person.pk].append(note)
-
-    # Get all lesson periods for the selected group
-    lesson_periods = LessonPeriod.objects.filter_group(group).distinct()
-    events = Event.objects.filter_group(group).distinct()
-    extra_lessons = ExtraLesson.objects.filter_group(group).distinct()
-    weeks = CalendarWeek.weeks_within(group.school_term.date_start, group.school_term.date_end)
-
-    register_objects_by_day = {}
-    for extra_lesson in extra_lessons:
-        day = extra_lesson.date
-        register_objects_by_day.setdefault(day, []).append(
-            (
-                extra_lesson,
-                sorted_documentations["extra_lesson"].get(extra_lesson.pk),
-                sorted_personal_notes["extra_lesson"].get(extra_lesson.pk, []),
-                None,
-            )
-        )
+    redirect_url = reverse("redirect_to_pdf_file", args=[file_object.pk])
 
-    for event in events:
-        day_number = (event.date_end - event.date_start).days + 1
-        for i in range(day_number):
-            day = event.date_start + timedelta(days=i)
-            event_copy = deepcopy(event)
-            event_copy.annotate_day(day)
-            register_objects_by_day.setdefault(day, []).append(
-                (
-                    event_copy,
-                    sorted_documentations["event"].get(event.pk),
-                    sorted_personal_notes["event"].get(event.pk, []),
-                    None,
-                )
-            )
+    result = generate_full_register_printout.delay(group.pk, file_object.pk)
 
-    weeks = CalendarWeek.weeks_within(
-        group.school_term.date_start,
-        group.school_term.date_end,
+    back_url = request.GET.get("back", "")
+    back_url_is_safe = url_has_allowed_host_and_scheme(
+        url=back_url,
+        allowed_hosts={request.get_host()},
+        require_https=request.is_secure(),
     )
-
-    for lesson_period in lesson_periods:
-        for week in weeks:
-            day = week[lesson_period.period.weekday]
-
-            if (
-                lesson_period.lesson.validity.date_start
-                <= day
-                <= lesson_period.lesson.validity.date_end
-            ):
-                filtered_documentation = sorted_documentations["lesson_period"].get(
-                    f"{lesson_period.pk}_{week.week}_{week.year}"
-                )
-                filtered_personal_notes = sorted_personal_notes["lesson_period"].get(
-                    f"{lesson_period.pk}_{week.week}_{week.year}", []
-                )
-
-                substitution = lesson_period.get_substitution(week)
-
-                register_objects_by_day.setdefault(day, []).append(
-                    (lesson_period, filtered_documentation, filtered_personal_notes, substitution)
-                )
-
-    persons = group.members.prefetch_related(None).select_related(None)
-    persons = group.generate_person_list_with_class_register_statistics(persons)
-
-    prefetched_persons = []
-    for person in persons:
-        person.filtered_notes = sorted_personal_notes["person"].get(person.pk, [])
-        prefetched_persons.append(person)
-
-    context["school_term"] = group.school_term
-    context["persons"] = prefetched_persons
-    context["excuse_types"] = ExcuseType.objects.filter(count_as_absent=True)
-    context["excuse_types_not_absent"] = ExcuseType.objects.filter(count_as_absent=False)
-    context["extra_marks"] = ExtraMark.objects.all()
-    context["group"] = group
-    context["weeks"] = weeks
-    context["register_objects_by_day"] = register_objects_by_day
-    context["register_objects"] = list(lesson_periods) + list(events) + list(extra_lessons)
-    context["today"] = date.today()
-    context["lessons"] = (
-        group.lessons.all()
-        .select_related(None)
-        .prefetch_related(None)
-        .select_related("validity", "subject")
-        .prefetch_related("teachers", "lesson_periods")
+    if not back_url_is_safe:
+        back_url = reverse("my_groups")
+
+    return render_progress_page(
+        request,
+        result,
+        title=_("Generate full register printout for {}").format(group),
+        progress_title=_("Generate full register printout …"),
+        success_message=_("The printout has been generated successfully."),
+        error_message=_("There was a problem while generating the printout."),
+        redirect_on_success_url=redirect_url,
+        back_url=back_url,
+        button_title=_("Download PDF"),
+        button_url=redirect_url,
+        button_icon="picture_as_pdf",
     )
-    context["child_groups"] = (
-        group.child_groups.all()
-        .select_related(None)
-        .prefetch_related(None)
-        .prefetch_related(
-            "lessons",
-            "lessons__validity",
-            "lessons__subject",
-            "lessons__teachers",
-            "lessons__lesson_periods",
-        )
-    )
-    return render_pdf(request, "alsijil/print/full_register.html", context)
 
 
 @permission_required("alsijil.view_my_students_rule")
@@ -797,7 +694,7 @@ def my_students(request: HttpRequest) -> HttpResponse:
                 "primary_group__owners",
                 Prefetch("member_of", queryset=relevant_groups, to_attr="member_of_prefetched"),
             )
-        ).filter(member_of__in=request.user.person.owner_of.all())
+        ).distinct()
         persons_for_group = []
         for person in persons:
             person.set_object_permission_checker(checker)
@@ -830,10 +727,10 @@ class StudentsList(PermissionRequiredMixin, DetailView):
     def get_context_data(self, **kwargs):
         context = super().get_context_data(**kwargs)
         context["group"] = self.object
-        context[
-            "persons"
-        ] = self.object.generate_person_list_with_class_register_statistics().filter(
-            member_of__in=self.request.user.person.owner_of.all()
+        context["persons"] = (
+            self.object.generate_person_list_with_class_register_statistics()
+            .filter(member_of__in=self.request.user.person.owner_of.all())
+            .distinct()
         )
         context["extra_marks"] = ExtraMark.objects.all()
         context["excuse_types"] = ExcuseType.objects.filter(count_as_absent=True)
diff --git a/docs/conf.py b/docs/conf.py
index 1bb1712a1d993fe8523eed1d34291b7865c37aa6..59ca213449c1f46b86ef5340aaac7c21447cb4e8 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -31,7 +31,7 @@ author = "The AlekSIS Team"
 # The short X.Y version
 version = "2.1"
 # The full version, including alpha/beta/rc tags
-release = "2.1.1.dev0"
+release = "2.2.dev0"
 
 
 # -- General configuration ---------------------------------------------------
diff --git a/pyproject.toml b/pyproject.toml
index 1381bc6d33e3ef546a6555d1e8695cae267f33d9..a3a4aea8d9b8f3cfd286cab366900bcce9ee5b9c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "AlekSIS-App-Alsijil"
-version = "2.1.1.dev0"
+version = "2.2.dev0"
 packages = [
     { include = "aleksis" }
 ]
@@ -48,7 +48,7 @@ secondary = true
 
 [tool.poetry.dependencies]
 python = "^3.9"
-aleksis-core = "^2.7"
+aleksis-core = "^2.12"
 aleksis-app-chronos = "^2.2"
 aleksis-app-stoelindeling = { version = "^1.0", optional = true }
 
diff --git a/tox.ini b/tox.ini
index 749e0606f4f02fcbd1649627219b15850cbc0a90..78e09567e193b72a299dfb3f776499420ecc04ec 100644
--- a/tox.ini
+++ b/tox.ini
@@ -10,7 +10,7 @@ skip_install = true
 envdir = {toxworkdir}/globalenv
 commands_pre =
      poetry install
-     poetry run aleksis-admin yarn install
+     poetry run aleksis-admin webpack_bundle
      poetry run aleksis-admin collectstatic --no-input
 commands =
     poetry run pytest --cov=. {posargs} aleksis/