MDL-68831 quiz overrides: show a summary on the quiz info page
This commit is contained in:
@@ -616,6 +616,11 @@ $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['overridessummary'] = 'Settings overrides exist ({$a})';
|
||||
$string['overridessummarythisgroup'] = 'Settings overrides exist ({$a}) for this group';
|
||||
$string['overridessummaryyourgroups'] = 'Settings overrides exist ({$a}) for your groups';
|
||||
$string['overridessummarygroup'] = 'Groups: {$a}';
|
||||
$string['overridessummaryuser'] = 'Users: {$a}';
|
||||
$string['overrideuser'] = 'Override user';
|
||||
$string['overrideusereventname'] = '{$a->quiz} - Override';
|
||||
$string['pageshort'] = 'P';
|
||||
|
||||
+3
-9
@@ -1645,16 +1645,10 @@ function quiz_num_attempt_summary($quiz, $cm, $returnzero = false, $currentgroup
|
||||
*/
|
||||
function quiz_attempt_summary_link_to_reports($quiz, $cm, $context, $returnzero = false,
|
||||
$currentgroup = 0) {
|
||||
global $CFG;
|
||||
$summary = quiz_num_attempt_summary($quiz, $cm, $returnzero, $currentgroup);
|
||||
if (!$summary) {
|
||||
return '';
|
||||
}
|
||||
global $PAGE;
|
||||
|
||||
require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
|
||||
$url = new moodle_url('/mod/quiz/report.php', array(
|
||||
'id' => $cm->id, 'mode' => quiz_report_default_report($context)));
|
||||
return html_writer::link($url, $summary);
|
||||
return $PAGE->get_renderer('mod_quiz')->quiz_attempt_summary_link_to_reports(
|
||||
$quiz, $cm, $context, $returnzero, $currentgroup);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -968,6 +968,72 @@ function quiz_update_all_final_grades($quiz) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return summary of the number of settings override that exist.
|
||||
*
|
||||
* To get a nice display of this, see the quiz_override_summary_links()
|
||||
* quiz renderer method.
|
||||
*
|
||||
* @param stdClass $quiz the quiz settings. Only $quiz->id is used at the moment.
|
||||
* @param stdClass|cm_info $cm the cm object. Only $cm->course, $cm->groupmode and
|
||||
* $cm->groupingid fields are used at the moment.
|
||||
* @param int $currentgroup if there is a concept of current group where this method is being called
|
||||
* (e.g. a report) pass it in here. Default 0 which means no current group.
|
||||
* @return array like 'group' => 3, 'user' => 12] where 3 is the number of group overrides,
|
||||
* and 12 is the number of user ones.
|
||||
*/
|
||||
function quiz_override_summary(stdClass $quiz, stdClass $cm, int $currentgroup = 0): array {
|
||||
global $DB;
|
||||
|
||||
if ($currentgroup) {
|
||||
// Currently only interested in one group.
|
||||
$groupcount = $DB->count_records('quiz_overrides', ['quiz' => $quiz->id, 'groupid' => $currentgroup]);
|
||||
$usercount = $DB->count_records_sql("
|
||||
SELECT COUNT(1)
|
||||
FROM {quiz_overrides} o
|
||||
JOIN {groups_members} gm ON o.userid = gm.userid
|
||||
WHERE o.quiz = ?
|
||||
AND gm.groupid = ?
|
||||
", [$quiz->id, $currentgroup]);
|
||||
return ['group' => $groupcount, 'user' => $usercount, 'mode' => 'onegroup'];
|
||||
}
|
||||
|
||||
$quizgroupmode = groups_get_activity_groupmode($cm);
|
||||
$accessallgroups = ($quizgroupmode == NOGROUPS) ||
|
||||
has_capability('moodle/site:accessallgroups', context_module::instance($cm->id));
|
||||
|
||||
if ($accessallgroups) {
|
||||
// User can see all groups.
|
||||
$groupcount = $DB->count_records_select('quiz_overrides',
|
||||
'quiz = ? AND groupid IS NOT NULL', [$quiz->id]);
|
||||
$usercount = $DB->count_records_select('quiz_overrides',
|
||||
'quiz = ? AND userid IS NOT NULL', [$quiz->id]);
|
||||
return ['group' => $groupcount, 'user' => $usercount, 'mode' => 'allgroups'];
|
||||
|
||||
} else {
|
||||
// User can only see groups they are in.
|
||||
$groups = groups_get_activity_allowed_groups($cm);
|
||||
if (!$groups) {
|
||||
return ['group' => 0, 'user' => 0, 'mode' => 'somegroups'];
|
||||
}
|
||||
|
||||
list($groupidtest, $params) = $DB->get_in_or_equal(array_keys($groups));
|
||||
$params[] = $quiz->id;
|
||||
|
||||
$groupcount = $DB->count_records_select('quiz_overrides',
|
||||
"groupid $groupidtest AND quiz = ?", $params);
|
||||
$usercount = $DB->count_records_sql("
|
||||
SELECT COUNT(1)
|
||||
FROM {quiz_overrides} o
|
||||
JOIN {groups_members} gm ON o.userid = gm.userid
|
||||
WHERE gm.groupid $groupidtest
|
||||
AND o.quiz = ?
|
||||
", $params);
|
||||
|
||||
return ['group' => $groupcount, 'user' => $usercount, 'mode' => 'somegroups'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Efficiently update check state time on all open attempts
|
||||
*
|
||||
|
||||
@@ -102,6 +102,7 @@ if ($groupmode) {
|
||||
$overrides = $DB->get_records_sql($sql, $params);
|
||||
}
|
||||
} else {
|
||||
// User overrides.
|
||||
$colname = get_string('user');
|
||||
list($sort, $params) = users_order_by_sql('u');
|
||||
$params['quizid'] = $quiz->id;
|
||||
|
||||
+56
-7
@@ -927,7 +927,7 @@ class mod_quiz_renderer extends plugin_renderer_base {
|
||||
*
|
||||
* @param object $quiz the quiz settings.
|
||||
* @param object $cm the course_module object.
|
||||
* @param object $context the quiz context.
|
||||
* @param context $context the quiz context.
|
||||
* @param array $messages any access messages that should be described.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
@@ -953,6 +953,13 @@ class mod_quiz_renderer extends plugin_renderer_base {
|
||||
array('class' => 'quizattemptcounts'));
|
||||
}
|
||||
}
|
||||
|
||||
if (has_any_capability(['mod/quiz:manageoverrides', 'mod/quiz:viewoverrides'], $context)) {
|
||||
if ($overrideinfo = $this->quiz_override_summary_links($quiz, $cm)) {
|
||||
$output .= html_writer::tag('div', $overrideinfo, ['class' => 'quizattemptcounts']);
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
@@ -1216,15 +1223,14 @@ class mod_quiz_renderer extends plugin_renderer_base {
|
||||
* Returns the same as {@link quiz_num_attempt_summary()} but wrapped in a link
|
||||
* to the quiz reports.
|
||||
*
|
||||
* @param object $quiz the quiz object. Only $quiz->id is used at the moment.
|
||||
* @param object $cm the cm object. Only $cm->course, $cm->groupmode and $cm->groupingid
|
||||
* @param stdClass $quiz the quiz object. Only $quiz->id is used at the moment.
|
||||
* @param stdClass $cm the cm object. Only $cm->course, $cm->groupmode and $cm->groupingid
|
||||
* fields are used at the moment.
|
||||
* @param object $context the quiz context.
|
||||
* @param context $context the quiz context.
|
||||
* @param bool $returnzero if false (default), when no attempts have been made '' is returned
|
||||
* instead of 'Attempts: 0'.
|
||||
* instead of 'Attempts: 0'.
|
||||
* @param int $currentgroup if there is a concept of current group where this method is being
|
||||
* called
|
||||
* (e.g. a report) pass it in here. Default 0 which means no current group.
|
||||
* called (e.g. a report) pass it in here. Default 0 which means no current group.
|
||||
* @return string HTML fragment for the link.
|
||||
*/
|
||||
public function quiz_attempt_summary_link_to_reports($quiz, $cm, $context,
|
||||
@@ -1241,6 +1247,49 @@ class mod_quiz_renderer extends plugin_renderer_base {
|
||||
return html_writer::link($url, $summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a summary of the number of group and user overrides, with corresponding links.
|
||||
*
|
||||
* @param stdClass $quiz the quiz settings.
|
||||
* @param stdClass|cm_info $cm the cm object.
|
||||
* @param int $currentgroup currently selected group, if there is one.
|
||||
* @return string HTML fragment for the link.
|
||||
*/
|
||||
public function quiz_override_summary_links(stdClass $quiz, stdClass $cm, $currentgroup = 0): string {
|
||||
|
||||
$baseurl = new moodle_url('/mod/quiz/overrides.php', ['cmid' => $cm->id]);
|
||||
$counts = quiz_override_summary($quiz, $cm, $currentgroup);
|
||||
|
||||
$links = [];
|
||||
if ($counts['group']) {
|
||||
$links[] = html_writer::link(new moodle_url($baseurl, ['mode' => 'group']),
|
||||
get_string('overridessummarygroup', 'quiz', $counts['group']));
|
||||
}
|
||||
if ($counts['user']) {
|
||||
$links[] = html_writer::link(new moodle_url($baseurl, ['mode' => 'user']),
|
||||
get_string('overridessummaryuser', 'quiz', $counts['user']));
|
||||
}
|
||||
|
||||
if (!$links) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$links = implode(', ', $links);
|
||||
switch ($counts['mode']) {
|
||||
case 'onegroup':
|
||||
return get_string('overridessummarythisgroup', 'quiz', $links);
|
||||
|
||||
case 'somegroups':
|
||||
return get_string('overridessummaryyourgroups', 'quiz', $links);
|
||||
|
||||
case 'allgroups':
|
||||
return get_string('overridessummary', 'quiz', $links);
|
||||
|
||||
default:
|
||||
throw new coding_exception('Unexpected mode ' . $counts['mode']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs a chart.
|
||||
*
|
||||
|
||||
@@ -82,8 +82,10 @@ Feature: Quiz group override
|
||||
| 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
|
||||
When I am on the "Test quiz" "mod_quiz > View" page logged in as "teacher1"
|
||||
Then I should see "Settings overrides exist (Groups: 2)"
|
||||
And I follow "Groups: 2"
|
||||
And "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"
|
||||
@@ -94,7 +96,9 @@ Feature: Quiz group override
|
||||
| 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"
|
||||
When I am on the "Test quiz" "mod_quiz > View" page logged in as "teacher1"
|
||||
Then I should see "Settings overrides exist (Groups: 1) for your groups"
|
||||
And I follow "Groups: 1"
|
||||
Then "Group 1" "table_row" should exist
|
||||
And "Group 2" "table_row" should not exist
|
||||
|
||||
|
||||
@@ -121,3 +121,5 @@ Feature: Quiz user override
|
||||
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"
|
||||
And I am on the "Test quiz" "mod_quiz > View" page
|
||||
And I should see "Settings overrides exist (Users: 2)"
|
||||
|
||||
@@ -839,4 +839,106 @@ class mod_quiz_locallib_testcase extends advanced_testcase {
|
||||
|
||||
$this->assertEquals($formattedexptected, $actual);
|
||||
}
|
||||
|
||||
public function test_quiz_override_summary() {
|
||||
global $DB, $PAGE;
|
||||
$this->resetAfterTest();
|
||||
$generator = $this->getDataGenerator();
|
||||
/** @var mod_quiz_generator $quizgenerator */
|
||||
$quizgenerator = $generator->get_plugin_generator('mod_quiz');
|
||||
/** @var mod_quiz_renderer $renderer */
|
||||
$renderer = $PAGE->get_renderer('mod_quiz');
|
||||
|
||||
// Course with quiz and a group - plus some others, to verify they don't get counted.
|
||||
$course = $generator->create_course();
|
||||
$quiz = $quizgenerator->create_instance(['course' => $course->id, 'groupmode' => SEPARATEGROUPS]);
|
||||
$cm = get_coursemodule_from_id('quiz', $quiz->cmid, $course->id);
|
||||
$group = $generator->create_group(['courseid' => $course->id]);
|
||||
$othergroup = $generator->create_group(['courseid' => $course->id]);
|
||||
$otherquiz = $quizgenerator->create_instance(['course' => $course->id]);
|
||||
|
||||
// Initial test (as admin) with no data.
|
||||
$this->setAdminUser();
|
||||
$this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'allgroups'],
|
||||
quiz_override_summary($quiz, $cm));
|
||||
$this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'],
|
||||
quiz_override_summary($quiz, $cm, $group->id));
|
||||
|
||||
// Editing teacher.
|
||||
$teacher = $generator->create_user();
|
||||
$generator->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
|
||||
// Non-editing teacher.
|
||||
$tutor = $generator->create_user();
|
||||
$generator->enrol_user($tutor->id, $course->id, 'teacher');
|
||||
$generator->create_group_member(['userid' => $tutor->id, 'groupid' => $group->id]);
|
||||
|
||||
// Three students.
|
||||
$student1 = $generator->create_user();
|
||||
$generator->enrol_user($student1->id, $course->id, 'student');
|
||||
$generator->create_group_member(['userid' => $student1->id, 'groupid' => $group->id]);
|
||||
|
||||
$student2 = $generator->create_user();
|
||||
$generator->enrol_user($student2->id, $course->id, 'student');
|
||||
$generator->create_group_member(['userid' => $student2->id, 'groupid' => $othergroup->id]);
|
||||
|
||||
$student3 = $generator->create_user();
|
||||
$generator->enrol_user($student3->id, $course->id, 'student');
|
||||
|
||||
// Initial test now users exist, but before overrides.
|
||||
// Test as teacher.
|
||||
$this->setUser($teacher);
|
||||
$this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'allgroups'],
|
||||
quiz_override_summary($quiz, $cm));
|
||||
$this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'],
|
||||
quiz_override_summary($quiz, $cm, $group->id));
|
||||
|
||||
// Test as tutor.
|
||||
$this->setUser($tutor);
|
||||
$this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'somegroups'],
|
||||
quiz_override_summary($quiz, $cm));
|
||||
$this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'],
|
||||
quiz_override_summary($quiz, $cm, $group->id));
|
||||
$this->assertEquals('', $renderer->quiz_override_summary_links($quiz, $cm));
|
||||
|
||||
// Quiz setting overrides for students 1 and 3.
|
||||
$quizgenerator->create_override(['quiz' => $quiz->id, 'userid' => $student1->id, 'attempts' => 2]);
|
||||
$quizgenerator->create_override(['quiz' => $quiz->id, 'userid' => $student3->id, 'attempts' => 2]);
|
||||
$quizgenerator->create_override(['quiz' => $quiz->id, 'groupid' => $group->id, 'attempts' => 3]);
|
||||
$quizgenerator->create_override(['quiz' => $quiz->id, 'groupid' => $othergroup->id, 'attempts' => 3]);
|
||||
$quizgenerator->create_override(['quiz' => $otherquiz->id, 'userid' => $student2->id, 'attempts' => 2]);
|
||||
|
||||
// Test as teacher.
|
||||
$this->setUser($teacher);
|
||||
$this->assertEquals(['group' => 2, 'user' => 2, 'mode' => 'allgroups'],
|
||||
quiz_override_summary($quiz, $cm));
|
||||
$this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)',
|
||||
// Links checked by Behat, so strip them for these tests.
|
||||
html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
|
||||
$this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'onegroup'],
|
||||
quiz_override_summary($quiz, $cm, $group->id));
|
||||
$this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for this group',
|
||||
html_to_text($renderer->quiz_override_summary_links($quiz, $cm, $group->id), 0, false));
|
||||
|
||||
// Test as tutor.
|
||||
$this->setUser($tutor);
|
||||
$this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'somegroups'],
|
||||
quiz_override_summary($quiz, $cm));
|
||||
$this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for your groups',
|
||||
html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
|
||||
$this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'onegroup'],
|
||||
quiz_override_summary($quiz, $cm, $group->id));
|
||||
$this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for this group',
|
||||
html_to_text($renderer->quiz_override_summary_links($quiz, $cm, $group->id), 0, false));
|
||||
|
||||
// Now set the quiz to be group mode: no groups, and re-test as tutor.
|
||||
// In this case, the tutor should see all groups.
|
||||
$DB->set_field('course_modules', 'groupmode', NOGROUPS, ['id' => $cm->id]);
|
||||
$cm = get_coursemodule_from_id('quiz', $quiz->cmid, $course->id);
|
||||
|
||||
$this->assertEquals(['group' => 2, 'user' => 2, 'mode' => 'allgroups'],
|
||||
quiz_override_summary($quiz, $cm));
|
||||
$this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)',
|
||||
html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user