diff --git a/.upgradenotes/MDL-86660-2025111708215080.yml b/.upgradenotes/MDL-86660-2025111708215080.yml new file mode 100644 index 00000000000..78e040f66e7 --- /dev/null +++ b/.upgradenotes/MDL-86660-2025111708215080.yml @@ -0,0 +1,7 @@ +issueNumber: MDL-86660 +notes: + core_courseformat: + - message: >- + The `$cm` attribute in `activityoverviewbase` has been updated to public + visibility, allowing direct access to the course module instance + type: changed diff --git a/.upgradenotes/MDL-86660-2025111708245313.yml b/.upgradenotes/MDL-86660-2025111708245313.yml new file mode 100644 index 00000000000..cec8fa5d90e --- /dev/null +++ b/.upgradenotes/MDL-86660-2025111708245313.yml @@ -0,0 +1,8 @@ +issueNumber: MDL-86660 +notes: + core_courseformat: + - message: >- + A new `available` attribute has been added to `activityname_exporter` + class. It allows the external API to return the activity's availability + status relative to the current user. + type: changed diff --git a/.upgradenotes/MDL-86660-2025111708292708.yml b/.upgradenotes/MDL-86660-2025111708292708.yml new file mode 100644 index 00000000000..6b7e8ca5b92 --- /dev/null +++ b/.upgradenotes/MDL-86660-2025111708292708.yml @@ -0,0 +1,9 @@ +issueNumber: MDL-86660 +notes: + core_courseformat: + - message: >- + Two new public static methods have been added to the `overviewtable` + class: + - `is_cm_displayable`: Determines if a course module should be listed in the overview table. + - `is_cm_available`: Checks if a course module is accessible to the user (and should therefore be rendered as a link). + type: changed diff --git a/public/course/format/classes/activityoverviewbase.php b/public/course/format/classes/activityoverviewbase.php index fa6203ab2f5..69ef2ca4634 100644 --- a/public/course/format/classes/activityoverviewbase.php +++ b/public/course/format/classes/activityoverviewbase.php @@ -75,7 +75,7 @@ abstract class activityoverviewbase { */ public function __construct( /** @var cm_info The course module. */ - protected readonly cm_info $cm, + public readonly cm_info $cm, ) { $this->context = $cm->context; $this->course = $cm->get_course(); diff --git a/public/course/format/classes/external/activityname_exporter.php b/public/course/format/classes/external/activityname_exporter.php index 4c4f2f2092f..358f13e59f4 100644 --- a/public/course/format/classes/external/activityname_exporter.php +++ b/public/course/format/classes/external/activityname_exporter.php @@ -87,6 +87,11 @@ class activityname_exporter extends exporter { 'multiple' => true, 'default' => [], ], + 'available' => [ + 'type' => PARAM_BOOL, + 'null' => NULL_NOT_ALLOWED, + 'description' => 'Whether the activity is available.', + ], ]; } @@ -102,6 +107,7 @@ class activityname_exporter extends exporter { 'hidden' => $templatedata->hidden, 'stealth' => $templatedata->stealth, 'sectiontitle' => $templatedata->sectiontitle ?? null, + 'available' => $templatedata->available, 'errormessages' => $source->get_error_messages(), ]; } diff --git a/public/course/format/classes/output/local/overview/activityname.php b/public/course/format/classes/output/local/overview/activityname.php index 103f7595315..267d43635ad 100644 --- a/public/course/format/classes/output/local/overview/activityname.php +++ b/public/course/format/classes/output/local/overview/activityname.php @@ -75,6 +75,7 @@ class activityname implements externable, named_templatable, renderable { 'hidden' => empty($cm->visible), 'stealth' => $cm->is_stealth(), 'nogroupserror' => $this->nogroupserror, + 'available' => overviewtable::is_cm_available($cm), ]; if ($format->uses_sections() && $section->uservisible) { $result->sectiontitle = $format->get_section_name($section); diff --git a/public/course/format/classes/output/local/overview/overviewpage.php b/public/course/format/classes/output/local/overview/overviewpage.php index 9a43021c1dc..38de38a4d96 100644 --- a/public/course/format/classes/output/local/overview/overviewpage.php +++ b/public/course/format/classes/output/local/overview/overviewpage.php @@ -92,9 +92,7 @@ class overviewpage implements renderable, named_templatable { $archetypes = []; foreach ($modinfo->cms as $cm) { - // Exclude activities that aren't visible or have no view link (e.g. label). - // Account for folder being displayed inline. - if (!$cm->uservisible || (!$cm->has_view() && strcmp($cm->modname, 'folder') !== 0)) { + if (!overviewtable::is_cm_displayable($cm)) { continue; } if (array_key_exists($cm->modname, $modfullnames)) { diff --git a/public/course/format/classes/output/local/overview/overviewtable.php b/public/course/format/classes/output/local/overview/overviewtable.php index f9f23100c07..209f28b1b1c 100644 --- a/public/course/format/classes/output/local/overview/overviewtable.php +++ b/public/course/format/classes/output/local/overview/overviewtable.php @@ -138,7 +138,7 @@ class overviewtable implements externable, named_templatable, renderable { private function load_all_overviews_from_each_activity(): array { $result = []; foreach ($this->get_related_course_modules() as $cm) { - if (!$this->is_cm_displayable($cm)) { + if (!self::is_cm_displayable($cm)) { continue; } $overview = overviewfactory::create($cm); @@ -215,13 +215,31 @@ class overviewtable implements externable, named_templatable, renderable { /** * Check if the course module is displayable in the overview table. * - * @param cm_info $cm - * @return bool + * @param cm_info $cm The course module info + * @return bool Whether the course module is displayable in the overview table or not. */ - private function is_cm_displayable(cm_info $cm): bool { + public static function is_cm_displayable(cm_info $cm): bool { + // Exclude activities that aren't displayed in the course page (except for stealth), + // activities that are not available but availability is hidden + // or activities that have no view link (e.g. label). // Folder is an exception because it has settings to be displayed in the course // page without having a view link. - return $cm->uservisible && ($cm->has_view() || strcmp($cm->modname, 'folder') === 0); + return ( + (has_capability('moodle/course:viewhiddenactivities', $cm->context) + || (($cm->is_visible_on_course_page() || $cm->is_stealth()) + && ($cm->available || !empty($cm->availableinfo)))) + && ($cm->has_view() || strcmp($cm->modname, 'folder') === 0) + ); + } + + /** + * Check if the given course module is available (so linkable) in the overview table. + * + * @param cm_info $cm The course module info + * @return bool Whether the course module is available or not. + */ + public static function is_cm_available(cm_info $cm): bool { + return $cm->uservisible || $cm->available; } /** @@ -263,6 +281,13 @@ class overviewtable implements externable, named_templatable, renderable { return ['name' => $overview->get_name_overview()]; } + if (!self::is_cm_available($overview->cm)) { + return [ + 'name' => $overview->get_name_overview(), + 'duedate' => $overview->get_due_date_overview(), + ]; + } + $row = [ 'name' => $overview->get_name_overview(), 'duedate' => $overview->get_due_date_overview(), diff --git a/public/course/format/templates/local/overview/activityname.mustache b/public/course/format/templates/local/overview/activityname.mustache index f8201f2b5ef..905ac8af80c 100644 --- a/public/course/format/templates/local/overview/activityname.mustache +++ b/public/course/format/templates/local/overview/activityname.mustache @@ -26,12 +26,14 @@ "sectiontitle": "Section title", "visible": true, "stealth": false, - "nogroupserror": false + "nogroupserror": false, + "available": true } }}
- {{{activityname}}} + {{#available}}{{{activityname}}}{{/available}} + {{^available}}{{{activityname}}}{{/available}}
{{#sectiontitle}}
diff --git a/public/course/format/tests/external/activityname_exporter_test.php b/public/course/format/tests/external/activityname_exporter_test.php index 00a089afa47..acf053be9cf 100644 --- a/public/course/format/tests/external/activityname_exporter_test.php +++ b/public/course/format/tests/external/activityname_exporter_test.php @@ -16,6 +16,8 @@ namespace core_courseformat\external; +use core_courseformat\output\local\overview\overviewtable; + /** * Tests for activityname_exporter. * @@ -57,7 +59,8 @@ final class activityname_exporter_test extends \advanced_testcase { $this->assertObjectHasProperty('stealth', $data); $this->assertObjectHasProperty('sectiontitle', $data); $this->assertObjectHasProperty('errormessages', $data); - $this->assertCount(6, get_object_vars($data)); + $this->assertObjectHasProperty('available', $data); + $this->assertCount(7, get_object_vars($data)); $expected = [ 'activityname' => \core_external\util::format_string($cm->name, $cm->context, true), @@ -66,6 +69,7 @@ final class activityname_exporter_test extends \advanced_testcase { 'stealth' => $cm->is_stealth(), 'sectiontitle' => $format->get_section_name($cm->get_section_info()), 'errormessages' => [], + 'available' => overviewtable::is_cm_available($cm), ]; foreach ($expected as $property => $value) { diff --git a/public/course/format/tests/output/local/overview/overviewtable_test.php b/public/course/format/tests/output/local/overview/overviewtable_test.php index 768a009fc5e..5a81506f605 100644 --- a/public/course/format/tests/output/local/overview/overviewtable_test.php +++ b/public/course/format/tests/output/local/overview/overviewtable_test.php @@ -28,8 +28,15 @@ namespace core_courseformat\output\local\overview; final class overviewtable_test extends \advanced_testcase { /** * Test export_for_external method. + * + * @param string $role The role of the user. + * @param int $expectedactivities The expected number of activities visible to the user. */ - public function test_export_for_external(): void { + #[\PHPUnit\Framework\Attributes\DataProvider('provider_export_for_external')] + public function test_export_for_external( + string $role, + int $expectedactivities, + ): void { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); @@ -37,32 +44,49 @@ final class overviewtable_test extends \advanced_testcase { // Ensure the course is fully loaded. $course = get_course($course->id); + // Create three pages, one of them unavailable and hidden to students. $mods = [ - 'assign1' => $this->getDataGenerator()->create_module('assign', ['course' => $course->id]), - 'assign2' => $this->getDataGenerator()->create_module('assign', ['course' => $course->id]), + 'page1' => $this->getDataGenerator()->create_module('page', ['course' => $course->id]), + 'page2' => $this->getDataGenerator()->create_module('page', ['course' => $course->id]), ]; + $availabilityjson = json_encode(\core_availability\tree::get_root_json( + [ + \availability_date\condition::get_json( + \availability_date\condition::DIRECTION_FROM, + time() + 3600, + ), + ], + '&', + false, + )); + $mods['page3'] = $this->getDataGenerator()->create_module('page', [ + 'course' => $course->id, + 'visible' => true, + 'availability' => $availabilityjson, + ]); $user = $this->getDataGenerator()->create_user(); - $this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher'); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $role); $this->setUser($user); $modinfo = get_fast_modinfo($course); $cms = [ - 'assign1' => $modinfo->get_cm($mods['assign1']->cmid), - 'assign2' => $modinfo->get_cm($mods['assign2']->cmid), + 'page1' => $modinfo->get_cm($mods['page1']->cmid), + 'page2' => $modinfo->get_cm($mods['page2']->cmid), + 'page3' => $modinfo->get_cm($mods['page3']->cmid), ]; $renderer = \core\di::get(\core\output\renderer_helper::class)->get_core_renderer(); - $overviewtable = new overviewtable($course, 'assign'); + $overviewtable = new overviewtable($course, 'page'); $data = $overviewtable->export_for_external(); $templatedata = $overviewtable->export_for_template($renderer); $this->assertEquals($course, $data->course); - $this->assertEquals(true, $data->hasintegration); + $this->assertEquals(false, $data->hasintegration); foreach ($templatedata->headers as $header) { $this->assertObjectHasProperty('name', $header); @@ -74,9 +98,9 @@ final class overviewtable_test extends \advanced_testcase { $this->assertCount(4, get_object_vars($data)); - $this->assertCount(2, $data->activities); + $this->assertCount($expectedactivities, $data->activities); - $this->assertEquals($cms['assign1'], $data->activities[0]->cm); + $this->assertEquals($cms['page1'], $data->activities[0]->cm); $this->assertEquals(false, $data->activities[0]->haserror); $this->assertCount(count($data->headers), $data->activities[0]->items); @@ -88,4 +112,442 @@ final class overviewtable_test extends \advanced_testcase { } } } + + /** + * Data provider for test_export_for_external. + * + * @return \Generator The data provider array. + */ + public static function provider_export_for_external(): \Generator { + yield 'Editing teacher' => [ + 'role' => 'editingteacher', + 'expectedactivities' => 3, + ]; + yield 'Non-editing teacher' => [ + 'role' => 'teacher', + 'expectedactivities' => 3, + ]; + yield 'Student' => [ + 'role' => 'student', + 'expectedactivities' => 2, + ]; + } + + /** + * Test is_cm_displayable method for various visibility and stealth combinations. + * + * @param string $role The role of the user. + * @param bool $visible Whether the activity is visible. + * @param bool $stealth Whether the activity is displayed in the course page or not. + * @param bool $expected The expected result. + */ + #[\PHPUnit\Framework\Attributes\DataProvider('provider_is_cm_displayable_visibility')] + public function test_is_cm_displayable_visibility( + string $role, + bool $visible, + bool $stealth, + bool $expected + ): void { + $this->resetAfterTest(); + set_config('allowstealth', true); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $role); + $this->setUser($user); + + $mod = $this->getDataGenerator()->create_module('page', [ + 'course' => $course->id, + 'visible' => $visible, + 'visibleoncoursepage' => !$stealth, + ]); + $modinfo = get_fast_modinfo($course); + $cm = $modinfo->get_cm($mod->cmid); + + $this->assertEquals($visible, $cm->visible); + $this->assertEquals($stealth, !$cm->visibleoncoursepage); + + $this->assertEquals($expected, overviewtable::is_cm_displayable($cm)); + } + + /** + * Data provider for test_is_cm_displayable_visibility. + * + * @return \Generator The data provider array. + */ + public static function provider_is_cm_displayable_visibility(): \Generator { + yield 'Editing teacher - Visible' => [ + 'role' => 'editingteacher', + 'visible' => true, + 'stealth' => false, + 'expected' => true, + ]; + yield 'Editing teacher - Hidden' => [ + 'role' => 'editingteacher', + 'visible' => false, + 'stealth' => false, + 'expected' => true, + ]; + yield 'Editing teacher - Stealth' => [ + 'role' => 'editingteacher', + 'visible' => true, + 'stealth' => true, + 'expected' => true, + ]; + yield 'Teacher - Visible' => [ + 'role' => 'teacher', + 'visible' => true, + 'stealth' => false, + 'expected' => true, + ]; + yield 'Teacher - Hidden' => [ + 'role' => 'teacher', + 'visible' => false, + 'stealth' => false, + 'expected' => true, + ]; + yield 'Teacher - Stealth' => [ + 'role' => 'teacher', + 'visible' => true, + 'stealth' => true, + 'expected' => true, + ]; + yield 'Student - Visible' => [ + 'role' => 'student', + 'visible' => true, + 'stealth' => false, + 'expected' => true, + ]; + yield 'Student - Hidden' => [ + 'role' => 'student', + 'visible' => false, + 'stealth' => false, + 'expected' => false, + ]; + yield 'Student - Stealth' => [ + 'role' => 'student', + 'visible' => true, + 'stealth' => true, + 'expected' => true, + ]; + } + + /** + * Test is_cm_displayable method for modules without view page (like folder or text&media). + */ + public function test_is_cm_displayable_without_view_page(): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher'); + $this->setUser($user); + + $modfolder = $this->getDataGenerator()->create_module('folder', [ + 'course' => $course->id, + 'visible' => 1, + ]); + $modtext = $this->getDataGenerator()->create_module('label', [ + 'course' => $course->id, + 'visible' => 1, + ]); + $modinfo = get_fast_modinfo($course); + $cmfolder = $modinfo->get_cm($modfolder->cmid); + $cmtext = $modinfo->get_cm($modtext->cmid); + + $this->assertTrue(overviewtable::is_cm_displayable($cmfolder)); + $this->assertFalse(overviewtable::is_cm_displayable($cmtext)); + } + + /** + * Test is_cm_displayable method for various availability combinations. + * + * @param string $role The role of the user. + * @param bool $visible Whether the activity is visible. + * @param bool $isavailable Whether the activity is available. + * @param bool $availabilityvisible Whether the availability info is shown. + * @param bool $expected The expected result. + */ + #[\PHPUnit\Framework\Attributes\DataProvider('provider_is_cm_displayable_availability')] + public function test_is_cm_displayable_availability( + string $role, + bool $visible, + bool $isavailable, + bool $availabilityvisible, + bool $expected + ): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $role); + $this->setUser($user); + + // Set up the availability settings. + $operation = \availability_date\condition::DIRECTION_FROM; + $time = $isavailable ? time() - 3600 : time() + 3600; + $availabilityjson = json_encode(\core_availability\tree::get_root_json( + [ + \availability_date\condition::get_json($operation, $time), + ], + '&', + $availabilityvisible, + )); + + $mod = $this->getDataGenerator()->create_module('page', [ + 'course' => $course->id, + 'visible' => $visible, + 'availability' => $availabilityjson, + ]); + $modinfo = get_fast_modinfo($course); + $cm = $modinfo->get_cm($mod->cmid); + + $this->assertEquals($visible, $cm->visible); + $this->assertEquals($isavailable, $cm->available); + if ($isavailable || !$visible) { + $this->assertEmpty($cm->availableinfo); + } else { + $this->assertEquals($availabilityvisible, !empty($cm->availableinfo)); + } + + $this->assertEquals($expected, overviewtable::is_cm_displayable($cm)); + } + + /** + * Data provider for test_is_cm_displayable_availability. + * + * @return \Generator The data provider array. + */ + public static function provider_is_cm_displayable_availability(): \Generator { + yield 'Teacher - Visible - Available visible' => [ + 'role' => 'teacher', + 'visible' => true, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Visible - Unavailable visible' => [ + 'role' => 'teacher', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Visible - Unavailable hidden' => [ + 'role' => 'teacher', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => true, + ]; + yield 'Teacher - Hidden - Available visible' => [ + 'role' => 'teacher', + 'visible' => false, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Hidden - Unavailable visible' => [ + 'role' => 'teacher', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Hidden - Unavailable hidden' => [ + 'role' => 'teacher', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => true, + ]; + yield 'Student - Visible - Available visible' => [ + 'role' => 'student', + 'visible' => true, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Student - Visible - Unavailable visible' => [ + 'role' => 'student', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Student - Visible - Unavailable hidden' => [ + 'role' => 'student', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => false, + ]; + yield 'Student - Hidden - Available visible' => [ + 'role' => 'student', + 'visible' => false, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => false, + ]; + yield 'Student - Hidden - Unavailable visible' => [ + 'role' => 'student', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => false, + ]; + yield 'Student - Hidden - Unavailable hidden' => [ + 'role' => 'student', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => false, + ]; + } + + /** + * Test is_cm_available method. + * + * @param string $role The role of the user. + * @param bool $visible Whether the activity is visible. + * @param bool $isavailable Whether the activity is available. + * @param bool $availabilityvisible Whether the availability info is shown. + * @param bool $expected The expected result. + */ + #[\PHPUnit\Framework\Attributes\DataProvider('provider_is_cm_available')] + public function test_is_cm_available( + string $role, + bool $visible, + bool $isavailable, + bool $availabilityvisible, + bool $expected + ): void { + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user->id, $course->id, $role); + $this->setUser($user); + + // Set up the availability settings. + $operation = \availability_date\condition::DIRECTION_FROM; + $time = $isavailable ? time() - 3600 : time() + 3600; + $availabilityjson = json_encode(\core_availability\tree::get_root_json( + [ + \availability_date\condition::get_json($operation, $time), + ], + '&', + $availabilityvisible, + )); + + $mod = $this->getDataGenerator()->create_module('page', [ + 'course' => $course->id, + 'visible' => $visible, + 'availability' => $availabilityjson, + ]); + $modinfo = get_fast_modinfo($course); + $cm = $modinfo->get_cm($mod->cmid); + + $this->assertEquals($visible, $cm->visible); + $this->assertEquals($isavailable, $cm->available); + if ($isavailable || !$visible) { + $this->assertEmpty($cm->availableinfo); + } else { + $this->assertEquals($availabilityvisible, !empty($cm->availableinfo)); + } + + $this->assertEquals($expected, overviewtable::is_cm_available($cm)); + } + + /** + * Data provider for test_is_cm_available. + * + * @return \Generator The data provider array. + */ + public static function provider_is_cm_available(): \Generator { + yield 'Teacher - Visible - Available visible' => [ + 'role' => 'teacher', + 'visible' => true, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Visible - Unavailable visible' => [ + 'role' => 'teacher', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Visible - Unavailable hidden' => [ + 'role' => 'teacher', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => true, + ]; + yield 'Teacher - Hidden - Available visible' => [ + 'role' => 'teacher', + 'visible' => false, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Hidden - Unavailable visible' => [ + 'role' => 'teacher', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Teacher - Hidden - Unavailable hidden' => [ + 'role' => 'teacher', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => true, + ]; + yield 'Student - Visible - Available visible' => [ + 'role' => 'student', + 'visible' => true, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Student - Visible - Unavailable visible' => [ + 'role' => 'student', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => false, + ]; + yield 'Student - Visible - Unavailable hidden' => [ + 'role' => 'student', + 'visible' => true, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => false, + ]; + yield 'Student - Hidden - Available visible' => [ + 'role' => 'student', + 'visible' => false, + 'isavailable' => true, + 'availabilityvisible' => true, + 'expected' => true, + ]; + yield 'Student - Hidden - Unavailable visible' => [ + 'role' => 'student', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => true, + 'expected' => false, + ]; + yield 'Student - Hidden - Unavailable hidden' => [ + 'role' => 'student', + 'visible' => false, + 'isavailable' => false, + 'availabilityvisible' => false, + 'expected' => false, + ]; + } } diff --git a/public/course/tests/behat/course_overview.feature b/public/course/tests/behat/course_overview.feature index 043b44a911d..a9edbcd27f8 100644 --- a/public/course/tests/behat/course_overview.feature +++ b/public/course/tests/behat/course_overview.feature @@ -17,8 +17,8 @@ Feature: Users can access the course activities overview page | teacher1 | C1 | editingteacher | | student1 | C1 | student | And the following "activities" exist: - | activity | course | section | idnumber | name | - | assign | C1 | 1 | 1 | Test assignment name | + | activity | course | section | idnumber | name | duedate | + | assign | C1 | 1 | 1 | Test assignment name | ##tomorrow noon## | Scenario: Teacher can navigate to the course overview page Given I am on the "C1" "Course" page logged in as "teacher1" @@ -364,3 +364,29 @@ Feature: Users can access the course activities overview page # Student should not see the section name. But I am on the "Course 1" "course > activities > assign" page logged in as "student1" And I should not see "Section 1" in the "Test assignment name" "table_row" + + @javascript + Scenario: Unavailable activities are shown or hidden in the overview based on user capability + # Add a date restriction to an activity, visible to students. + Given I am on the "Test assignment name" "assign activity editing" page logged in as teacher1 + And I expand all fieldsets + And I click on "Add restriction..." "button" in the "root" "core_availability > Availability Button Area" + And I click on "Date" "button" in the "Add restriction..." "dialogue" + And I set the field "Direction" in the "1" "availability_date > Date Restriction" to "until" + And I press "Save and return to course" + # Teacher can see the activity and the link in the overview. + When I am on the "Course 1" "course > activities > assign" page logged in as "teacher1" + Then I should see "Test assignment name" in the "assign_overview_collapsible" "region" + And "Test assignment name" "link" should exist in the "assign_overview_collapsible" "region" + And I should see "Name" in the "assign_overview_collapsible" "region" + And I should see "Due date" in the "assign_overview_collapsible" "region" + And I should see "Submissions" in the "assign_overview_collapsible" "region" + And I should see "Actions" in the "assign_overview_collapsible" "region" + # Student can see the activity but not the link in the overview. + But I am on the "Course 1" "course > activities > assign" page logged in as "student1" + And I should see "Test assignment name" in the "assign_overview_collapsible" "region" + And "Test assignment name" "link" should not exist in the "assign_overview_collapsible" "region" + And I should see "Name" in the "assign_overview_collapsible" "region" + And I should see "Due date" in the "assign_overview_collapsible" "region" + And I should not see "Submission status" in the "assign_overview_collapsible" "region" + And I should not see "Grade" in the "assign_overview_collapsible" "region"