diff --git a/lib/classes/output/notification.php b/lib/classes/output/notification.php
index 1db678b0404..023193d94a6 100644
--- a/lib/classes/output/notification.php
+++ b/lib/classes/output/notification.php
@@ -84,9 +84,10 @@ class notification implements \renderable, \templatable {
* Notification constructor.
*
* @param string $message the message to print out
- * @param string $messagetype one of the NOTIFY_* constants..
+ * @param ?string $messagetype one of the NOTIFY_* constants..
+ * @param bool $closebutton Whether to show a close icon to remove the notification (default true).
*/
- public function __construct($message, $messagetype = null) {
+ public function __construct($message, $messagetype = null, $closebutton = true) {
$this->message = $message;
if (empty($messagetype)) {
@@ -94,6 +95,8 @@ class notification implements \renderable, \templatable {
}
$this->messagetype = $messagetype;
+
+ $this->closebutton = $closebutton;
}
/**
diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php
index 6a64c28cd38..6b61cab00f6 100644
--- a/lib/outputrenderers.php
+++ b/lib/outputrenderers.php
@@ -2875,10 +2875,11 @@ EOD;
* Note: \core\notification::add() may be more suitable for your usage.
*
* @param string $message The message to print out.
- * @param string $type The type of notification. See constants on \core\output\notification.
+ * @param ?string $type The type of notification. See constants on \core\output\notification.
+ * @param bool $closebutton Whether to show a close icon to remove the notification (default true).
* @return string the HTML to output.
*/
- public function notification($message, $type = null) {
+ public function notification($message, $type = null, $closebutton = true) {
$typemappings = [
// Valid types.
'success' => \core\output\notification::NOTIFY_SUCCESS,
@@ -2922,7 +2923,7 @@ EOD;
}
}
- $notification = new \core\output\notification($message, $type);
+ $notification = new \core\output\notification($message, $type, $closebutton);
if (count($extraclasses)) {
$notification->set_extra_classes($extraclasses);
}
@@ -4886,9 +4887,10 @@ class core_renderer_cli extends core_renderer {
*
* @param string $message The message to print out.
* @param string $type The type of notification. See constants on \core\output\notification.
+ * @param bool $closebutton Whether to show a close icon to remove the notification (default true).
* @return string A template fragment for a notification
*/
- public function notification($message, $type = null) {
+ public function notification($message, $type = null, $closebutton = true) {
$message = clean_text($message);
if ($type === 'notifysuccess' || $type === 'success') {
return "++ $message ++\n";
@@ -4972,8 +4974,10 @@ class core_renderer_ajax extends core_renderer {
*
* @param string $message The message to print out.
* @param string $type The type of notification. See constants on \core\output\notification.
+ * @param bool $closebutton Whether to show a close icon to remove the notification (default true).
*/
- public function notification($message, $type = null) {}
+ public function notification($message, $type = null, $closebutton = true) {
+ }
/**
* Used to display a redirection message.
diff --git a/mod/quiz/db/access.php b/mod/quiz/db/access.php
index ae31ddb7347..246641f6320 100644
--- a/mod/quiz/db/access.php
+++ b/mod/quiz/db/access.php
@@ -24,162 +24,173 @@
defined('MOODLE_INTERNAL') || die();
-$capabilities = array(
+$capabilities = [
// Ability to see that the quiz exists, and the basic information
// about it, for example the start date and time limit.
- 'mod/quiz:view' => array(
+ 'mod/quiz:view' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'guest' => CAP_ALLOW,
'student' => CAP_ALLOW,
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
// Ability to add a new quiz to the course.
- 'mod/quiz:addinstance' => array(
+ 'mod/quiz:addinstance' => [
'riskbitmask' => RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
- 'archetypes' => array(
+ 'archetypes' => [
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- ),
+ ],
'clonepermissionsfrom' => 'moodle/course:manageactivities'
- ),
+ ],
// Ability to do the quiz as a 'student'.
- 'mod/quiz:attempt' => array(
+ 'mod/quiz:attempt' => [
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'student' => CAP_ALLOW
- )
- ),
+ ]
+ ],
// Ability for a 'Student' to review their previous attempts. Review by
// 'Teachers' is controlled by mod/quiz:viewreports.
- 'mod/quiz:reviewmyattempts' => array(
+ 'mod/quiz:reviewmyattempts' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'student' => CAP_ALLOW
- ),
+ ],
'clonepermissionsfrom' => 'moodle/quiz:attempt'
- ),
+ ],
// Edit the quiz settings, add and remove questions.
- 'mod/quiz:manage' => array(
+ 'mod/quiz:manage' => [
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
// Edit the quiz overrides.
- 'mod/quiz:manageoverrides' => array(
+ 'mod/quiz:manageoverrides' => [
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
- // Preview the quiz.
- 'mod/quiz:preview' => array(
- 'captype' => 'write', // Only just a write.
+ // View the quiz overrides (only checked for users who don't have mod/quiz:manageoverrides.
+ 'mod/quiz:viewoverrides' => [
+ 'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
+
+ // Preview the quiz.
+ 'mod/quiz:preview' => [
+ 'captype' => 'write', // Only just a write.
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => [
+ 'teacher' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW
+ ]
+ ],
// Manually grade and comment on student attempts at a question.
- 'mod/quiz:grade' => array(
+ 'mod/quiz:grade' => [
'riskbitmask' => RISK_SPAM | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
// Regrade quizzes.
- 'mod/quiz:regrade' => array(
+ 'mod/quiz:regrade' => [
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- ),
+ ],
'clonepermissionsfrom' => 'mod/quiz:grade'
- ),
+ ],
// View the quiz reports.
- 'mod/quiz:viewreports' => array(
+ 'mod/quiz:viewreports' => [
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
// Delete attempts using the overview report.
- 'mod/quiz:deleteattempts' => array(
+ 'mod/quiz:deleteattempts' => [
'riskbitmask' => RISK_DATALOSS,
'captype' => 'write',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array(
+ 'archetypes' => [
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
- )
- ),
+ ]
+ ],
// Do not have the time limit imposed. Used for accessibility legislation compliance.
- 'mod/quiz:ignoretimelimits' => array(
+ 'mod/quiz:ignoretimelimits' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array()
- ),
+ 'archetypes' => []
+ ],
// Receive a confirmation message of own quiz submission.
- 'mod/quiz:emailconfirmsubmission' => array(
+ 'mod/quiz:emailconfirmsubmission' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array()
- ),
+ 'archetypes' => []
+ ],
// Receive a notification message of other peoples' quiz submissions.
- 'mod/quiz:emailnotifysubmission' => array(
+ 'mod/quiz:emailnotifysubmission' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array()
- ),
+ 'archetypes' => []
+ ],
// Receive a notification message when a quiz attempt becomes overdue.
- 'mod/quiz:emailwarnoverdue' => array(
+ 'mod/quiz:emailwarnoverdue' => [
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
- 'archetypes' => array()
- ),
-);
+ 'archetypes' => []
+ ],
+];
diff --git a/mod/quiz/lang/en/deprecated.txt b/mod/quiz/lang/en/deprecated.txt
index 29a19bc3732..ecadc8221b1 100644
--- a/mod/quiz/lang/en/deprecated.txt
+++ b/mod/quiz/lang/en/deprecated.txt
@@ -1,3 +1,4 @@
numattemptsmade,mod_quiz
reviewofattempt,mod_quiz
-reviewofpreview,mod_quiz
\ No newline at end of file
+reviewofpreview,mod_quiz
+settingsoverrides,mod_quiz
diff --git a/mod/quiz/lang/en/quiz.php b/mod/quiz/lang/en/quiz.php
index b2684443eab..b59e4048403 100644
--- a/mod/quiz/lang/en/quiz.php
+++ b/mod/quiz/lang/en/quiz.php
@@ -613,6 +613,9 @@ $string['overridedeleteusersure'] = 'Are you sure you want to delete the overrid
$string['overridegroup'] = 'Override group';
$string['overridegroupeventname'] = '{$a->quiz} - {$a->group}';
$string['overrides'] = 'Overrides';
+$string['overridesforquiz'] = 'Settings overrides: {$a}';
+$string['overridesnoneforgroups'] = 'No group settings overrides have been created for this quiz.';
+$string['overridesnoneforusers'] = 'No user settings overrides have been created for this quiz.';
$string['overrideuser'] = 'Override user';
$string['overrideusereventname'] = '{$a->quiz} - Override';
$string['pageshort'] = 'P';
@@ -724,7 +727,8 @@ $string['quizisopen'] = 'This quiz is open';
$string['quizisclosedwillopen'] = 'Quiz closed (opens {$a})';
$string['quizisopenwillclose'] = 'Quiz open (closes {$a})';
$string['quiz:manage'] = 'Manage quizzes';
-$string['quiz:manageoverrides'] = 'Manage quiz overrides';
+$string['quiz:manageoverrides'] = 'Manage quiz settings overrides';
+$string['quiz:viewoverrides'] = 'View quiz settings overrides';
$string['quiznavigation'] = 'Quiz navigation';
$string['quizopen'] = 'Open the quiz';
$string['quizeventopens'] = '{$a} opens';
@@ -886,7 +890,6 @@ $string['serveridentifier'] = 'Identifier';
$string['serverinfo'] = 'Server information';
$string['servers'] = 'Servers';
$string['serverurl'] = 'Server URL';
-$string['settingsoverrides'] = 'Settings overrides';
$string['shortanswer'] = 'Short answer';
$string['show'] = 'Show';
$string['showall'] = 'Show all questions on one page';
@@ -1008,3 +1011,4 @@ $string['yourfinalgradeis'] = 'Your final grade for this quiz is {$a}.';
$string['numattemptsmade'] = '{$a} attempts made on this quiz';
$string['reviewofattempt'] = 'Review of attempt {$a}';
$string['reviewofpreview'] = 'Review of preview';
+$string['settingsoverrides'] = 'Settings overrides';
diff --git a/mod/quiz/lib.php b/mod/quiz/lib.php
index eb9b090de44..8f377d16479 100644
--- a/mod/quiz/lib.php
+++ b/mod/quiz/lib.php
@@ -1716,7 +1716,7 @@ function quiz_extend_settings_navigation($settings, $quiznode) {
$beforekey = $keys[$i + 1];
}
- if (has_capability('mod/quiz:manageoverrides', $PAGE->cm->context)) {
+ if (has_any_capability(['mod/quiz:manageoverrides', 'mod/quiz:viewoverrides'], $PAGE->cm->context)) {
$url = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$PAGE->cm->id));
$node = navigation_node::create(get_string('groupoverrides', 'quiz'),
new moodle_url($url, array('mode'=>'group')),
diff --git a/mod/quiz/overrides.php b/mod/quiz/overrides.php
index a42c3d6f96f..6e0e0dbb579 100644
--- a/mod/quiz/overrides.php
+++ b/mod/quiz/overrides.php
@@ -22,7 +22,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot.'/mod/quiz/lib.php');
require_once($CFG->dirroot.'/mod/quiz/locallib.php');
@@ -33,14 +32,17 @@ $cmid = required_param('cmid', PARAM_INT);
$mode = optional_param('mode', '', PARAM_ALPHA); // One of 'user' or 'group', default is 'group'.
list($course, $cm) = get_course_and_cm_from_cmid($cmid, 'quiz');
-$quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST);
+$quiz = $DB->get_record('quiz', ['id' => $cm->instance], '*', MUST_EXIST);
require_login($course, false, $cm);
$context = context_module::instance($cm->id);
// Check the user has the required capabilities to list overrides.
-require_capability('mod/quiz:manageoverrides', $context);
+$canedit = has_capability('mod/quiz:manageoverrides', $context);
+if (!$canedit) {
+ require_capability('mod/quiz:viewoverrides', $context);
+}
$quizgroupmode = groups_get_activity_groupmode($cm);
$accessallgroups = ($quizgroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $context);
@@ -58,16 +60,14 @@ if ($mode != "user" and $mode != "group") {
}
$groupmode = ($mode == "group");
-$url = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id, 'mode'=>$mode));
+$url = new moodle_url('/mod/quiz/overrides.php', ['cmid' => $cm->id, 'mode' => $mode]);
+$title = get_string('overridesforquiz', 'quiz',
+ format_string($quiz->name, true, ['context' => $context]));
$PAGE->set_url($url);
-
-// Display a list of overrides.
$PAGE->set_pagelayout('admin');
-$PAGE->set_title(get_string('overrides', 'quiz'));
+$PAGE->set_title($title);
$PAGE->set_heading($course->fullname);
-echo $OUTPUT->header();
-echo $OUTPUT->heading(format_string($quiz->name, true, array('context' => $context)));
// Delete orphaned group overrides.
$sql = 'SELECT o.id
@@ -76,7 +76,7 @@ $sql = 'SELECT o.id
WHERE o.groupid IS NOT NULL
AND g.id IS NULL
AND o.quiz = ?';
-$params = array($quiz->id);
+$params = [$quiz->id];
$orphaned = $DB->get_records_sql($sql, $params);
if (!empty($orphaned)) {
$DB->delete_records_list('quiz_overrides', 'id', array_keys($orphaned));
@@ -131,16 +131,18 @@ if ($groupmode) {
// Initialise table.
$table = new html_table();
-$table->headspan = array(1, 2, 1);
-$table->colclasses = array('colname', 'colsetting', 'colvalue', 'colaction');
-$table->head = array(
- $colname,
- get_string('overrides', 'quiz'),
- get_string('action'),
-);
+$table->headspan = [1, 2, 1];
+$table->colclasses = ['colname', 'colsetting', 'colvalue', 'colaction'];
+$table->head = [
+ $colname,
+ get_string('overrides', 'quiz'),
+];
+if ($canedit) {
+ $table->head[] = get_string('action');
+}
-$userurl = new moodle_url('/user/view.php', array());
-$groupurl = new moodle_url('/group/overview.php', array('id' => $cm->course));
+$userurl = new moodle_url('/user/view.php', []);
+$groupurl = new moodle_url('/group/overview.php', ['id' => $cm->course]);
$overridedeleteurl = new moodle_url('/mod/quiz/overridedelete.php');
$overrideediturl = new moodle_url('/mod/quiz/overrideedit.php');
@@ -149,11 +151,8 @@ $hasinactive = false; // Whether there are any inactive overrides.
foreach ($overrides as $override) {
- $fields = array();
- $values = array();
+ // Check if this override is active.
$active = true;
-
- // Check for inactive overrides.
if (!$groupmode) {
if (!has_capability('mod/quiz:attempt', $context, $override->userid)) {
// User not allowed to take the quiz.
@@ -163,6 +162,13 @@ foreach ($overrides as $override) {
$active = false;
}
}
+ if (!$active) {
+ $hasinactive = true;
+ }
+
+ // Prepare the information about which settings are overridden.
+ $fields = [];
+ $values = [];
// Format timeopen.
if (isset($override->timeopen)) {
@@ -170,28 +176,24 @@ foreach ($overrides as $override) {
$values[] = $override->timeopen > 0 ?
userdate($override->timeopen) : get_string('noopen', 'quiz');
}
-
// Format timeclose.
if (isset($override->timeclose)) {
$fields[] = get_string('quizcloses', 'quiz');
$values[] = $override->timeclose > 0 ?
userdate($override->timeclose) : get_string('noclose', 'quiz');
}
-
// Format timelimit.
if (isset($override->timelimit)) {
$fields[] = get_string('timelimit', 'quiz');
$values[] = $override->timelimit > 0 ?
format_time($override->timelimit) : get_string('none', 'quiz');
}
-
// Format number of attempts.
if (isset($override->attempts)) {
$fields[] = get_string('attempts', 'quiz');
$values[] = $override->attempts > 0 ?
$override->attempts : get_string('unlimited');
}
-
// Format password.
if (isset($override->password)) {
$fields[] = get_string('requirepassword', 'quiz');
@@ -199,110 +201,130 @@ foreach ($overrides as $override) {
get_string('enabled', 'quiz') : get_string('none', 'quiz');
}
- // Icons.
- $iconstr = '';
-
- // Edit.
- $editurlstr = $overrideediturl->out(true, array('id' => $override->id));
- $iconstr = '' .
- $OUTPUT->pix_icon('t/edit', get_string('edit')) . ' ';
- // Duplicate.
- $copyurlstr = $overrideediturl->out(true,
- array('id' => $override->id, 'action' => 'duplicate'));
- $iconstr .= '' .
- $OUTPUT->pix_icon('t/copy', get_string('copy')) . ' ';
- // Delete.
- $deleteurlstr = $overridedeleteurl->out(true,
- array('id' => $override->id, 'sesskey' => sesskey()));
- $iconstr .= '' .
- $OUTPUT->pix_icon('t/delete', get_string('delete')) . ' ';
-
+ // Prepare the information about who this override applies to.
if ($groupmode) {
$usergroupstr = '' . $override->name . '';
+ ['group' => $override->groupid]) . '" >' . $override->name . '';
} else {
$usergroupstr = '' . fullname($override) . '';
+ ['id' => $override->userid]) . '" >' . fullname($override) . '';
}
-
- $class = '';
if (!$active) {
- $class = "dimmed_text";
$usergroupstr .= '*';
- $hasinactive = true;
}
-
$usergroupcell = new html_table_cell();
$usergroupcell->rowspan = count($fields);
$usergroupcell->text = $usergroupstr;
- $actioncell = new html_table_cell();
- $actioncell->rowspan = count($fields);
- $actioncell->text = $iconstr;
+ // Prepare the actions.
+ if ($canedit) {
+ // Icons.
+ $iconstr = '';
+
+ // Edit.
+ $editurlstr = $overrideediturl->out(true, ['id' => $override->id]);
+ $iconstr = '' .
+ $OUTPUT->pix_icon('t/edit', get_string('edit')) . ' ';
+ // Duplicate.
+ $copyurlstr = $overrideediturl->out(true,
+ ['id' => $override->id, 'action' => 'duplicate']);
+ $iconstr .= '' .
+ $OUTPUT->pix_icon('t/copy', get_string('copy')) . ' ';
+ // Delete.
+ $deleteurlstr = $overridedeleteurl->out(true,
+ ['id' => $override->id, 'sesskey' => sesskey()]);
+ $iconstr .= '' .
+ $OUTPUT->pix_icon('t/delete', get_string('delete')) . ' ';
+
+ $actioncell = new html_table_cell();
+ $actioncell->rowspan = count($fields);
+ $actioncell->text = $iconstr;
+ }
+
+ // Add the data to the table.
for ($i = 0; $i < count($fields); ++$i) {
$row = new html_table_row();
- $row->attributes['class'] = $class;
+ if (!$active) {
+ $row->attributes['class'] = 'dimmed_text';
+ }
+
if ($i == 0) {
$row->cells[] = $usergroupcell;
}
- $cell1 = new html_table_cell();
- $cell1->text = $fields[$i];
- $row->cells[] = $cell1;
- $cell2 = new html_table_cell();
- $cell2->text = $values[$i];
- $row->cells[] = $cell2;
- if ($i == 0) {
+
+ $labelcell = new html_table_cell();
+ $labelcell->text = $fields[$i];
+ $row->cells[] = $labelcell;
+ $valuecell = new html_table_cell();
+ $valuecell->text = $values[$i];
+ $row->cells[] = $valuecell;
+
+ if ($canedit && $i == 0) {
$row->cells[] = $actioncell;
}
+
$table->data[] = $row;
}
}
+// Display a list of overrides.
+echo $OUTPUT->header();
+echo $OUTPUT->heading($title);
+
// Output the table and button.
-echo html_writer::start_tag('div', array('id' => 'quizoverrides'));
+echo html_writer::start_tag('div', ['id' => 'quizoverrides']);
if (count($table->data)) {
echo html_writer::table($table);
+} else {
+ if ($groupmode) {
+ echo $OUTPUT->notification(get_string('overridesnoneforgroups', 'quiz'), 'info', false);
+ } else {
+ echo $OUTPUT->notification(get_string('overridesnoneforusers', 'quiz'), 'info', false);
+ }
}
if ($hasinactive) {
- echo $OUTPUT->notification(get_string('inactiveoverridehelp', 'quiz'), 'dimmed_text');
+ echo $OUTPUT->notification(get_string('inactiveoverridehelp', 'quiz'), 'info', false);
}
-echo html_writer::start_tag('div', array('class' => 'buttons'));
-$options = array();
-if ($groupmode) {
- if (empty($groups)) {
- // There are no groups.
- echo $OUTPUT->notification(get_string('groupsnone', 'quiz'), 'error');
- $options['disabled'] = true;
- }
- echo $OUTPUT->single_button($overrideediturl->out(true,
- array('action' => 'addgroup', 'cmid' => $cm->id)),
- get_string('addnewgroupoverride', 'quiz'), 'post', $options);
-} else {
- $users = array();
- // See if there are any students in the quiz.
- if ($accessallgroups) {
- $users = get_users_by_capability($context, 'mod/quiz:attempt', 'u.id');
- $nousermessage = get_string('usersnone', 'quiz');
- } else if ($groups) {
- $users = get_users_by_capability($context, 'mod/quiz:attempt', 'u.id', '', '', '', array_keys($groups));
- $nousermessage = get_string('usersnone', 'quiz');
+if ($canedit) {
+ echo html_writer::start_tag('div', ['class' => 'buttons']);
+ $options = [];
+ if ($groupmode) {
+ if (empty($groups)) {
+ // There are no groups.
+ echo $OUTPUT->notification(get_string('groupsnone', 'quiz'), 'error');
+ $options['disabled'] = true;
+ }
+ echo $OUTPUT->single_button($overrideediturl->out(true,
+ ['action' => 'addgroup', 'cmid' => $cm->id]),
+ get_string('addnewgroupoverride', 'quiz'), 'post', $options);
} else {
- $nousermessage = get_string('groupsnone', 'quiz');
- }
- $info = new \core_availability\info_module($cm);
- $users = $info->filter_user_list($users);
+ $users = [];
+ // See if there are any students in the quiz.
+ if ($accessallgroups) {
+ $users = get_users_by_capability($context, 'mod/quiz:attempt', 'u.id');
+ $nousermessage = get_string('usersnone', 'quiz');
+ } else if ($groups) {
+ $users = get_users_by_capability($context, 'mod/quiz:attempt', 'u.id', '', '', '', array_keys($groups));
+ $nousermessage = get_string('usersnone', 'quiz');
+ } else {
+ $nousermessage = get_string('groupsnone', 'quiz');
+ }
+ $info = new \core_availability\info_module($cm);
+ $users = $info->filter_user_list($users);
- if (empty($users)) {
- // There are no students.
- echo $OUTPUT->notification($nousermessage, 'error');
- $options['disabled'] = true;
+ if (empty($users)) {
+ // There are no students.
+ echo $OUTPUT->notification($nousermessage, 'error');
+ $options['disabled'] = true;
+ }
+ echo $OUTPUT->single_button($overrideediturl->out(true,
+ ['action' => 'adduser', 'cmid' => $cm->id]),
+ get_string('addnewuseroverride', 'quiz'), 'get', $options);
}
- echo $OUTPUT->single_button($overrideediturl->out(true,
- array('action' => 'adduser', 'cmid' => $cm->id)),
- get_string('addnewuseroverride', 'quiz'), 'get', $options);
+ echo html_writer::end_tag('div');
}
-echo html_writer::end_tag('div');
+
echo html_writer::end_tag('div');
// Finish the page.
diff --git a/mod/quiz/tests/behat/quiz_group_override.feature b/mod/quiz/tests/behat/quiz_group_override.feature
index c20ac9fbffd..04edfc4e83a 100644
--- a/mod/quiz/tests/behat/quiz_group_override.feature
+++ b/mod/quiz/tests/behat/quiz_group_override.feature
@@ -2,7 +2,7 @@
Feature: Quiz group override
In order to grant a group special access to a quiz
As a teacher
- I need to create an override for thta group.
+ I need to create an override for that group.
Background:
Given the following "users" exist:
@@ -13,6 +13,7 @@ Feature: Quiz group override
| student2 | Sam 2 | Student 2 | student2@example.com |
| teacher3 | Terry 3 | Teacher 3 | teacher3@example.com |
| student3 | Sam 3 | Student 3 | student3@example.com |
+ | helper | Exam | Helper | helper@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
@@ -24,6 +25,7 @@ Feature: Quiz group override
| student2 | C1 | student |
| teacher3 | C1 | editingteacher |
| student3 | C1 | student |
+ | helper | C1 | teacher |
And the following "groups" exist:
| name | course | idnumber |
| Group 1 | C1 | G1 |
@@ -38,6 +40,9 @@ Feature: Quiz group override
| teacher2 | G2 |
| teacher2 | G3 |
| student3 | G3 |
+ | helper | G1 |
+ | helper | G2 |
+ | helper | G3 |
And the following "activities" exist:
| activity | name | intro | course | idnumber | groupmode |
| quiz | Test quiz | Test quiz description | C1 | quiz1 | 1 |
@@ -59,37 +64,49 @@ Feature: Quiz group override
Then I should see "No groups you can access."
And the "Add group override" "button" should be disabled
- Scenario: A teacher with accessallgroups permission should see all group overrides
- When I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "admin"
+ Scenario: A teacher can create an override
+ When I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "teacher1"
And I press "Add group override"
And I set the following fields to these values:
- | Override group | Group 1 |
- | Attempts allowed | 2 |
+ | Override group | Group 1 |
+ | Attempts allowed | 2 |
And I press "Save and enter another override"
And I set the following fields to these values:
- | Override group | Group 2 |
+ | Override group | Group 3 |
| Attempts allowed | 2 |
And I press "Save"
- And I log out
- And I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "teacher1"
- Then I should see "Group 1" in the ".generaltable" "css_element"
- And I should see "Group 2" in the ".generaltable" "css_element"
+ Then "Group 1" "table_row" should exist
+
+ Scenario: A teacher with accessallgroups permission should see all group overrides
+ Given the following "mod_quiz > group overrides" exist:
+ | quiz | group | attempts |
+ | Test quiz | G1 | 2 |
+ | Test quiz | G2 | 2 |
+ When I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "teacher1"
+ Then "Group 1" "table_row" should exist
+ And "Group 2" "table_row" should exist
Scenario: A teacher without accessallgroups permission should only see the group overrides within his/her groups, when the activity's group mode is "separate groups"
Given the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 |
- When I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "admin"
- And I press "Add group override"
- And I set the following fields to these values:
- | Override group | Group 1 |
- | Attempts allowed | 2 |
- And I press "Save and enter another override"
- And I set the following fields to these values:
- | Override group | Group 2 |
- | Attempts allowed | 2 |
- And I press "Save"
- And I log out
+ And the following "mod_quiz > group overrides" exist:
+ | quiz | group | attempts |
+ | Test quiz | G1 | 2 |
+ | Test quiz | G2 | 2 |
When I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "teacher1"
- Then I should see "Group 1" in the ".generaltable" "css_element"
- And I should not see "Group 2" in the ".generaltable" "css_element"
+ Then "Group 1" "table_row" should exist
+ And "Group 2" "table_row" should not exist
+
+ Scenario: A non-editing teacher can see the overrides, but not change them
+ Given the following "mod_quiz > group overrides" exist:
+ | quiz | group | attempts |
+ | Test quiz | G1 | 2 |
+ | Test quiz | G2 | 2 |
+ When I am on the "Test quiz" "mod_quiz > Group overrides" page logged in as "helper"
+ Then "Group 1" "table_row" should exist
+ And "Group 2" "table_row" should exist
+ And "Add group override" "button" should not exist
+ And "Edit" "link" should not exist in the "Group 1" "table_row"
+ And "Copy" "link" should not exist in the "Group 1" "table_row"
+ And "Delete" "link" should not exist in the "Group 1" "table_row"
diff --git a/mod/quiz/tests/behat/quiz_user_override.feature b/mod/quiz/tests/behat/quiz_user_override.feature
index 408345d8b22..c9e7d905834 100644
--- a/mod/quiz/tests/behat/quiz_user_override.feature
+++ b/mod/quiz/tests/behat/quiz_user_override.feature
@@ -7,7 +7,8 @@ Feature: Quiz user override
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
- | teacher1 | Teacher | One | teacher1@example.com |
+ | teacher | Teacher | One | teacher@example.com |
+ | helper | Exam | Helper | helper@example.com |
| student1 | Student | One | student1@example.com |
| student2 | Student | Two | student2@example.com |
And the following "courses" exist:
@@ -15,18 +16,17 @@ Feature: Quiz user override
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
- | teacher1 | C1 | editingteacher |
+ | teacher | C1 | editingteacher |
+ | helper | C1 | teacher |
| student1 | C1 | student |
| student2 | C1 | student |
- And the following "activities" exist:
- | activity | name | intro | course | idnumber |
- | quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 |
@javascript
Scenario: Add, modify then delete a user override
- Given I log in as "teacher1"
- And I am on "Course 1" course homepage
- When I follow "Quiz 1"
+ Given the following "activities" exist:
+ | activity | name | course | idnumber |
+ | quiz | Test quiz | C1 | quiz1 |
+ And I am on the "Test quiz" "mod_quiz > View" page logged in as "teacher"
And I navigate to "User overrides" in current page administration
And I press "Add user override"
And I set the following fields to these values:
@@ -38,26 +38,24 @@ Feature: Quiz user override
| timeclose[hour] | 08 |
| timeclose[minute] | 00 |
And I press "Save"
- And I should see "Wednesday, 1 January 2020, 8:00"
- Then I click on "Edit" "link" in the "Student One" "table_row"
+ Then I should see "Wednesday, 1 January 2020, 8:00"
+
+ And I click on "Edit" "link" in the "Student One" "table_row"
And I set the following fields to these values:
| timeclose[year] | 2030 |
And I press "Save"
And I should see "Tuesday, 1 January 2030, 8:00"
+
And I click on "Delete" "link"
And I press "Continue"
And I should not see "Student One"
@javascript
- Scenario: Being able to modify a user override when the quiz is not available to the student
- Given I log in as "teacher1"
- And I am on "Course 1" course homepage
- And I follow "Quiz 1"
- And I navigate to "Edit settings" in current page administration
- And I expand all fieldsets
- And I set the field "Availability" to "Hide from students"
- And I click on "Save and display" "button"
- When I navigate to "User overrides" in current page administration
+ Scenario: Can add a user override when the quiz is not available to the student
+ Given the following "activities" exist:
+ | activity | name | course | idnumber | visible |
+ | quiz | Test quiz | C1 | quiz1 | 0 |
+ When I am on the "Test quiz" "mod_quiz > User overrides" page logged in as "teacher"
And I press "Add user override"
And I set the following fields to these values:
| Override user | Student1 |
@@ -77,18 +75,15 @@ Feature: Quiz user override
And the following "group members" exist:
| user | group |
| student1 | G1 |
- | teacher1 | G1 |
+ | teacher | G1 |
| student2 | G2 |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 |
And the following "activities" exist:
- | activity | name | intro | course | idnumber | groupmode |
- | quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 | 1 |
- When I log in as "teacher1"
- And I am on "Course 1" course homepage
- And I follow "Quiz 2"
- And I navigate to "User overrides" in current page administration
+ | activity | name | course | idnumber | groupmode |
+ | quiz | Test quiz | C1 | quiz1 | 1 |
+ When I am on the "Test quiz" "mod_quiz > User overrides" page logged in as "teacher"
And I press "Add user override"
Then the "Override user" select box should contain "Student One, student1@example.com"
And the "Override user" select box should not contain "Student Two, student2@example.com"
@@ -104,11 +99,25 @@ Feature: Quiz user override
| capability | permission | role | contextlevel | reference |
| moodle/site:accessallgroups | Prevent | editingteacher | Course | C1 |
And the following "activities" exist:
- | activity | name | intro | course | idnumber | groupmode |
- | quiz | Quiz 2 | Quiz 2 description | C1 | quiz2 | 1 |
- When I log in as "teacher1"
- And I am on "Course 1" course homepage
- And I follow "Quiz 2"
- And I navigate to "User overrides" in current page administration
+ | activity | name | course | idnumber | groupmode |
+ | quiz | Test quiz | C1 | quiz1 | 1 |
+ When I am on the "Test quiz" "mod_quiz > User overrides" page logged in as "teacher"
Then I should see "No groups you can access."
And the "Add user override" "button" should be disabled
+
+ Scenario: A non-editing teacher can see the overrides, but not change them
+ Given the following "activities" exist:
+ | activity | name | course | idnumber |
+ | quiz | Test quiz | C1 | quiz1 |
+ And the following "mod_quiz > user overrides" exist:
+ | quiz | user | attempts |
+ | Test quiz | student1 | 2 |
+ | Test quiz | student2 | 2 |
+ And I am on the "Test quiz" "mod_quiz > View" page logged in as "helper"
+ When I navigate to "User overrides" in current page administration
+ Then "Student One" "table_row" should exist
+ And "Student Two" "table_row" should exist
+ And "Add user override" "button" should not exist
+ And "Edit" "link" should not exist in the "Student One" "table_row"
+ And "Copy" "link" should not exist in the "Student One" "table_row"
+ And "Delete" "link" should not exist in the "Student One" "table_row"
diff --git a/mod/quiz/version.php b/mod/quiz/version.php
index ca5d4f5ec72..4ec5a89b202 100644
--- a/mod/quiz/version.php
+++ b/mod/quiz/version.php
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2021052500;
+$plugin->version = 2021052501;
$plugin->requires = 2021052500;
$plugin->component = 'mod_quiz';