diff --git a/public/availability/tests/behat/display_availability.feature b/public/availability/tests/behat/display_availability.feature index c0ce6dcd9f4..c873cda4426 100644 --- a/public/availability/tests/behat/display_availability.feature +++ b/public/availability/tests/behat/display_availability.feature @@ -181,3 +181,30 @@ Feature: Display availability for activities and sections And I press "Add restriction..." And I click on "Grade" "button" in the "Add restriction..." "dialogue" And the "alt" attribute of ".availability-item .availability-eye img" "css_element" should contain "Item name displayed" + + Scenario: Restricted section page + # Set up. + Given the following config values are set as admin: + | unaddableblocks | | theme_boost| + And the following "groups" exist: + | course | name | idnumber | + | C1 | G1 | GI1 | + And the following "groupings" exist: + | name | course | idnumber | + | GX1 | C1 | GXI1 | + And I am on the "C1" "Course" page logged in as "teacher1" + And I turn editing mode on + And I add the "Navigation" block if not present + # Add a restriction to section 1 (visible to students). + And I edit the section "1" + And I set the following fields to these values: + | Access restrictions | Grouping: GX1 | + And I press "Save changes" + # Change to student view. + And I am on the "Course 1" "Course" page logged in as "student1" + And "Section 1" "link" should appear before "Section 2" "link" in the "Navigation" "block" + When I click on "Section 1" "link" in the "Navigation" "block" + # Section 1 should be visible and show info. + And I should see "Section 1" in the "page-header" "region" + And I should see "Not available unless" in the "region-main" "region" + And "Page 1" "link" should not exist in the "region-main" "region" diff --git a/public/course/classes/route/controller/restricted_section.php b/public/course/classes/route/controller/restricted_section.php new file mode 100644 index 00000000000..533aef54485 --- /dev/null +++ b/public/course/classes/route/controller/restricted_section.php @@ -0,0 +1,87 @@ +. + +namespace core_course\route\controller; + +use core\router\route; +use core\router\require_login; +use core_course\modinfo; +use core_course\section_info; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; + +/** + * Restricted section redirection. + * + * @package core_course + * @copyright 2026 Amaia Anabitarte + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class restricted_section { + use \core\router\route_controller; + + /** + * Restricted section. + * + * @param ResponseInterface $response + * @param section_info $sectioninfo + * @return ResponseInterface + */ + #[route( + path: '/sections/{section}/restricted', + pathtypes: [ + new \core\router\parameters\path_section(), + ], + requirelogin: new require_login( + requirelogin: true, + courseattributename: 'course', + ), + )] + public function restricted_section_page( + ServerRequestInterface $request, + ResponseInterface $response, + \stdClass $section, + ): ResponseInterface { + global $OUTPUT, $PAGE, $CFG; + + require_once($CFG->dirroot . '/course/lib.php'); + + $course = get_course($section->course); + $format = course_get_format($course->id); + $format->set_sectionid($section->id); + $outputclass = $format->get_output_classname('content'); + $sectionoutput = new $outputclass($format); + $PAGE->set_url('/course/section.php', ['id' => $section->id]); + $PAGE->set_course($course); + + $PAGE->set_pagelayout('course'); + $PAGE->add_body_classes(['limitedwidth', 'single-section-page']); + $PAGE->set_pagetype('course-view-section-' . $course->format . '-restricted'); + $PAGE->set_context(\context_course::instance($course->id)); + + $sectiontitle = $format->get_section_name($section); + $strtitle = get_string('restrictedtitle', 'course', $sectiontitle); + $PAGE->set_title($strtitle . \moodle_page::TITLE_SEPARATOR . $course->shortname); + $PAGE->set_heading($sectiontitle); + $PAGE->set_secondary_navigation(false); + $renderer = $format->get_renderer($PAGE); + $response->getBody()->write($OUTPUT->header()); + $response->getBody()->write($renderer->render($sectionoutput)); + $response->getBody()->write($OUTPUT->footer()); + + return $response; + } +} diff --git a/public/course/section.php b/public/course/section.php index eafb7df74db..3c4668b6e75 100644 --- a/public/course/section.php +++ b/public/course/section.php @@ -96,9 +96,11 @@ if (!$sectioninfo->uservisible) { // Check if coursesection has conditions affecting availability and if // so, output availability info. if ($sectioninfo->visible && $sectioninfo->availableinfo) { - $sectionname = get_section_name($course, $sectioninfo); - $message = get_string('notavailablecourse', '', $sectionname); - redirect(course_get_url($course), $message, null, \core\output\notification::NOTIFY_ERROR); + $url = \core\router\util::get_path_for_callable( + [\core_course\route\controller\restricted_section::class, 'restricted_section_page'], + ['section' => $sectioninfo->id], + ); + redirect($url, '', null); } else { // Note: We actually already know they don't have this capability // or uservisible would have been true; this is just to get the