diff --git a/mod/quiz/classes/form/edit_override_form.php b/mod/quiz/classes/form/edit_override_form.php new file mode 100644 index 00000000000..7cbfcc76293 --- /dev/null +++ b/mod/quiz/classes/form/edit_override_form.php @@ -0,0 +1,297 @@ +. + +namespace mod_quiz\form; + +use cm_info; +use context; +use mod_quiz_mod_form; +use moodle_url; +use moodleform; +use stdClass; + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir . '/formslib.php'); +require_once($CFG->dirroot . '/mod/quiz/mod_form.php'); + +/** + * Form for editing quiz settings overrides. + * + * @package mod_quiz + * @copyright 2010 Matt Petro + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class edit_override_form extends moodleform { + + /** @var cm_info course module object. */ + protected $cm; + + /** @var stdClass the quiz settings object. */ + protected $quiz; + + /** @var context the quiz context. */ + protected $context; + + /** @var bool editing group override (true) or user override (false). */ + protected $groupmode; + + /** @var int groupid, if provided. */ + protected $groupid; + + /** @var int userid, if provided. */ + protected $userid; + + /** + * Constructor. + * @param moodle_url $submiturl the form action URL. + * @param object course module object. + * @param object the quiz settings object. + * @param context the quiz context. + * @param bool editing group override (true) or user override (false). + * @param object $override the override being edited, if it already exists. + */ + public function __construct($submiturl, $cm, $quiz, $context, $groupmode, $override) { + + $this->cm = $cm; + $this->quiz = $quiz; + $this->context = $context; + $this->groupmode = $groupmode; + $this->groupid = empty($override->groupid) ? 0 : $override->groupid; + $this->userid = empty($override->userid) ? 0 : $override->userid; + + parent::__construct($submiturl); + } + + protected function definition() { + global $DB; + + $cm = $this->cm; + $mform = $this->_form; + + $mform->addElement('header', 'override', get_string('override', 'quiz')); + + $quizgroupmode = groups_get_activity_groupmode($cm); + $accessallgroups = ($quizgroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context); + + if ($this->groupmode) { + // Group override. + if ($this->groupid) { + // There is already a groupid, so freeze the selector. + $groupchoices = array(); + $groupchoices[$this->groupid] = groups_get_group_name($this->groupid); + $mform->addElement('select', 'groupid', + get_string('overridegroup', 'quiz'), $groupchoices); + $mform->freeze('groupid'); + } else { + // Prepare the list of groups. + // Only include the groups the current can access. + $groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm); + if (empty($groups)) { + // Generate an error. + $link = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id)); + throw new \moodle_exception('groupsnone', 'quiz', $link); + } + + $groupchoices = array(); + foreach ($groups as $group) { + $groupchoices[$group->id] = $group->name; + } + unset($groups); + + if (count($groupchoices) == 0) { + $groupchoices[0] = get_string('none'); + } + + $mform->addElement('select', 'groupid', + get_string('overridegroup', 'quiz'), $groupchoices); + $mform->addRule('groupid', get_string('required'), 'required', null, 'client'); + } + } else { + // User override. + $userfieldsapi = \core_user\fields::for_identity($this->context)->with_userpic()->with_name(); + $extrauserfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]); + if ($this->userid) { + // There is already a userid, so freeze the selector. + $user = $DB->get_record('user', ['id' => $this->userid]); + profile_load_custom_fields($user); + $userchoices = array(); + $userchoices[$this->userid] = self::display_user_name($user, $extrauserfields); + $mform->addElement('select', 'userid', + get_string('overrideuser', 'quiz'), $userchoices); + $mform->freeze('userid'); + } else { + // Prepare the list of users. + $groupids = 0; + if (!$accessallgroups) { + $groups = groups_get_activity_allowed_groups($cm); + $groupids = array_keys($groups); + } + $enrolledjoin = get_enrolled_with_capabilities_join( + $this->context, '', 'mod/quiz:attempt', $groupids, true); + $userfieldsql = $userfieldsapi->get_sql('u', true, '', '', false); + list($sort, $sortparams) = users_order_by_sql('u', null, + $this->context, $userfieldsql->mappings); + + $users = $DB->get_records_sql(" + SELECT $userfieldsql->selects + FROM {user} u + $enrolledjoin->joins + $userfieldsql->joins + LEFT JOIN {quiz_overrides} existingoverride ON + existingoverride.userid = u.id AND existingoverride.quiz = :quizid + WHERE existingoverride.id IS NULL + AND $enrolledjoin->wheres + ORDER BY $sort + ", array_merge(['quizid' => $this->quiz->id], $userfieldsql->params, $enrolledjoin->params, $sortparams)); + + // Filter users based on any fixed restrictions (groups, profile). + $info = new \core_availability\info_module($cm); + $users = $info->filter_user_list($users); + + if (empty($users)) { + // Generate an error. + $link = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id)); + throw new \moodle_exception('usersnone', 'quiz', $link); + } + + $userchoices = []; + foreach ($users as $id => $user) { + $userchoices[$id] = self::display_user_name($user, $extrauserfields); + } + unset($users); + + $mform->addElement('searchableselector', 'userid', + get_string('overrideuser', 'quiz'), $userchoices); + $mform->addRule('userid', get_string('required'), 'required', null, 'client'); + } + } + + // Password. + // This field has to be above the date and timelimit fields, + // otherwise browsers will clear it when those fields are changed. + $mform->addElement('passwordunmask', 'password', get_string('requirepassword', 'quiz')); + $mform->setType('password', PARAM_TEXT); + $mform->addHelpButton('password', 'requirepassword', 'quiz'); + $mform->setDefault('password', $this->quiz->password); + + // Open and close dates. + $mform->addElement('date_time_selector', 'timeopen', + get_string('quizopen', 'quiz'), mod_quiz_mod_form::$datefieldoptions); + $mform->setDefault('timeopen', $this->quiz->timeopen); + + $mform->addElement('date_time_selector', 'timeclose', + get_string('quizclose', 'quiz'), mod_quiz_mod_form::$datefieldoptions); + $mform->setDefault('timeclose', $this->quiz->timeclose); + + // Time limit. + $mform->addElement('duration', 'timelimit', + get_string('timelimit', 'quiz'), array('optional' => true)); + $mform->addHelpButton('timelimit', 'timelimit', 'quiz'); + $mform->setDefault('timelimit', $this->quiz->timelimit); + + // Number of attempts. + $attemptoptions = array('0' => get_string('unlimited')); + for ($i = 1; $i <= QUIZ_MAX_ATTEMPT_OPTION; $i++) { + $attemptoptions[$i] = $i; + } + $mform->addElement('select', 'attempts', + get_string('attemptsallowed', 'quiz'), $attemptoptions); + $mform->addHelpButton('attempts', 'attempts', 'quiz'); + $mform->setDefault('attempts', $this->quiz->attempts); + + // Submit buttons. + $mform->addElement('submit', 'resetbutton', + get_string('reverttodefaults', 'quiz')); + + $buttonarray = array(); + $buttonarray[] = $mform->createElement('submit', 'submitbutton', + get_string('save', 'quiz')); + $buttonarray[] = $mform->createElement('submit', 'againbutton', + get_string('saveoverrideandstay', 'quiz')); + $buttonarray[] = $mform->createElement('cancel'); + + $mform->addGroup($buttonarray, 'buttonbar', '', array(' '), false); + $mform->closeHeaderBefore('buttonbar'); + } + + /** + * Get a user's name and identity ready to display. + * + * @param stdClass $user a user object. + * @param array $extrauserfields (identity fields in user table only from the user_fields API) + * @return string User's name, with extra info, for display. + */ + public static function display_user_name(stdClass $user, array $extrauserfields): string { + $username = fullname($user); + $namefields = []; + foreach ($extrauserfields as $field) { + if (isset($user->$field) && $user->$field !== '') { + $namefields[] = s($user->$field); + } else if (strpos($field, 'profile_field_') === 0) { + $field = substr($field, 14); + if (isset($user->profile[$field]) && $user->profile[$field] !== '') { + $namefields[] = s($user->profile[$field]); + } + } + } + if ($namefields) { + $username .= ' (' . implode(', ', $namefields) . ')'; + } + return $username; + } + + public function validation($data, $files): array { + $errors = parent::validation($data, $files); + + $mform =& $this->_form; + $quiz = $this->quiz; + + if ($mform->elementExists('userid')) { + if (empty($data['userid'])) { + $errors['userid'] = get_string('required'); + } + } + + if ($mform->elementExists('groupid')) { + if (empty($data['groupid'])) { + $errors['groupid'] = get_string('required'); + } + } + + // Ensure that the dates make sense. + if (!empty($data['timeopen']) && !empty($data['timeclose'])) { + if ($data['timeclose'] < $data['timeopen'] ) { + $errors['timeclose'] = get_string('closebeforeopen', 'quiz'); + } + } + + // Ensure that at least one quiz setting was changed. + $changed = false; + $keys = array('timeopen', 'timeclose', 'timelimit', 'attempts', 'password'); + foreach ($keys as $key) { + if ($data[$key] != $quiz->{$key}) { + $changed = true; + break; + } + } + if (!$changed) { + $errors['timeopen'] = get_string('nooverridedata', 'quiz'); + } + + return $errors; + } +} diff --git a/mod/quiz/db/renamedclasses.php b/mod/quiz/db/renamedclasses.php index 7256a8b8890..d6b3086aa07 100644 --- a/mod/quiz/db/renamedclasses.php +++ b/mod/quiz/db/renamedclasses.php @@ -53,4 +53,5 @@ $renamedclasses = [ 'quiz_attempts_report_table' => 'mod_quiz\local\reports\attempts_report_table', 'quiz_access_manager' => 'mod_quiz\access_manager', 'mod_quiz_preflight_check_form' => 'mod_quiz\form\preflight_check_form', + 'quiz_override_form' => 'mod_quiz\form\edit_override_form', ]; diff --git a/mod/quiz/override_form.php b/mod/quiz/override_form.php index 04f33033bbf..4fcf92cd630 100644 --- a/mod/quiz/override_form.php +++ b/mod/quiz/override_form.php @@ -20,278 +20,10 @@ * @package mod_quiz * @copyright 2010 Matt Petro * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @todo MDL-76612 delete this file as part of Moodle 4.6 development. + * @deprecated This file is no longer required in Moodle 4.2+. */ - defined('MOODLE_INTERNAL') || die(); -require_once($CFG->libdir . '/formslib.php'); -require_once($CFG->dirroot . '/mod/quiz/mod_form.php'); - - -/** - * Form for editing settings overrides. - * - * @copyright 2010 Matt Petro - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class quiz_override_form extends moodleform { - - /** @var cm_info course module object. */ - protected $cm; - - /** @var stdClass the quiz settings object. */ - protected $quiz; - - /** @var context the quiz context. */ - protected $context; - - /** @var bool editing group override (true) or user override (false). */ - protected $groupmode; - - /** @var int groupid, if provided. */ - protected $groupid; - - /** @var int userid, if provided. */ - protected $userid; - - /** - * Constructor. - * @param moodle_url $submiturl the form action URL. - * @param object course module object. - * @param object the quiz settings object. - * @param context the quiz context. - * @param bool editing group override (true) or user override (false). - * @param object $override the override being edited, if it already exists. - */ - public function __construct($submiturl, $cm, $quiz, $context, $groupmode, $override) { - - $this->cm = $cm; - $this->quiz = $quiz; - $this->context = $context; - $this->groupmode = $groupmode; - $this->groupid = empty($override->groupid) ? 0 : $override->groupid; - $this->userid = empty($override->userid) ? 0 : $override->userid; - - parent::__construct($submiturl); - } - - protected function definition() { - global $DB; - - $cm = $this->cm; - $mform = $this->_form; - - $mform->addElement('header', 'override', get_string('override', 'quiz')); - - $quizgroupmode = groups_get_activity_groupmode($cm); - $accessallgroups = ($quizgroupmode == NOGROUPS) || has_capability('moodle/site:accessallgroups', $this->context); - - if ($this->groupmode) { - // Group override. - if ($this->groupid) { - // There is already a groupid, so freeze the selector. - $groupchoices = array(); - $groupchoices[$this->groupid] = groups_get_group_name($this->groupid); - $mform->addElement('select', 'groupid', - get_string('overridegroup', 'quiz'), $groupchoices); - $mform->freeze('groupid'); - } else { - // Prepare the list of groups. - // Only include the groups the current can access. - $groups = $accessallgroups ? groups_get_all_groups($cm->course) : groups_get_activity_allowed_groups($cm); - if (empty($groups)) { - // Generate an error. - $link = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id)); - throw new \moodle_exception('groupsnone', 'quiz', $link); - } - - $groupchoices = array(); - foreach ($groups as $group) { - $groupchoices[$group->id] = $group->name; - } - unset($groups); - - if (count($groupchoices) == 0) { - $groupchoices[0] = get_string('none'); - } - - $mform->addElement('select', 'groupid', - get_string('overridegroup', 'quiz'), $groupchoices); - $mform->addRule('groupid', get_string('required'), 'required', null, 'client'); - } - } else { - // User override. - $userfieldsapi = \core_user\fields::for_identity($this->context)->with_userpic()->with_name(); - $extrauserfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]); - if ($this->userid) { - // There is already a userid, so freeze the selector. - $user = $DB->get_record('user', ['id' => $this->userid]); - profile_load_custom_fields($user); - $userchoices = array(); - $userchoices[$this->userid] = self::display_user_name($user, $extrauserfields); - $mform->addElement('select', 'userid', - get_string('overrideuser', 'quiz'), $userchoices); - $mform->freeze('userid'); - } else { - // Prepare the list of users. - $groupids = 0; - if (!$accessallgroups) { - $groups = groups_get_activity_allowed_groups($cm); - $groupids = array_keys($groups); - } - $enrolledjoin = get_enrolled_with_capabilities_join( - $this->context, '', 'mod/quiz:attempt', $groupids, true); - $userfieldsql = $userfieldsapi->get_sql('u', true, '', '', false); - list($sort, $sortparams) = users_order_by_sql('u', null, - $this->context, $userfieldsql->mappings); - - $users = $DB->get_records_sql(" - SELECT $userfieldsql->selects - FROM {user} u - $enrolledjoin->joins - $userfieldsql->joins - LEFT JOIN {quiz_overrides} existingoverride ON - existingoverride.userid = u.id AND existingoverride.quiz = :quizid - WHERE existingoverride.id IS NULL - AND $enrolledjoin->wheres - ORDER BY $sort - ", array_merge(['quizid' => $this->quiz->id], $userfieldsql->params, $enrolledjoin->params, $sortparams)); - - // Filter users based on any fixed restrictions (groups, profile). - $info = new \core_availability\info_module($cm); - $users = $info->filter_user_list($users); - - if (empty($users)) { - // Generate an error. - $link = new moodle_url('/mod/quiz/overrides.php', array('cmid'=>$cm->id)); - throw new \moodle_exception('usersnone', 'quiz', $link); - } - - $userchoices = []; - foreach ($users as $id => $user) { - $userchoices[$id] = self::display_user_name($user, $extrauserfields); - } - unset($users); - - $mform->addElement('searchableselector', 'userid', - get_string('overrideuser', 'quiz'), $userchoices); - $mform->addRule('userid', get_string('required'), 'required', null, 'client'); - } - } - - // Password. - // This field has to be above the date and timelimit fields, - // otherwise browsers will clear it when those fields are changed. - $mform->addElement('passwordunmask', 'password', get_string('requirepassword', 'quiz')); - $mform->setType('password', PARAM_TEXT); - $mform->addHelpButton('password', 'requirepassword', 'quiz'); - $mform->setDefault('password', $this->quiz->password); - - // Open and close dates. - $mform->addElement('date_time_selector', 'timeopen', - get_string('quizopen', 'quiz'), mod_quiz_mod_form::$datefieldoptions); - $mform->setDefault('timeopen', $this->quiz->timeopen); - - $mform->addElement('date_time_selector', 'timeclose', - get_string('quizclose', 'quiz'), mod_quiz_mod_form::$datefieldoptions); - $mform->setDefault('timeclose', $this->quiz->timeclose); - - // Time limit. - $mform->addElement('duration', 'timelimit', - get_string('timelimit', 'quiz'), array('optional' => true)); - $mform->addHelpButton('timelimit', 'timelimit', 'quiz'); - $mform->setDefault('timelimit', $this->quiz->timelimit); - - // Number of attempts. - $attemptoptions = array('0' => get_string('unlimited')); - for ($i = 1; $i <= QUIZ_MAX_ATTEMPT_OPTION; $i++) { - $attemptoptions[$i] = $i; - } - $mform->addElement('select', 'attempts', - get_string('attemptsallowed', 'quiz'), $attemptoptions); - $mform->addHelpButton('attempts', 'attempts', 'quiz'); - $mform->setDefault('attempts', $this->quiz->attempts); - - // Submit buttons. - $mform->addElement('submit', 'resetbutton', - get_string('reverttodefaults', 'quiz')); - - $buttonarray = array(); - $buttonarray[] = $mform->createElement('submit', 'submitbutton', - get_string('save', 'quiz')); - $buttonarray[] = $mform->createElement('submit', 'againbutton', - get_string('saveoverrideandstay', 'quiz')); - $buttonarray[] = $mform->createElement('cancel'); - - $mform->addGroup($buttonarray, 'buttonbar', '', array(' '), false); - $mform->closeHeaderBefore('buttonbar'); - } - - /** - * Get a user's name and identity ready to display. - * - * @param stdClass $user a user object. - * @param array $extrauserfields (identity fields in user table only from the user_fields API) - * @return string User's name, with extra info, for display. - */ - public static function display_user_name(stdClass $user, array $extrauserfields): string { - $username = fullname($user); - $namefields = []; - foreach ($extrauserfields as $field) { - if (isset($user->$field) && $user->$field !== '') { - $namefields[] = s($user->$field); - } else if (strpos($field, 'profile_field_') === 0) { - $field = substr($field, 14); - if (isset($user->profile[$field]) && $user->profile[$field] !== '') { - $namefields[] = s($user->profile[$field]); - } - } - } - if ($namefields) { - $username .= ' (' . implode(', ', $namefields) . ')'; - } - return $username; - } - - public function validation($data, $files): array { - $errors = parent::validation($data, $files); - - $mform =& $this->_form; - $quiz = $this->quiz; - - if ($mform->elementExists('userid')) { - if (empty($data['userid'])) { - $errors['userid'] = get_string('required'); - } - } - - if ($mform->elementExists('groupid')) { - if (empty($data['groupid'])) { - $errors['groupid'] = get_string('required'); - } - } - - // Ensure that the dates make sense. - if (!empty($data['timeopen']) && !empty($data['timeclose'])) { - if ($data['timeclose'] < $data['timeopen'] ) { - $errors['timeclose'] = get_string('closebeforeopen', 'quiz'); - } - } - - // Ensure that at least one quiz setting was changed. - $changed = false; - $keys = array('timeopen', 'timeclose', 'timelimit', 'attempts', 'password'); - foreach ($keys as $key) { - if ($data[$key] != $quiz->{$key}) { - $changed = true; - break; - } - } - if (!$changed) { - $errors['timeopen'] = get_string('nooverridedata', 'quiz'); - } - - return $errors; - } -} +debugging('This file is no longer required in Moodle 4.2+. Please do not include/require it.', DEBUG_DEVELOPER); diff --git a/mod/quiz/overridedelete.php b/mod/quiz/overridedelete.php index 117ab70fafc..fab6698ac3d 100644 --- a/mod/quiz/overridedelete.php +++ b/mod/quiz/overridedelete.php @@ -22,11 +22,11 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use mod_quiz\form\edit_override_form; require_once(__DIR__ . '/../../config.php'); require_once($CFG->dirroot.'/mod/quiz/lib.php'); require_once($CFG->dirroot.'/mod/quiz/locallib.php'); -require_once($CFG->dirroot.'/mod/quiz/override_form.php'); $overrideid = required_param('id', PARAM_INT); $confirm = optional_param('confirm', false, PARAM_BOOL); @@ -103,7 +103,7 @@ if ($override->groupid) { profile_load_custom_fields($user); $confirmstr = get_string('overridedeleteusersure', 'quiz', - quiz_override_form::display_user_name($user, + edit_override_form::display_user_name($user, \core_user\fields::get_identity_fields($context))); } diff --git a/mod/quiz/overrideedit.php b/mod/quiz/overrideedit.php index 3450be23ee5..d8e419d8bdc 100644 --- a/mod/quiz/overrideedit.php +++ b/mod/quiz/overrideedit.php @@ -22,12 +22,11 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +use mod_quiz\form\edit_override_form; require_once(__DIR__ . '/../../config.php'); require_once($CFG->dirroot.'/mod/quiz/lib.php'); require_once($CFG->dirroot.'/mod/quiz/locallib.php'); -require_once($CFG->dirroot.'/mod/quiz/override_form.php'); - $cmid = optional_param('cmid', 0, PARAM_INT); $overrideid = optional_param('id', 0, PARAM_INT); @@ -119,7 +118,7 @@ if (!$groupmode) { } // Setup the form. -$mform = new quiz_override_form($url, $cm, $quiz, $context, $groupmode, $override); +$mform = new edit_override_form($url, $cm, $quiz, $context, $groupmode, $override); $mform->set_data($data); if ($mform->is_cancelled()) { diff --git a/mod/quiz/overrides.php b/mod/quiz/overrides.php index d419a0d2410..8bb12c6ab58 100644 --- a/mod/quiz/overrides.php +++ b/mod/quiz/overrides.php @@ -25,8 +25,6 @@ require_once(__DIR__ . '/../../config.php'); require_once($CFG->dirroot.'/mod/quiz/lib.php'); require_once($CFG->dirroot.'/mod/quiz/locallib.php'); -require_once($CFG->dirroot.'/mod/quiz/override_form.php'); - $cmid = required_param('cmid', PARAM_INT); $mode = optional_param('mode', '', PARAM_ALPHA); // One of 'user' or 'group', default is 'group'. diff --git a/mod/quiz/upgrade.txt b/mod/quiz/upgrade.txt index aaf2da397f7..f80bbfd341a 100644 --- a/mod/quiz/upgrade.txt +++ b/mod/quiz/upgrade.txt @@ -37,6 +37,7 @@ This files describes API changes in the quiz code. - quiz_attempts_report_table => mod_quiz\local\reports\attempts_report_table - quiz_access_manager => mod_quiz\access_manager - mod_quiz_preflight_check_form => mod_quiz\form\preflight_check_form + - quiz_override_form => mod_quiz\form\edit_override_form * The following classes have been deprecated: - mod_quiz_overdue_attempt_updater - merged into mod_quiz\task\update_overdue_attempts @@ -52,6 +53,7 @@ This files describes API changes in the quiz code. - mod/quiz/accessmanager.php - mod/quiz/accessmanager_form.php - mod/quiz/cronlib.php + - mod/quiz/override_form.php === 4.1 ===