diff --git a/aleksis/apps/alsijil/preferences.py b/aleksis/apps/alsijil/preferences.py
index b0d8fbc42c9227e32c227bf3ac10ef9c1635fba6..43125d96be458a42e0af49ffdb943ca287869914 100644
--- a/aleksis/apps/alsijil/preferences.py
+++ b/aleksis/apps/alsijil/preferences.py
@@ -64,6 +64,19 @@ class GroupTypesRegisterAbsence(ModelMultipleChoicePreference):
     )
 
 
+@site_preferences_registry.register
+class GroupTypesViewPersonStatistics(ModelMultipleChoicePreference):
+    section = alsijil
+    name = "group_types_view_person_statistics"
+    required = False
+    default = []
+    model = GroupType
+    verbose_name = _(
+        "User is allowed to view coursebook statistics for members "
+        "of groups the user is an owner of with these group types"
+    )
+
+
 @site_preferences_registry.register
 class GroupTypePriorityCoursebook(ModelChoicePreference):
     section = alsijil
diff --git a/aleksis/apps/alsijil/rules.py b/aleksis/apps/alsijil/rules.py
index 602663b519a0680ca88de3813ecbc38df64579a8..71927e400fb68beab9d2c5864106f63bb011e128 100644
--- a/aleksis/apps/alsijil/rules.py
+++ b/aleksis/apps/alsijil/rules.py
@@ -20,6 +20,7 @@ from .util.predicates import (
     can_view_documentation,
     can_view_participation_status,
     can_view_personal_note,
+    can_view_statistics_for_person,
     has_person_group_object_perm,
     is_course_group_owner,
     is_course_member,
@@ -241,6 +242,24 @@ add_perm(
     edit_personal_note_predicate,
 )
 
+view_group_statistics_predicate = has_person & (
+    has_global_perm("alsijil.view_participationstatus") | is_group_owner
+)
+add_perm(
+    "alsijil.view_group_statistics_rule",
+    view_group_statistics_predicate,
+)
+
+view_person_statistics_predicate = has_person & (
+    is_current_person
+    | has_global_perm("alsijil.view_participationstatus")
+    | can_view_statistics_for_person
+)
+add_perm(
+    "alsijil.view_person_statistics_rule",
+    view_person_statistics_predicate,
+)
+
 # View parent menu entry
 view_menu_predicate = has_person & (view_documentations_menu_predicate | view_extramarks_predicate)
 add_perm(
diff --git a/aleksis/apps/alsijil/schema/__init__.py b/aleksis/apps/alsijil/schema/__init__.py
index c7e7e2a23b45c76da8184f1e0f19420a8c417aa7..2e6bb7ad852bb3cb932d34393b8d05abaeed7f0d 100644
--- a/aleksis/apps/alsijil/schema/__init__.py
+++ b/aleksis/apps/alsijil/schema/__init__.py
@@ -259,28 +259,44 @@ class Query(graphene.ObjectType):
 
     @staticmethod
     def resolve_statistics_by_person(root, info, person, term):
+        person = Person.objects.get(pk=person)
+        if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
+            return None
         school_term = SchoolTerm.objects.get(id=term)
         return annotate_person_statistics_for_school_term(
-            Person.objects.filter(id=person), school_term
+            Person.objects.filter(id=person.id), school_term
         ).first()
 
     @staticmethod
     def resolve_participations_of_person(root, info, person, term=None):
-        # TODO: only current term
-        return ParticipationStatus.objects.filter(person=person, absence_reason__isnull=False)
+        person = Person.objects.get(pk=person)
+        if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
+            return []
+        school_term = SchoolTerm.objects.get(id=term)
+        return ParticipationStatus.objects.filter(
+            person=person,
+            absence_reason__isnull=False,
+            datetime_start__date__gte=school_term.date_start,
+            datetime_end__date__lte=school_term.date_end,
+        )
 
     @staticmethod
     def resolve_personal_notes_for_person(root, info, person, term=None):
-        # TODO: only current term
+        person = Person.objects.get(pk=person)
+        if not info.context.user.has_perm("alsijil.view_person_statistics_rule", person):
+            return []
         return NewPersonalNote.objects.filter(person=person)
 
     @staticmethod
     def resolve_statistics_by_group(root, info, group, term=None):
+        group = Group.objects.get(pk=group)
+        if not info.context.user.has_perm("alsijil.view_group_statistics_rule", group):
+            return []
         school_term = (
             SchoolTerm.objects.get(id=term) if term is not None else SchoolTerm.get_current()
         )
 
-        members = Group.objects.get(id=group).members.all()
+        members = group.members.all()
         return annotate_person_statistics_for_school_term(members, school_term, group=group)
 
 
diff --git a/aleksis/apps/alsijil/util/predicates.py b/aleksis/apps/alsijil/util/predicates.py
index 2a27bca7e2260a13d12199027d3501add3494b60..f44b7677af2b9222b3fbbeec4ee66ad088176135 100644
--- a/aleksis/apps/alsijil/util/predicates.py
+++ b/aleksis/apps/alsijil/util/predicates.py
@@ -365,3 +365,13 @@ def can_edit_personal_note(user: User, obj: NewPersonalNote):
                 user, obj.documentation.amends
             ) | is_lesson_event_group_owner(user, obj.documentation.amends)
     return False
+
+
+@predicate
+def can_view_statistics_for_person(user: User, obj: Person) -> bool:
+    """Predicate for registering absence for person."""
+    group_types = get_site_preferences()["alsijil__group_types_view_person_statistics"]
+    qs = obj.member_of.filter(owners=user.person)
+    if not group_types:
+        return False
+    return qs.filter(group_type__in=group_types).exists()