mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 04:30:15 +01:00
Merge branch 'MDL-73683-master' of https://github.com/ferranrecio/moodle
This commit is contained in:
commit
f167418fc9
2
course/amd/build/actions.min.js
vendored
2
course/amd/build/actions.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -846,11 +846,7 @@ define(
|
||||
|
||||
case 'hide':
|
||||
case 'show':
|
||||
cm.visible = (action === 'show') ? true : false;
|
||||
break;
|
||||
|
||||
case 'duplicate':
|
||||
// Duplicate requires to get extra data from the server.
|
||||
courseeditor.dispatch('cmState', affectedids);
|
||||
break;
|
||||
}
|
||||
|
@ -388,14 +388,8 @@ class core_course_external extends external_api {
|
||||
// We didn't this before to be able to retrieve stealth activities.
|
||||
foreach ($coursecontents as $sectionnumber => $sectioncontents) {
|
||||
$section = $sections[$sectionnumber];
|
||||
// Show the section if the user is permitted to access it OR
|
||||
// if it's not available but there is some available info text which explains the reason & should display OR
|
||||
// the course is configured to show hidden sections name.
|
||||
$showsection = $section->uservisible ||
|
||||
($section->visible && !$section->available && !empty($section->availableinfo)) ||
|
||||
(!$section->visible && empty($courseformat->get_course()->hiddensections));
|
||||
|
||||
if (!$showsection) {
|
||||
if (!$courseformat->is_section_visible($section)) {
|
||||
unset($coursecontents[$sectionnumber]);
|
||||
continue;
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -50,7 +50,7 @@ export default class Component extends DndCmItem {
|
||||
this.classes = {
|
||||
CMHIDDEN: 'dimmed',
|
||||
LOCKED: 'editinprogress',
|
||||
RESTRICTIONS: 'rectrictions',
|
||||
RESTRICTIONS: 'restrictions',
|
||||
PAGEITEM: 'pageitem',
|
||||
};
|
||||
// We need our id to watch specific events.
|
||||
@ -131,7 +131,7 @@ export default class Component extends DndCmItem {
|
||||
this.getElement(this.selectors.CM_NAME).innerHTML = element.name;
|
||||
this.element.classList.toggle(this.classes.DRAGGING, element.dragging ?? false);
|
||||
this.element.classList.toggle(this.classes.LOCKED, element.locked ?? false);
|
||||
this.element.classList.toggle(this.classes.RESTRICTIONS, element.hascmrectrictions ?? false);
|
||||
this.element.classList.toggle(this.classes.RESTRICTIONS, element.hascmrestrictions ?? false);
|
||||
this.locked = element.locked;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ export default class Component extends DndSection {
|
||||
SECTIONHIDDEN: 'dimmed',
|
||||
SECTIONCURRENT: 'current',
|
||||
LOCKED: 'editinprogress',
|
||||
RESTRICTIONS: 'rectrictions',
|
||||
RESTRICTIONS: 'restrictions',
|
||||
PAGEITEM: 'pageitem',
|
||||
};
|
||||
|
||||
@ -127,10 +127,10 @@ export default class Component extends DndSection {
|
||||
// Update classes.
|
||||
const sectionItem = this.getElement(this.selectors.SECTION_ITEM);
|
||||
sectionItem.classList.toggle(this.classes.SECTIONHIDDEN, !element.visible);
|
||||
sectionItem.classList.toggle(this.classes.RESTRICTIONS, element.hasrestrictions ?? false);
|
||||
this.element.classList.toggle(this.classes.SECTIONCURRENT, element.current);
|
||||
this.element.classList.toggle(this.classes.DRAGGING, element.dragging ?? false);
|
||||
this.element.classList.toggle(this.classes.LOCKED, element.locked ?? false);
|
||||
this.element.classList.toggle(this.classes.RESTRICTIONS, element.hasrestrictions ?? false);
|
||||
this.locked = element.locked;
|
||||
// Update title.
|
||||
this.getElement(this.selectors.SECTION_TITLE).innerHTML = element.title;
|
||||
|
@ -1210,6 +1210,28 @@ abstract class base {
|
||||
return ($sectionnum && ($course = $this->get_course()) && $course->marker == $sectionnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if an specific section is visible to the current user.
|
||||
*
|
||||
* Formats can overrride this method to implement any special section logic.
|
||||
*
|
||||
* @param section_info $section the section modinfo
|
||||
* @return bool;
|
||||
*/
|
||||
public function is_section_visible(section_info $section): bool {
|
||||
// Previous to Moodle 4.0 thas logic was hardcoded. To prevent errors in the contrib plugins
|
||||
// the default logic is the same required for topics and weeks format and still uses
|
||||
// a "hiddensections" format setting.
|
||||
$course = $this->get_course();
|
||||
$hidesections = $course->hiddensections ?? true;
|
||||
// Show the section if the user is permitted to access it, OR if it's not available
|
||||
// but there is some available info text which explains the reason & should display,
|
||||
// OR it is hidden but the course has a setting to display hidden sections as unavailable.
|
||||
return $section->uservisible ||
|
||||
($section->visible && !$section->available && !empty($section->availableinfo)) ||
|
||||
(!$section->visible && !$hidesections);
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if the course editor must be displayed.
|
||||
*
|
||||
|
2
course/format/classes/external/get_state.php
vendored
2
course/format/classes/external/get_state.php
vendored
@ -102,7 +102,7 @@ class get_state extends external_api {
|
||||
// Sections and course modules state.
|
||||
$sections = $modinfo->get_section_info_all();
|
||||
foreach ($sections as $section) {
|
||||
if (!empty($section->uservisible)) {
|
||||
if ($courseformat->is_section_visible($section)) {
|
||||
// Only return this section data if it's visible by current user on the course page.
|
||||
$sectionstate = new $sectionclass($courseformat, $section);
|
||||
$result->section[] = $sectionstate->export_for_template($renderer);
|
||||
|
@ -153,13 +153,7 @@ class content implements renderable, templatable {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Show the section if the user is permitted to access it, OR if it's not available
|
||||
// but there is some available info text which explains the reason & should display,
|
||||
// OR it is hidden but the course has a setting to display hidden sections as unavilable.
|
||||
$showsection = $thissection->uservisible ||
|
||||
($thissection->visible && !$thissection->available && !empty($thissection->availableinfo)) ||
|
||||
(!$thissection->visible && !$course->hiddensections);
|
||||
if (!$showsection) {
|
||||
if (!$format->is_section_visible($thissection)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -86,21 +86,13 @@ class cm implements renderable {
|
||||
'sectionid' => $section->id,
|
||||
'sectionnumber' => $section->section,
|
||||
'uservisible' => $cm->uservisible,
|
||||
'hascmrestrictions' => $this->get_has_restrictions(),
|
||||
];
|
||||
|
||||
// Check the user access type to this cm.
|
||||
$info = new info_module($cm);
|
||||
$data->accessvisible = ($data->visible && $info->is_available_for_all());
|
||||
|
||||
// Check if restriction access are visible to the user.
|
||||
$canviewhidden = has_capability('moodle/course:viewhiddenactivities', $cm->context);
|
||||
if (!empty($CFG->enableavailability) && $canviewhidden) {
|
||||
// Some users can see restrictions even if it does not apply to them.
|
||||
$data->hascmrectrictions = !empty($cm->availableinfo);
|
||||
} else {
|
||||
$data->hascmrectrictions = !$data->accessvisible || !$cm->uservisible;
|
||||
}
|
||||
|
||||
// Add url if the activity is compatible.
|
||||
$url = $cm->url;
|
||||
if ($url) {
|
||||
@ -121,4 +113,33 @@ class cm implements renderable {
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the activity has a restrictions icon displayed or not.
|
||||
*
|
||||
* @return bool if the activity has visible restrictions for the user.
|
||||
*/
|
||||
protected function get_has_restrictions(): bool {
|
||||
global $CFG;
|
||||
$cm = $this->cm;
|
||||
|
||||
if (empty($cm->visible) || empty($CFG->enableavailability)) {
|
||||
return false;
|
||||
}
|
||||
// Nothing to be displayed to the user.
|
||||
if (!$cm->is_visible_on_course_page()) {
|
||||
return false;
|
||||
}
|
||||
// Not allowed to see the module but might be allowed to see some availability.
|
||||
if (!$cm->uservisible) {
|
||||
return !empty($cm->availableinfo);
|
||||
}
|
||||
// Content editors can see all restrictions if the activity is visible.
|
||||
if (has_capability('moodle/course:viewhiddenactivities', $cm->context)) {
|
||||
$ci = new info_module($cm);
|
||||
return !empty($ci->get_full_information());
|
||||
}
|
||||
// Regular users can only see restrictions if apply to them.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class course implements renderable {
|
||||
|
||||
$sections = $modinfo->get_section_info_all();
|
||||
foreach ($sections as $section) {
|
||||
if (!empty($section->uservisible)) {
|
||||
if ($format->is_section_visible($section)) {
|
||||
$data->sectionlist[] = $section->id;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
namespace core_courseformat\output\local\state;
|
||||
|
||||
use core_availability\info_section;
|
||||
use core_courseformat\base as course_format;
|
||||
use section_info;
|
||||
use renderable;
|
||||
@ -55,8 +56,6 @@ class section implements renderable {
|
||||
* @return array data context for a mustache template
|
||||
*/
|
||||
public function export_for_template(\renderer_base $output): stdClass {
|
||||
global $CFG;
|
||||
|
||||
$format = $this->format;
|
||||
$course = $format->get_course();
|
||||
$section = $this->section;
|
||||
@ -87,31 +86,50 @@ class section implements renderable {
|
||||
'sectionurl' => course_get_url($course, $section->section)->out(),
|
||||
'current' => $format->is_section_current($section),
|
||||
'indexcollapsed' => $indexcollapsed,
|
||||
'contentcollapsed' => $contentcollapsed
|
||||
'contentcollapsed' => $contentcollapsed,
|
||||
'hasrestrictions' => $this->get_has_restrictions(),
|
||||
];
|
||||
|
||||
// If the section availability restrictions must be displayed.
|
||||
$canviewhidden = has_capability(
|
||||
'moodle/course:viewhiddenactivities',
|
||||
context_course::instance($course->id)
|
||||
);
|
||||
if (!empty($CFG->enableavailability) && $canviewhidden) {
|
||||
$data->hasrestrictions = !empty($section->availableinfo);
|
||||
} else {
|
||||
$data->hasrestrictions = false;
|
||||
}
|
||||
|
||||
if (empty($modinfo->sections[$section->section])) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
foreach ($modinfo->sections[$section->section] as $modnumber) {
|
||||
$mod = $modinfo->cms[$modnumber];
|
||||
if ($mod->is_visible_on_course_page()) {
|
||||
if ($section->uservisible && $mod->is_visible_on_course_page()) {
|
||||
$data->cmlist[] = $mod->id;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the section has a restrictions icon displayed or not.
|
||||
*
|
||||
* @return bool if the section has visible restrictions for the user.
|
||||
*/
|
||||
protected function get_has_restrictions(): bool {
|
||||
global $CFG;
|
||||
|
||||
$section = $this->section;
|
||||
$course = $this->format->get_course();
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
// Hidden sections have no restriction indicator displayed.
|
||||
if (empty($section->visible) || empty($CFG->enableavailability)) {
|
||||
return false;
|
||||
}
|
||||
// The activity is not visible to the user but it may have some availability information.
|
||||
if (!$section->uservisible) {
|
||||
return !empty($section->availableinfo);
|
||||
}
|
||||
// Course editors can see all restrictions if the section is visible.
|
||||
if (has_capability('moodle/course:viewhiddensections', $context)) {
|
||||
$ci = new info_section($section);
|
||||
return !empty($ci->get_full_information());
|
||||
}
|
||||
// Regular users can only see restrictions if apply to them.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1033,13 +1033,8 @@ abstract class section_renderer extends core_course_renderer {
|
||||
// Activities inside this section are 'orphaned', this section will be printed as 'stealth' below.
|
||||
continue;
|
||||
}
|
||||
// Show the section if the user is permitted to access it, OR if it's not available
|
||||
// but there is some available info text which explains the reason & should display,
|
||||
// OR it is hidden but the course has a setting to display hidden sections as unavilable.
|
||||
$showsection = $thissection->uservisible ||
|
||||
($thissection->visible && !$thissection->available && !empty($thissection->availableinfo)) ||
|
||||
(!$thissection->visible && !$course->hiddensections);
|
||||
if (!$showsection) {
|
||||
|
||||
if (!$format->is_section_visible($thissection)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -111,14 +111,15 @@ class stateupdates implements JsonSerializable {
|
||||
}
|
||||
$course = $this->format->get_course();
|
||||
$modinfo = course_modinfo::instance($course);
|
||||
$format = $this->format;
|
||||
|
||||
$section = $modinfo->get_section_info_by_id($sectionid, MUST_EXIST);
|
||||
|
||||
if (!$section->uservisible) {
|
||||
if (!$format->is_section_visible($section)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sectionclass = $this->format->get_output_classname('state\\section');
|
||||
$sectionclass = $format->get_output_classname('state\\section');
|
||||
$currentstate = new $sectionclass($this->format, $section);
|
||||
|
||||
$this->add_update('section', $action, $currentstate->export_for_template($this->output));
|
||||
@ -162,12 +163,13 @@ class stateupdates implements JsonSerializable {
|
||||
|
||||
$cm = $modinfo->get_cm($cmid);
|
||||
$section = $modinfo->get_section_info_by_id($cm->section);
|
||||
$format = $this->format;
|
||||
|
||||
if (!$section->uservisible || !$cm->is_visible_on_course_page()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cmclass = $this->format->get_output_classname('state\\cm');
|
||||
$cmclass = $format->get_output_classname('state\\cm');
|
||||
$currentstate = new $cmclass($this->format, $section, $cm);
|
||||
|
||||
$this->add_update('cm', $action, $currentstate->export_for_template($this->output));
|
||||
|
@ -28,12 +28,12 @@
|
||||
"isactive": 1,
|
||||
"uniqid": "0",
|
||||
"accessvisible": 1,
|
||||
"hascmrectrictions": 0
|
||||
"hascmrestrictions": 0
|
||||
}
|
||||
}}
|
||||
<li class="courseindex-item
|
||||
{{#isactive}}active{{/isactive}}
|
||||
{{#hascmrectrictions}}rectrictions{{/hascmrectrictions}}
|
||||
{{#hascmrestrictions}}restrictions{{/hascmrestrictions}}
|
||||
{{^accessvisible}}dimmed{{/accessvisible}}
|
||||
{{#url}} d-flex {{/url}} {{^url}} d-flex-noedit {{/url}}"
|
||||
id="{{uniqid}}-course-index-cm-{{id}}"
|
||||
|
@ -29,7 +29,7 @@
|
||||
"indexcollapsed": 0,
|
||||
"current": 1,
|
||||
"visible": 1,
|
||||
"hasrectrictions": 0,
|
||||
"hasrestrictions": 0,
|
||||
"cms": [
|
||||
{
|
||||
"id": 10,
|
||||
@ -66,7 +66,7 @@
|
||||
>
|
||||
<div class="courseindex-item d-flex
|
||||
{{^visible}}dimmed{{/visible}}
|
||||
{{#hasrestrictions}}rectrictions{{/hasrestrictions}}
|
||||
{{#hasrestrictions}}restrictions{{/hasrestrictions}}
|
||||
courseindex-section-title"
|
||||
id="courseindexsection{{number}}"
|
||||
data-for="section_item"
|
||||
|
358
course/format/tests/output/local/state/cm_test.php
Normal file
358
course/format/tests/output/local/state/cm_test.php
Normal file
@ -0,0 +1,358 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_courseformat\output\local\state;
|
||||
|
||||
use availability_date\condition;
|
||||
use core_availability\tree;
|
||||
use context_course;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Tests for cm state class.
|
||||
*
|
||||
* @package core_courseformat
|
||||
* @copyright 2022 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_courseformat\output\local\state\cm
|
||||
*/
|
||||
class cm_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Setup to ensure that fixtures are loaded.
|
||||
*/
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php');
|
||||
require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_state.php');
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of state\cm hasavailability attribute.
|
||||
*
|
||||
* @dataProvider hasrestrictions_state_provider
|
||||
* @covers ::export_for_template
|
||||
*
|
||||
* @param string $format the course format
|
||||
* @param string $rolename the user role name (editingteacher or student)
|
||||
* @param bool $hasavailability if the activity|section has availability
|
||||
* @param bool $available if the activity availability condition is available or not to the user
|
||||
* @param bool $expected the expected result
|
||||
*/
|
||||
public function test_cm_hasrestrictions_state(
|
||||
string $format = 'topics',
|
||||
string $rolename = 'editingteacher',
|
||||
bool $hasavailability = false,
|
||||
bool $available = false,
|
||||
bool $expected = false
|
||||
) {
|
||||
$data = $this->setup_hasrestrictions_scenario($format, $rolename, $hasavailability, $available);
|
||||
|
||||
// Get the cm state.
|
||||
$courseformat = $data->courseformat;
|
||||
$renderer = $data->renderer;
|
||||
|
||||
$cmclass = $courseformat->get_output_classname('state\\cm');
|
||||
|
||||
$cmstate = new $cmclass(
|
||||
$courseformat,
|
||||
$data->section,
|
||||
$data->cm
|
||||
);
|
||||
$state = $cmstate->export_for_template($renderer);
|
||||
|
||||
$this->assertEquals($expected, $state->hascmrestrictions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup section or cm has restrictions scenario.
|
||||
*
|
||||
* @param string $format the course format
|
||||
* @param string $rolename the user role name (editingteacher or student)
|
||||
* @param bool $hasavailability if the activity|section has availability
|
||||
* @param bool $available if the activity availability condition is available or not to the user
|
||||
* @return stdClass the scenario instances.
|
||||
*/
|
||||
private function setup_hasrestrictions_scenario(
|
||||
string $format = 'topics',
|
||||
string $rolename = 'editingteacher',
|
||||
bool $hasavailability = false,
|
||||
bool $available = false
|
||||
): stdClass {
|
||||
global $PAGE, $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
set_config('enableavailability', 1);
|
||||
|
||||
$course = $this->getDataGenerator()->create_course(['numsections' => 1, 'format' => $format]);
|
||||
|
||||
// Create and enrol user.
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user(
|
||||
$user->id,
|
||||
$course->id,
|
||||
$rolename
|
||||
);
|
||||
$this->setUser($user);
|
||||
|
||||
// Create an activity.
|
||||
$activity = $this->getDataGenerator()->create_module('page', ['course' => $course->id], [
|
||||
'section' => 1,
|
||||
'visible' => 1
|
||||
]);
|
||||
|
||||
// Set up the availability settings.
|
||||
if ($hasavailability) {
|
||||
$operation = ($available) ? condition::DIRECTION_UNTIL : condition::DIRECTION_FROM;
|
||||
$availabilityjson = json_encode(tree::get_root_json(
|
||||
[
|
||||
condition::get_json($operation, time() + 3600),
|
||||
],
|
||||
'&',
|
||||
true
|
||||
));
|
||||
$selector = ['id' => $activity->cmid];
|
||||
$DB->set_field('course_modules', 'availability', trim($availabilityjson), $selector);
|
||||
}
|
||||
|
||||
// Get the cm state.
|
||||
$courseformat = course_get_format($course->id);
|
||||
$modinfo = $courseformat->get_modinfo();
|
||||
$renderer = $courseformat->get_renderer($PAGE);
|
||||
|
||||
if ($format == 'theunittest') {
|
||||
// These course format's hasn't the renderer file, so a debugging message will be displayed.
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
|
||||
return (object)[
|
||||
'courseformat' => $courseformat,
|
||||
'section' => $modinfo->get_section_info(1),
|
||||
'cm' => $modinfo->get_cm($activity->cmid),
|
||||
'renderer' => $renderer,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_state().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function hasrestrictions_state_provider(): array {
|
||||
return [
|
||||
// Teacher scenarios (topics).
|
||||
'Teacher, Topics, can edit, has availability and is available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Topics, can edit, has availability and is not available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Topics, can edit and has not availability' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Teacher scenarios (weeks).
|
||||
'Teacher, Weeks, can edit, has availability and is available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Weeks, can edit, has availability and is not available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Weeks, can edit and has not availability' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Teacher scenarios (mock format).
|
||||
'Teacher, Mock format, can edit, has availability and is available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Mock format, can edit, has availability and is not available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Mock format, can edit and has not availability' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Non editing teacher scenarios (topics).
|
||||
'Non editing teacher, Topics, can edit, has availability and is available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Non editing teacher, Topics, can edit, has availability and is not available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Non editing teacher, Topics, can edit and has not availability' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Non editing teacher scenarios (weeks).
|
||||
'Non editing teacher, Weeks, can edit, has availability and is available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Non editing teacher, Weeks, can edit, has availability and is not available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Non editing teacher, Weeks, can edit and has not availability' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Non editing teacher scenarios (mock format).
|
||||
'Non editing teacher, Mock format, can edit, has availability and is available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Non editing teacher, Mock format, can edit, has availability and is not available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Non editing teacher, Mock format, can edit and has not availability' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Student scenarios (topics).
|
||||
'Student, Topics, cannot edit, has availability and is available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Student, Topics, cannot edit, has availability and is not available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Student, Topics, cannot edit and has not availability' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Student scenarios (weeks).
|
||||
'Student, Weeks, cannot edit, has availability and is available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Student, Weeks, cannot edit, has availability and is not available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Student, Weeks, cannot edit and has not availability' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Student scenarios (mock format).
|
||||
'Student, Mock format, cannot edit, has availability and is available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Student, Mock format, cannot edit, has availability and is not available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Student, Mock format, cannot edit and has not availability' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
350
course/format/tests/output/local/state/section_test.php
Normal file
350
course/format/tests/output/local/state/section_test.php
Normal file
@ -0,0 +1,350 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_courseformat\output\local\state;
|
||||
|
||||
use availability_date\condition;
|
||||
use core_availability\tree;
|
||||
use context_course;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Tests for section state class.
|
||||
*
|
||||
* @package core_courseformat
|
||||
* @copyright 2022 Ferran Recio <ferran@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @coversDefaultClass \core_courseformat\output\local\state\section
|
||||
*/
|
||||
class section_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Setup to ensure that fixtures are loaded.
|
||||
*/
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php');
|
||||
require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_state.php');
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of state\section hasavailability attribute.
|
||||
*
|
||||
* @dataProvider hasrestrictions_state_provider
|
||||
* @covers ::export_for_template
|
||||
*
|
||||
* @param string $format the course format
|
||||
* @param string $rolename the user role name (editingteacher or student)
|
||||
* @param bool $hasavailability if the activity|section has availability
|
||||
* @param bool $available if the activity availability condition is available or not to the user
|
||||
* @param bool $expected the expected result
|
||||
*/
|
||||
public function test_section_hasrestrictions_state(
|
||||
string $format = 'topics',
|
||||
string $rolename = 'editingteacher',
|
||||
bool $hasavailability = false,
|
||||
bool $available = false,
|
||||
bool $expected = false
|
||||
) {
|
||||
$data = $this->setup_hasrestrictions_scenario($format, $rolename, $hasavailability, $available);
|
||||
|
||||
// Get the cm state.
|
||||
$courseformat = $data->courseformat;
|
||||
$renderer = $data->renderer;
|
||||
|
||||
$sectionclass = $courseformat->get_output_classname('state\\section');
|
||||
|
||||
$sectionstate = new $sectionclass(
|
||||
$courseformat,
|
||||
$data->section
|
||||
);
|
||||
$state = $sectionstate->export_for_template($renderer);
|
||||
|
||||
$this->assertEquals($expected, $state->hasrestrictions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup section or cm has restrictions scenario.
|
||||
*
|
||||
* @param string $format the course format
|
||||
* @param string $rolename the user role name (editingteacher or student)
|
||||
* @param bool $hasavailability if the section has availability
|
||||
* @param bool $available if the section availability condition is available or not to the user
|
||||
* @return stdClass the scenario instances.
|
||||
*/
|
||||
private function setup_hasrestrictions_scenario(
|
||||
string $format = 'topics',
|
||||
string $rolename = 'editingteacher',
|
||||
bool $hasavailability = false,
|
||||
bool $available = false
|
||||
): stdClass {
|
||||
global $PAGE, $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course(['numsections' => 1, 'format' => $format]);
|
||||
|
||||
// Create and enrol user.
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user(
|
||||
$user->id,
|
||||
$course->id,
|
||||
$rolename
|
||||
);
|
||||
$this->setUser($user);
|
||||
|
||||
// Set up the availability settings.
|
||||
if ($hasavailability) {
|
||||
$operation = ($available) ? condition::DIRECTION_UNTIL : condition::DIRECTION_FROM;
|
||||
$availabilityjson = json_encode(tree::get_root_json(
|
||||
[
|
||||
condition::get_json($operation, time() + 3600),
|
||||
],
|
||||
'&',
|
||||
true
|
||||
));
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$sectioninfo = $modinfo->get_section_info(1);
|
||||
$selector = ['id' => $sectioninfo->id];
|
||||
$DB->set_field('course_sections', 'availability', trim($availabilityjson), $selector);
|
||||
}
|
||||
rebuild_course_cache($course->id, true);
|
||||
|
||||
$courseformat = course_get_format($course->id);
|
||||
$modinfo = $courseformat->get_modinfo();
|
||||
$renderer = $courseformat->get_renderer($PAGE);
|
||||
|
||||
if ($format == 'theunittest') {
|
||||
// These course format's hasn't the renderer file, so a debugging message will be displayed.
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
|
||||
return (object)[
|
||||
'courseformat' => $courseformat,
|
||||
'section' => $modinfo->get_section_info(1),
|
||||
'renderer' => $renderer,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_state().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function hasrestrictions_state_provider(): array {
|
||||
return [
|
||||
// Teacher scenarios (topics).
|
||||
'Teacher, Topics, can edit, has availability and is available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Topics, can edit, has availability and is not available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Topics, can edit and has not availability' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Teacher scenarios (weeks).
|
||||
'Teacher, Weeks, can edit, has availability and is available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Weeks, can edit, has availability and is not available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Weeks, can edit and has not availability' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Teacher scenarios (mock format).
|
||||
'Teacher, Mock format, can edit, has availability and is available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Mock format, can edit, has availability and is not available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Teacher, Mock format, can edit and has not availability' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'editingteacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Non editing teacher scenarios (topics).
|
||||
'Non editing teacher, Topics, can edit, has availability and is available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Non editing teacher, Topics, can edit, has availability and is not available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => false,
|
||||
],
|
||||
'Non editing teacher, Topics, can edit and has not availability' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Non editing teacher scenarios (weeks).
|
||||
'Non editing teacher, Weeks, can edit, has availability and is available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Non editing teacher, Weeks, can edit, has availability and is not available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => false,
|
||||
],
|
||||
'Non editing teacher, Weeks, can edit and has not availability' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Non editing teacher scenarios (mock format).
|
||||
'Non editing teacher, Mock format, can edit, has availability and is available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Non editing teacher, Mock format, can edit, has availability and is not available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => false,
|
||||
],
|
||||
'Non editing teacher, Mock format, can edit and has not availability' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'teacher',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Student scenarios (topics).
|
||||
'Topics, cannot edit, has availability and is available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Topics, cannot edit, has availability and is not available' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Topics, cannot edit and has not availability' => [
|
||||
'format' => 'topics',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Student scenarios (weeks).
|
||||
'Weeks, cannot edit, has availability and is available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Weeks, cannot edit, has availability and is not available' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Weeks, cannot edit and has not availability' => [
|
||||
'format' => 'weeks',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
// Student scenarios (mock format).
|
||||
'Mock format, cannot edit, has availability and is available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
'Mock format, cannot edit, has availability and is not available' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => true,
|
||||
'available' => false,
|
||||
'expected' => true,
|
||||
],
|
||||
'Mock format, cannot edit and has not availability' => [
|
||||
'format' => 'theunittest',
|
||||
'rolename' => 'student',
|
||||
'hasavailability' => false,
|
||||
'available' => true,
|
||||
'expected' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
@ -98,7 +98,7 @@ $courseindex-item-current: $primary !default;
|
||||
.courseindex-locked {
|
||||
display: none;
|
||||
}
|
||||
&.rectrictions {
|
||||
&.restrictions {
|
||||
.courseindex-locked {
|
||||
display: block;
|
||||
}
|
||||
|
@ -21389,7 +21389,7 @@ div.editor_atto_toolbar button .icon {
|
||||
color: #fff; }
|
||||
.courseindex .courseindex-item .courseindex-locked {
|
||||
display: none; }
|
||||
.courseindex .courseindex-item.rectrictions .courseindex-locked {
|
||||
.courseindex .courseindex-item.restrictions .courseindex-locked {
|
||||
display: block; }
|
||||
.courseindex .courseindex-item.pageitem {
|
||||
background-color: #0f6cbf;
|
||||
|
@ -21335,7 +21335,7 @@ div.editor_atto_toolbar button .icon {
|
||||
color: #fff; }
|
||||
.courseindex .courseindex-item .courseindex-locked {
|
||||
display: none; }
|
||||
.courseindex .courseindex-item.rectrictions .courseindex-locked {
|
||||
.courseindex .courseindex-item.restrictions .courseindex-locked {
|
||||
display: block; }
|
||||
.courseindex .courseindex-item.pageitem {
|
||||
background-color: #0f6cbf;
|
||||
|
Loading…
x
Reference in New Issue
Block a user