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
}
}}
{{#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"