Problem/Motivation

hook_lms_initialize_lesson (#3550125) only fires when a LessonStatus is first created. It does not fire on subsequent visits to the same lesson.

For modules that let teachers dynamically check/uncheck lessons (e.g., unlock Lesson 3 on Monday, lock it again on Wednesday), this means a student who already visited a lesson can still access it even after the teacher revoked access.

Steps to reproduce

Proposed resolution

Add a new hook_lms_lesson_access invoked on every lesson request. The hook receives the $lesson_status and modules can throw a TrainingException to deny access with a custom message and redirect, the same way as hook_lms_initialize_lesson.

The hook should be invoked in 3 places in TrainingManager:

getRequestedLessonStatus() — same lesson path (after load/initialize, before return)
getRequestedLessonStatus() — different lesson path (after load/initialize, before save)
getNextLessonStatus() — before returning the loaded/initialized status
In all cases, TrainingException is already caught by CourseControllerTrait::handleError().

Remaining tasks

User interface changes

API changes

<?php
function hook_lms_lesson_access(\Drupal\lms\Entity\LessonStatusInterface $lesson_status): void {
// Throw TrainingException to deny access.
}

Data model changes

Comments

alumni created an issue.