diff --git a/aleksis/apps/alsijil/models.py b/aleksis/apps/alsijil/models.py
index 2449efb3176ed973fbc11368b562bc891ff23f2e..95360559b0cbe707ee5288375637b5ff1cb0dd0e 100644
--- a/aleksis/apps/alsijil/models.py
+++ b/aleksis/apps/alsijil/models.py
@@ -42,7 +42,7 @@ from aleksis.apps.kolego.models import Absence as KolegoAbsence
 from aleksis.apps.kolego.models import AbsenceReason
 from aleksis.core.data_checks import field_validation_data_check_factory
 from aleksis.core.mixins import ExtensibleModel, GlobalPermissionModel
-from aleksis.core.models import CalendarEvent, Group, SchoolTerm
+from aleksis.core.models import CalendarEvent, Group, Person, SchoolTerm
 from aleksis.core.util.core_helpers import get_site_preferences
 from aleksis.core.util.model_helpers import ICONS
 
@@ -660,29 +660,12 @@ class Documentation(CalendarEvent):
             amends=lesson_event,
             course=course,
             subject=subject,
-            topic="",
-            homework="",
-            group_note="",
         )
         obj.teachers.set(teachers.all())
         obj.save()
 
         # Create Participation Statuses
-        # Cannot use djangos bulk_create method, as then the save method of the
-        # superclass wouldn't be called
-
-        for member in lesson_event.all_members:
-            # TODO: Check for preexisting absences in kolego
-            # TODO: maybe only create if the lesson start is in the past
-            status = ParticipationStatus.objects.create(
-                person=member,
-                related_documentation=obj,
-                datetime_start=datetime_start,
-                datetime_end=datetime_end,
-                timezone=lesson_event.timezone,
-            )
-            status.groups_of_person.set(member.member_of.all())
-            status.save()
+        obj.touch()
 
         return obj
 
@@ -692,15 +675,47 @@ class Documentation(CalendarEvent):
             return cls.create_from_lesson_event(
                 user,
                 *cls.parse_dummy(_id),
-            )
-
-        return cls.objects.get(id=_id)
+            ), True
+
+        return cls.objects.get(id=_id), False
+
+    def build_participation_status(self, person: Person) -> "ParticipationStatus":
+        """Build participation status object for this documentation and a person."""
+        return ParticipationStatus(
+            person=person,
+            related_documentation=self,
+            datetime_start=self.datetime_start,
+            datetime_end=self.datetime_end,
+            # Set timezone directly as save of ParticipationStatus won't be called in bulk_create
+            timezone=self.timezone,
+        )
 
     def touch(self):
-        # TODO: check if participation statuses etc. are created correctly.
-        #   might require some extra work, as the object may have been created
-        #   recently, so checking again would be overkill.
-        pass
+        # TODO: Check for preexisting absences in kolego
+        # TODO: maybe only create if the lesson start is in the past
+
+        if not self.amends:
+            # There is no source to update from
+            return
+
+        lesson_event: LessonEvent = self.amends
+        all_members = lesson_event.all_members
+
+        existing_participations = ParticipationStatus.objects.filter(
+            person__in=all_members, related_documentation=self
+        )
+        new_persons = Person.objects.filter(
+            Q(pk__in=[p.pk for p in all_members])
+            & ~Q(pk__in=existing_participations.values_list("person", flat=True))
+        ).prefetch_related("member_of")
+        new_participations = []
+        for person in new_persons:
+            participation_status = self.build_participation_status(person)
+            participation_status.save()
+            participation_status.groups_of_person.set(person.member_of.all())
+            new_participations.append(participation_status)
+
+        return new_participations
 
 
 class ParticipationStatus(CalendarEvent):
diff --git a/aleksis/apps/alsijil/schema/documentation.py b/aleksis/apps/alsijil/schema/documentation.py
index a994457550ff91d94897b2c7c1f7e373532577ee..433cde4e7c16508451f404765b72010e5d275929 100644
--- a/aleksis/apps/alsijil/schema/documentation.py
+++ b/aleksis/apps/alsijil/schema/documentation.py
@@ -109,7 +109,7 @@ class DocumentationBatchCreateOrUpdateMutation(graphene.Mutation):
 
         # Sadly, we can't use the update_or_create method since create_defaults
         # is only introduced in Django 5.0
-        obj = Documentation.get_or_create_by_id(_id, info.context.user)
+        obj, __ = Documentation.get_or_create_by_id(_id, info.context.user)
 
         if not info.context.user.has_perm("alsijil.edit_documentation_rule", obj):
             raise PermissionDenied()
@@ -146,6 +146,15 @@ class TouchDocumentationMutation(graphene.Mutation):
     documentation = graphene.Field(DocumentationType)
 
     def mutate(root, info, documentation_id):
-        documentation = Documentation.get_or_create_by_id(documentation_id, info.context.user)
-        documentation.touch()
+        documentation, created = Documentation.get_or_create_by_id(
+            documentation_id, info.context.user
+        )
+
+        if not info.context.user.has_perm(
+            "alsijil.edit_participation_status_for_documentation_rule", documentation
+        ):
+            raise PermissionDenied()
+        # FIXME Should not be effective in past
+        if not created:
+            documentation.touch()
         return TouchDocumentationMutation(documentation=documentation)