diff --git a/aleksis/apps/alsijil/model_extensions.py b/aleksis/apps/alsijil/model_extensions.py
index b503bbf8f552e31977e56e64709a019cff265cfc..c27bfc88ade60a7e85a33861be0f852633b866ee 100644
--- a/aleksis/apps/alsijil/model_extensions.py
+++ b/aleksis/apps/alsijil/model_extensions.py
@@ -1,6 +1,7 @@
 from datetime import date
 
-from django.db.models import Exists, F, OuterRef
+from django.db.models import Exists, F, OuterRef, QuerySet
+from django.utils.translation import ugettext as _
 
 from calendarweek import CalendarWeek
 
@@ -57,7 +58,7 @@ def mark_absent(
 
 
 @LessonPeriod.method
-def get_personal_notes(self, wanted_week: CalendarWeek):
+def get_personal_notes(self, persons: QuerySet, wanted_week: CalendarWeek):
     """ Get all personal notes for that lesson in a specified week.
     
     Returns all linked `PersonalNote` objects, filtered by the given weeek,
@@ -71,7 +72,7 @@ def get_personal_notes(self, wanted_week: CalendarWeek):
     """
 
     # Find all persons in the associated groups that do not yet have a personal note for this lesson
-    missing_persons = Person.objects.annotate(
+    missing_persons = persons.annotate(
         no_personal_notes=~Exists(
             PersonalNote.objects.filter(
                 week=wanted_week.week, lesson_period=self, person__pk=OuterRef("pk")
@@ -94,3 +95,13 @@ def get_personal_notes(self, wanted_week: CalendarWeek):
     return PersonalNote.objects.select_related("person").filter(
         lesson_period=self, week=wanted_week.week
     )
+
+# Dynamically add extra permissions to Group and Person models in core, requires migration afterwards
+Group.add_permission("view_week_class_register_group", _("Can view week overview of group class register"))
+Group.add_permission("view_personalnote_group", _("Can view all personal notes of a group"))
+Group.add_permission("edit_personalnote_group", _("Can edit all personal notes of a group"))
+Group.add_permission("view_lessondocumentation_group", _("Can view all lesson documentation of a group"))
+Group.add_permission("edit_lessondocumentation_group", _("Can edit all lesson documentation of a group"))
+Group.add_permission("view_full_register_group", _("Can view full register of a group"))
+Group.add_permission("register_absence_group", _("Can register a absence for all members of a group"))
+Person.add_permission("register_absence_person", _("Can register a absence for a person"))
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index c6c6baf848bbb3a8cd497e67c38801a9cecdc9ad..4c8cf021e02dcc194650927c8f7ee68e109ac138 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -5,31 +5,96 @@ from aleksis.core.util.predicates import (
     has_global_perm,
     has_object_perm,
     has_person,
+    is_current_person,
+)
+
+from .util.predicates import (
+    is_lesson_teacher,
+    is_lesson_participant,
+    is_lesson_parent_group_owner,
+    has_lesson_group_object_perm,
+    is_group_member,
+    is_group_owner,
+    has_person_group_object_perm,
+    is_person_group_owner,
 )
 
-from .util.predicates import has_lesson_perm, has_week_perm
 
 # View lesson
 view_lesson_predicate = has_person & (
-    has_global_perm("chronos.view_lesson_period") | has_lesson_perm("chronos.view_lesson_period")
+    has_global_perm("alsijil.view_lesson") | is_lesson_teacher | is_lesson_participant | is_lesson_parent_group_owner | has_lesson_group_object_perm("alsijil.view_lesson")
 )
 add_perm("alsijil.view_lesson", view_lesson_predicate)
 
+# View lesson personal notes
+view_lesson_personal_notes_predicate = has_person & (
+    has_global_perm("alsijil.view_personalnote") |
+    has_lesson_group_object_perm("core.view_personalnote_group") |
+    is_lesson_teacher |
+    is_lesson_parent_group_owner
+)
+add_perm("alsijil.view_lesson_personalnote", view_lesson_personal_notes_predicate)
+
+# Edit lesson personal notes
+edit_lesson_personal_notes_predicate = has_person & (
+    has_global_perm("alsijil.change_personalnote") |
+    has_lesson_group_object_perm("core.edit_personalnote_group") |
+    is_lesson_teacher
+)
+add_perm("alsijil.edit_personalnote", edit_lesson_personal_notes_predicate)
+
+# View lesson documentation
+view_lesson_documentation_predicate = has_person & (
+    has_global_perm("alsijil.view_lessondocumentation") |
+    has_lesson_group_object_perm("core.view_lessondocumentation_group") |
+    is_lesson_teacher |
+    is_lesson_parent_group_owner |
+    is_lesson_participant
+)
+add_perm("alsijil.view_lessondocumentation", view_lesson_documentation_predicate)
+
+# Edit lesson documentation
+edit_lesson_documentation_predicate = has_person & (
+    has_global_perm("alsijil.change_lessondocumentation") |
+    has_lesson_group_object_perm("core.edit_lessondocumentation_group") |
+    is_lesson_teacher
+)
+add_perm("alsijil.edit_lessondocumentation", edit_lesson_documentation_predicate)
+
 # View week overview
 view_week_predicate = has_person & (
-    has_global_perm("alsijil.view_week") | has_week_perm("alsijil")
+    has_global_perm("alsijil.view_week") | has_object_perm("core.view_week_class_register_group") | is_group_member | is_group_owner | is_current_person
 )
 add_perm("alsijil.view_week", view_week_predicate)
 
+# View week personal notes
+view_week_personal_notes_predicate = has_person & (
+    has_global_perm("alsijil.view_personalnote") |
+    has_object_perm("alsijil.view_personalnote") |
+    is_group_owner
+)
+add_perm("alsijil.view_week_personalnote", view_week_personal_notes_predicate)
+
 # Register absence
 register_absence_predicate = has_person & (
-    has_global_perm("alsijil.register_absence")
+    has_global_perm("alsijil.register_absence") |
+    has_person_group_object_perm("core.register_absence_group") |
+    has_global_perm("core.register_absence_person") |
+    is_person_group_owner
 )
 add_perm("alsijil.register_absence", register_absence_predicate)
 
-# List all personal note filters
-list_personal_note_filters_predicate = has_person & has_global_perm("alsijil.list_personal_note_filters")
-add_perm("alsijil.list_personal_note_filters", list_personal_note_filters_predicate)
+# View full register for group
+view_full_register_predicate = has_person & (
+    has_global_perm("alsijil.view_full_register") |
+    has_object_perm("core.view_full_register_group") |
+    is_group_owner
+)
+add_perm("alsijil.view_full_register", view_full_register_predicate)
+
+# View all personal note filters
+list_personal_note_filters_predicate = has_person & has_global_perm("alsijil.view_personal_note_filter")
+add_perm("alsijil.view_personal_note_filters", list_personal_note_filters_predicate)
 
 # Edit personal note filter
 edit_personal_note_filter_predicate = has_person & (
diff --git a/aleksis/apps/alsijil/templates/alsijil/lesson.html b/aleksis/apps/alsijil/templates/alsijil/lesson.html
index 82f85bf751b6960e1f20a35b3b3b9402eb78d54b..3b17254adf3b594eac5d4a618b9d4f2be259e30a 100644
--- a/aleksis/apps/alsijil/templates/alsijil/lesson.html
+++ b/aleksis/apps/alsijil/templates/alsijil/lesson.html
@@ -1,6 +1,6 @@
 {# -*- engine:django -*- #}
 {% extends "core/base.html" %}
-{% load material_form i18n static %}
+{% load material_form i18n static rules %}
 
 {% block browser_title %}{% blocktrans %}Lesson{% endblocktrans %}{% endblock %}
 
@@ -34,9 +34,33 @@
             {% blocktrans %}Lesson documentation{% endblocktrans %}
           </div>
           {% csrf_token %}
-          {% form form=lesson_documentation_form %}{% endform %}
+          {% has_perm "alsijil.view_lessondocumentation" user lesson_period as can_view_lesson_documentation %}
+          {% has_perm "alsijil.edit_lessondocumentation" user lesson_period as can_edit_lesson_documentation %}
+          {% if can_edit_lesson_documentation %}
+            {% form form=lesson_documentation_form %}{% endform %}
+          {% elif can_view_lesson_documentation %}
+            <table>
+              <tr>
+                <th>
+                  {% trans "Lesson topic" %}
+                </th>
+                <td>
+                  {{ lesson_documentation.topic }}
+                </td>
+              </tr>
+              <tr>
+                <th>
+                  {% trans "Homework" %}
+                </th>
+                <td>
+                  {{ lesson_documentation.homework }}
+                </td>
+              </tr>
+            </table>
+          {% endif %}
         </div>
       </div>
+      {% if can_view_lesson_documentation %}
       <div class="col s4">
         <div class="card dark-text">
           <span class="card-title">
@@ -45,12 +69,14 @@
           {% include 'core/crud_events_ul.html' with class_ul='list-group list-group-flush' class_li='list-group-item d-flex justify-content-between align-items-center' obj=lesson_documentation %}
         </div>
       </div>
+      {% endif %}
     </div>
 
     <div class="card dark-text">
       <span class="card-title">
         {% blocktrans %}Personal notes{% endblocktrans %}
       </span>
+      {% has_perm "alsijil.edit_personalnote" user lesson_period as can_edit_personalnote %}
       {{ personal_note_formset.management_form }}
 
       <table class="striped responsive-table">
@@ -62,17 +88,29 @@
           <th>{% blocktrans %}Remarks{% endblocktrans %}</th>
         </tr>
         {% for form in personal_note_formset %}
-          {{ form.id }}
-          <tr>
-            <td>{{ form.person_name }}</td>
-            <td>{{ form.absent }}</td>
-            <td>{{ form.late }}</td>
-            <td>{{ form.excused }}</td>
-            <td>{{ form.remarks }}</td>
-          </tr>
+          {% if can_edit_personalnote %}
+            {{ form.id }}
+            <tr>
+              <td>{{ form.person_name }}</td>
+              <td>{{ form.absent }}</td>
+              <td>{{ form.late }}</td>
+              <td>{{ form.excused }}</td>
+              <td>{{ form.remarks }}</td>
+            </tr>
+          {% else %}
+            <tr>
+              <td>{{ form.person_name.value }}</td>
+              <td>{{ form.absent.value }}</td>
+              <td>{{ form.late.value }}</td>
+              <td>{{ form.excused.value }}</td>
+              <td>{{ form.remarks.value }}</td>
+            </tr>
+          {% endif %}
         {% endfor %}
       </table>
     </div>
-    {% include "core/save_button.html" %}
+    {% if can_edit_lesson_documentation or can_edit_personalnote %}
+      {% include "core/save_button.html" %}
+    {% endif %}
   </form>
 {% endblock %}
diff --git a/aleksis/apps/alsijil/util/alsijil_helpers.py b/aleksis/apps/alsijil/util/alsijil_helpers.py
index ec27bcb8b6edb0d2290ae5ef66bc4a36bd9b42c2..f1c1f4a3fb4e96fa239793b11ec9b00efd05a499 100644
--- a/aleksis/apps/alsijil/util/alsijil_helpers.py
+++ b/aleksis/apps/alsijil/util/alsijil_helpers.py
@@ -20,54 +20,24 @@ def get_lesson_period_by_pk(
 ):
     if period_id:
         lesson_period = LessonPeriod.objects.get(pk=period_id)
-        wanted_week = CalendarWeek(year=year, week=week)
     elif hasattr(request, "user") and hasattr(request.user, "person"):
         if request.user.person.lessons_as_teacher.exists():
             lesson_period = LessonPeriod.objects.at_time().filter_teacher(request.user.person).first()
         else:
             lesson_period = LessonPeriod.objects.at_time().filter_participant(request.user.person).first()
-        wanted_week = CalendarWeek()
     else:
-        lesson_period = wanted_week = None
-    return lesson_period, wanted_week
+        lesson_period = None
+    return lesson_period
 
 
-def get_lesson_periods_by_pk(
+def get_instance_by_pk(
     request: HttpRequest,
     year: Optional[int] = None,
     week: Optional[int] = None,
     type_: Optional[str] = None,
     id_: Optional[int] = None,
 ):
-    if year and week:
-        wanted_week = CalendarWeek(year=year, week=week)
-    else:
-        wanted_week = CalendarWeek()
-
-    lesson_periods = LessonPeriod.objects.annotate(
-        has_documentation=Exists(
-            LessonDocumentation.objects.filter(
-                ~Q(topic__exact=""), lesson_period=OuterRef("pk"), week=wanted_week.week
-            )
-        )
-    ).in_week(wanted_week)
-
     if type_ and id_:
-        instance = get_el_by_pk(request, type_, id_)
-
-        if isinstance(instance, HttpResponseNotFound):
-            return HttpResponseNotFound()
-
-        type_ = TimetableType.from_string(type_)
-
-        lesson_periods = lesson_periods.filter_from_type(type_, instance)
+        return get_el_by_pk(request, type_, id_)
     elif hasattr(request, "user") and hasattr(request.user, "person"):
-        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
-    return lesson_periods, wanted_week, type_, instance
\ No newline at end of file
+        return request.user.person
\ No newline at end of file
diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py
index 94c69e0fe72e3bbd775dc7557285c24fc45a54e2..80faf95f8ddbd3867c024a2e4a3b22d20f4dc2bd 100644
--- a/aleksis/apps/alsijil/util/predicates.py
+++ b/aleksis/apps/alsijil/util/predicates.py
@@ -1,33 +1,76 @@
+from typing import Union
+
 from django.contrib.auth.models import User
 
 from rules import predicate
 
+from aleksis.apps.chronos.models import LessonPeriod
 from aleksis.core.models import Group, Person
 from aleksis.core.util.predicates import check_object_permission
 
 
-def has_lesson_perm(perm: str):
-    """Build predicate which checks whether the user is allowed to access the requested lesson notes."""
-    name = f"has_lesson_perm:{perm}"
+@predicate
+def is_lesson_teacher(user: User, obj: LessonPeriod) -> bool:
+    """Predicate which checks whether the person linked to the user is a teacher in the lesson linked to the given LessonPeriod."""
+    return user.person in obj.lesson.teachers
 
-    @predicate(name)
-    def fn(user: User, obj: tuple) -> bool:
-        if (user.person in obj[0].lesson.teachers) or (set(user.person.member_of).intersection(set(obj[0].lesson.groups))):
+@predicate
+def is_lesson_participant(user: User, obj: LessonPeriod) -> bool:
+    """Predicate which checks whether the person linked to the user is a member in the groups linked to the given LessonPeriod."""
+    return obj.lesson.groups.filter(members=user.person).exists()
+
+@predicate
+def is_lesson_parent_group_owner(user: User, obj: LessonPeriod) -> bool:
+    """Predicate which checks whether the person linked to the user is the owner of any parent groups of any groups of the given LessonPeriods lesson."""
+    return obj.lesson.groups.filter(parent_groups__owners=user.person).exists()
+
+@predicate
+def is_group_owner(user: User, obj: Union[Group, Person]) -> bool:
+    """Predicate which checks whether the person linked to the user is the owner of the given group."""
+    if isinstance(obj, Group):
+        if obj.owners.filter(pk=user.person.pk).exists():
             return True
-        return check_object_permission(user, perm, obj)
 
-    return fn
+    return False
 
+@predicate
+def is_person_group_owner(user: User, obj: Person) -> bool:
+    """Predicate which checks whether the person linked to the user is the owner of any group of the given person."""
+    return obj.filter(member_of__owners=user.person).exists()
 
 @predicate
-def has_week_perm(perm: str):
-    """Build predicate which checks whether the user is allowed to access the week overview."""
-    name = f"has_week_perm:{perm}"
+def has_person_group_object_perm(perm: str):
+    """Predicate which checks whether a user has a permission on any group of a person."""
+    name = f"has_person_group_object_perm:{perm}"
 
     @predicate(name)
-    def fn(user: User, obj: tuple) -> bool:
-        if (user.person in obj[0].lesson.teachers) or (set(user.person.member_of).intersection(set(obj[0].lesson.groups))):
+    def fn(user: User, obj: Person) -> bool:
+        for group in obj.member_of.all():
+            if check_object_permission(user, perm, group):
+                return True
+        return False
+
+    return fn
+
+@predicate
+def is_group_member(user: User, obj: Union[Group, Person]) -> bool:
+    """Predicate which checks whether the person linked to the user is a member of the given group."""
+    if isinstance(obj, Group):
+        if obj.members.filter(pk=user.person.pk).exists():
             return True
-        return check_object_permission(user, perm, obj)
+
+    return False
+
+
+def has_lesson_group_object_perm(perm: str):
+    """Build predicate which checks whether a user has a permission on any group of a LessonPeriod."""
+    name = f"has_lesson_group_object_perm:{perm}"
+
+    @predicate(name)
+    def fn(user: User, obj: LessonPeriod) -> bool:
+        for group in obj.lesson.groups.all():
+            if check_object_permission(user, perm, group):
+                return True
+        return False
 
     return fn
diff --git a/aleksis/apps/alsijil/views.py b/aleksis/apps/alsijil/views.py
index da8d9764279f5e42d64ce7e08f718438034e7a24..f9e8296bcec246e4cf897f2dd6f2488d81734d27 100644
--- a/aleksis/apps/alsijil/views.py
+++ b/aleksis/apps/alsijil/views.py
@@ -15,7 +15,7 @@ from django_tables2 import RequestConfig
 from rules.contrib.views import permission_required
 
 from aleksis.apps.chronos.models import LessonPeriod
-from aleksis.core.models import Group, Person, SchoolYear
+from aleksis.core.models import Group, Person
 from aleksis.core.util import messages
 from aleksis.core.util.core_helpers import objectgetter_optional
 from .forms import (
@@ -27,7 +27,7 @@ from .forms import (
 )
 from .models import LessonDocumentation, PersonalNoteFilter
 from .tables import PersonalNoteFilterTable
-from .util.alsijil_helpers import get_lesson_period_by_pk, get_lesson_periods_by_pk
+from .util.alsijil_helpers import get_lesson_period_by_pk, get_instance_by_pk
 
 
 @permission_required("alsijil.view_lesson", fn=get_lesson_period_by_pk)
@@ -39,7 +39,14 @@ def lesson(
 ) -> HttpResponse:
     context = {}
 
-    lesson_period, wanted_week = get_lesson_period_by_pk(request, year, week, period_id)
+    lesson_period = get_lesson_period_by_pk(request, year, week, period_id)
+
+    if period_id:
+        wanted_week = CalendarWeek(year=year, week=week)
+    elif hasattr(request, "user") and hasattr(request.user, "person"):
+        wanted_week = CalendarWeek()
+    else:
+        wanted_week = None
 
     if not (year and week and period_id):
         if lesson_period:
@@ -77,16 +84,19 @@ def lesson(
     )
 
     # Create a formset that holds all personal notes for all persons in this lesson
-    persons_qs = lesson_period.get_personal_notes(wanted_week)
+    persons = Person.objects
+    if not request.user.has_perm("alsijil.view_lesson_personalnote", lesson_period):
+        persons = persons.filter(pk=request.user.pk)
+    persons_qs = lesson_period.get_personal_notes(persons, wanted_week)
     personal_note_formset = PersonalNoteFormSet(
         request.POST or None, queryset=persons_qs, prefix="personal_notes"
     )
 
     if request.method == "POST":
-        if lesson_documentation_form.is_valid():
+        if lesson_documentation_form.is_valid() and request.user.has_perm("alsijil.edit_lessondocumentation", lesson_period):
             lesson_documentation_form.save()
 
-        if personal_note_formset.is_valid():
+        if personal_note_formset.is_valid() and request.user.has_perm("alsijil.edit_personalnote", lesson_period):
             instances = personal_note_formset.save()
 
             # Iterate over personal notes and carry changed absences to following lessons
@@ -105,13 +115,45 @@ def lesson(
     return render(request, "alsijil/lesson.html", context)
 
 
-@permission_required("alsijil.view_week", fn=get_lesson_periods_by_pk)
+@permission_required("alsijil.view_week", fn=get_instance_by_pk)
 def week_view(
     request: HttpRequest, year: Optional[int] = None, week: Optional[int] = None, type_: Optional[str] = None, id_: Optional[int] = None
 ) -> HttpResponse:
     context = {}
 
-    lesson_periods, wanted_week, type_, instance = get_lesson_periods_by_pk(request, year, week, type_, id_)
+    instance = get_instance_by_pk(request, year, week, type_, id_)
+
+    lesson_periods = LessonPeriod.objects
+
+    if type_ and id_:
+        if isinstance(instance, HttpResponseNotFound):
+            return HttpResponseNotFound()
+
+        type_ = TimetableType.from_string(type_)
+
+        lesson_periods = lesson_periods.filter_from_type(type_, instance)
+    elif hasattr(request, "user") and hasattr(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
+
+
+    if year and week:
+        wanted_week = CalendarWeek(year=year, week=week)
+    else:
+        wanted_week = CalendarWeek()
+
+    lesson_periods = lesson_periods.annotate(
+        has_documentation=Exists(
+            LessonDocumentation.objects.filter(
+                ~Q(topic__exact=""), lesson_period=OuterRef("pk"), week=wanted_week.week
+            )
+        )
+    ).in_week(wanted_week)
 
     # Add a form to filter the view
     if type_:
@@ -136,9 +178,14 @@ def week_view(
     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_pk)
+
+
+        persons = Person.objects.filter(is_active=True)
+
+        if not request.user.has_perm("alsijil.view_week_personalnote", instance):
+            persons = persons.filter(pk=request.user.pk)
+
+        persons = (persons.filter(member_of__lessons__lesson_periods__in=lesson_periods_pk)
             .distinct()
             .prefetch_related("personal_notes")
             .annotate(
@@ -195,7 +242,7 @@ def week_view(
     return render(request, "alsijil/week_view.html", context)
 
 
-@permission_required("alsijil.full_register_group", fn=objectgetter_optional(Group, None, False))
+@permission_required("alsijil.view_full_register", fn=objectgetter_optional(Group, None, False))
 def full_register_group(request: HttpRequest, id_: int) -> HttpResponse:
     context = {}
 
@@ -270,7 +317,7 @@ def register_absence(request: HttpRequest) -> HttpResponse:
     register_absence_form = RegisterAbsenceForm(request.POST or None)
 
     if request.method == "POST":
-        if register_absence_form.is_valid():
+        if register_absence_form.is_valid() and request.user.has_perm("alsijil.register_absence", register_absence_form.cleaned_data["person"]):
             # Get data from form
             person = register_absence_form.cleaned_data["person"]
             start_date = register_absence_form.cleaned_data["date_start"]
@@ -295,7 +342,7 @@ def register_absence(request: HttpRequest) -> HttpResponse:
     return render(request, "alsijil/register_absence.html", context)
 
 
-@permission_required("alsijil.list_personal_note_filters")
+@permission_required("alsijil.view_personal_note_filters")
 def list_personal_note_filters(request: HttpRequest) -> HttpResponse:
     context = {}