diff --git a/mod/quiz/override_form.php b/mod/quiz/override_form.php index 7aecec655e0..164e1082043 100644 --- a/mod/quiz/override_form.php +++ b/mod/quiz/override_form.php @@ -37,10 +37,10 @@ require_once($CFG->dirroot . '/mod/quiz/mod_form.php'); */ class quiz_override_form extends moodleform { - /** @var object course module object. */ + /** @var cm_info course module object. */ protected $cm; - /** @var object the quiz settings object. */ + /** @var stdClass the quiz settings object. */ protected $quiz; /** @var context the quiz context. */ @@ -73,8 +73,7 @@ class quiz_override_form extends moodleform { $this->groupid = empty($override->groupid) ? 0 : $override->groupid; $this->userid = empty($override->userid) ? 0 : $override->userid; - parent::__construct($submiturl, null, 'post'); - + parent::__construct($submiturl); } protected function definition() { @@ -123,37 +122,57 @@ class quiz_override_form extends moodleform { } } else { // User override. - // TODO Does not support custom user profile fields (MDL-70456). - $userfieldsapi = \core_user\fields::for_identity($this->context, false)->with_userpic()->with_name(); + $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] = $this->display_user_name($user, $extrauserfields); + $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. - $users = array(); - list($sort, $sortparams) = users_order_by_sql('u'); - if (!empty($sortparams)) { - throw new coding_exception('users_order_by_sql returned some query parameters. ' . - 'This is unexpected, and a problem because there is no way to pass these ' . - 'parameters to get_users_by_capability. See MDL-34657.'); - } // Get the list of appropriate users, depending on whether and how groups are used. - $userfields = $userfieldsapi->get_sql('u', false, '', 'userid', false)->selects; - if ($accessallgroups) { - $users = get_users_by_capability($this->context, 'mod/quiz:attempt', - $userfields, $sort); - } else if ($groups = groups_get_activity_allowed_groups($cm)) { - $users = get_users_by_capability($this->context, 'mod/quiz:attempt', - $userfields, $sort, '', '', array_keys($groups)); + $userfieldsql = $userfieldsapi->get_sql('u', true, '', '', false); + $capabilityjoin = get_with_capability_join($this->context, 'mod/quiz:attempt', 'u.id'); + list($sort, $sortparams) = users_order_by_sql('u', null, + $this->context, $userfieldsql->mappings); + + $groupjoin = ''; + $groupparams = []; + if (!$accessallgroups) { + $groups = groups_get_activity_allowed_groups($cm); + list($grouptest, $groupparams) = $DB->get_in_or_equal( + array_keys($groups), SQL_PARAMS_NAMED, 'grp'); + $groupjoin = "JOIN (SELECT DISTINCT userid + FROM {groups_members} + WHERE groupid $grouptest + ) gm ON gm.userid = u.id"; } + $capabilitywhere = ''; + if ($capabilityjoin->wheres) { + $capabilitywhere = 'AND ' . $capabilityjoin->wheres; + } + + $users = $DB->get_records_sql(" + SELECT $userfieldsql->selects + FROM {user} u + LEFT JOIN {quiz_overrides} existingoverride ON + existingoverride.userid = u.id AND existingoverride.quiz = :quizid + $capabilityjoin->joins + $groupjoin + $userfieldsql->joins + WHERE existingoverride.id IS NULL + $capabilitywhere + ORDER BY $sort + ", array_merge(['quizid' => $this->quiz->id], $capabilityjoin->params, + $groupparams, $userfieldsql->params, $sortparams)); + // Filter users based on any fixed restrictions (groups, profile). $info = new \core_availability\info_module($cm); $users = $info->filter_user_list($users); @@ -166,7 +185,7 @@ class quiz_override_form extends moodleform { $userchoices = []; foreach ($users as $id => $user) { - $userchoices[$id] = $this->display_user_name($user, $extrauserfields); + $userchoices[$id] = self::display_user_name($user, $extrauserfields); } unset($users); @@ -231,12 +250,17 @@ class quiz_override_form extends moodleform { * @param array $extrauserfields (identity fields in user table only from the user_fields API) * @return string User's name, with extra info, for display. */ - protected function display_user_name(stdClass $user, array $extrauserfields) { + 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) { @@ -245,7 +269,7 @@ class quiz_override_form extends moodleform { return $username; } - public function validation($data, $files) { + public function validation($data, $files): array { $errors = parent::validation($data, $files); $mform =& $this->_form; diff --git a/mod/quiz/overridedelete.php b/mod/quiz/overridedelete.php index 9188850d71f..2c675c551a6 100644 --- a/mod/quiz/overridedelete.php +++ b/mod/quiz/overridedelete.php @@ -96,21 +96,11 @@ if ($override->groupid) { $confirmstr = get_string("overridedeletegroupsure", "quiz", $group->name); } else { $user = $DB->get_record('user', ['id' => $override->userid]); + profile_load_custom_fields($user); - $username = fullname($user); - $namefields = []; - - // TODO Does not support custom user profile fields (MDL-70456). - foreach (\core_user\fields::for_identity($context, false)->get_required_fields() as $field) { - if (isset($user->$field) && $user->$field !== '') { - $namefields[] = s($user->$field); - } - } - if ($namefields) { - $username .= ' (' . implode(', ', $namefields) . ')'; - } - - $confirmstr = get_string('overridedeleteusersure', 'quiz', $username); + $confirmstr = get_string('overridedeleteusersure', 'quiz', + quiz_override_form::display_user_name($user, + \core_user\fields::get_identity_fields($context))); } echo $OUTPUT->confirm($confirmstr, $confirmurl, $cancelurl); diff --git a/mod/quiz/overrides.php b/mod/quiz/overrides.php index beba75a98b4..ab2d4b83e73 100644 --- a/mod/quiz/overrides.php +++ b/mod/quiz/overrides.php @@ -108,17 +108,16 @@ if ($groupmode) { // User overrides. $colclasses[] = 'colname'; $headers[] = get_string('user'); - // TODO Does not support custom user profile fields (MDL-70456). - $userfieldsapi = \core_user\fields::for_identity($context, false)->with_name()->with_userpic(); + $userfieldsapi = \core_user\fields::for_identity($context)->with_name()->with_userpic(); $extrauserfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]); + $userfieldssql = $userfieldsapi->get_sql('u', true, '', 'userid', false); foreach ($extrauserfields as $field) { $colclasses[] = 'col' . $field; $headers[] = \core_user\fields::get_display_name($field); } - list($sort, $params) = users_order_by_sql('u'); + list($sort, $params) = users_order_by_sql('u', null, $context, $extrauserfields); $params['quizid'] = $quiz->id; - $userfields = $userfieldsapi->get_sql('u', true, '', 'userid', false)->selects; if ($showallgroups) { $groupsjoin = ''; @@ -137,14 +136,15 @@ if ($groupmode) { } $overrides = $DB->get_records_sql(" - SELECT o.*, $userfields + SELECT o.*, {$userfieldssql->selects} FROM {quiz_overrides} o JOIN {user} u ON o.userid = u.id + {$userfieldssql->joins} $groupsjoin WHERE o.quiz = :quizid $groupswhere ORDER BY $sort - ", $params); + ", array_merge($params, $userfieldssql->params)); } // Initialise table. diff --git a/mod/quiz/tests/behat/quiz_user_override.feature b/mod/quiz/tests/behat/quiz_user_override.feature index 9e4c7b701b9..15d3bcd34c4 100644 --- a/mod/quiz/tests/behat/quiz_user_override.feature +++ b/mod/quiz/tests/behat/quiz_user_override.feature @@ -5,12 +5,16 @@ Feature: Quiz user override I need to create an override for that user. Background: + And the following "custom profile fields" exist: + | datatype | shortname | name | + | text | frog | Favourite frog | Given the following "users" exist: - | username | firstname | lastname | email | - | teacher | Teacher | One | teacher@example.com | - | helper | Exam | Helper | helper@example.com | - | student1 | Student | One | student1@example.com | - | student2 | Student | Two | student2@example.com | + | username | firstname | lastname | email | profile_field_frog | + | teacher | Teacher | One | teacher@example.com | | + | helper | Exam | Helper | helper@example.com | | + | student1 | Student | One | student1@example.com | yellow frog | + | student2 | Student | Two | student2@example.com | prince frog | + | student3 | Student | Three | student3@example.com | Kermit | And the following "courses" exist: | fullname | shortname | category | | Course 1 | C1 | 0 | @@ -20,6 +24,7 @@ Feature: Quiz user override | helper | C1 | teacher | | student1 | C1 | student | | student2 | C1 | student | + | student3 | C1 | student | @javascript Scenario: Add, modify then delete a user override @@ -152,3 +157,32 @@ Feature: Quiz user override 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)" + + @javascript + Scenario: Teachers can see user additional user identity information + Given the following config values are set as admin: + | showuseridentity | email,profile_field_frog | + And 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 | + When I am on the "Test quiz" "mod_quiz > User overrides" page logged in as "teacher" + Then I should see "yellow frog" in the "Student One" "table_row" + And I should see "prince frog" in the "Student Two" "table_row" + + And I press "Add user override" + And I expand the "Override user" autocomplete + And I should see "Kermit" + And I should not see "Student one" + And I should not see "Student two" + And I press "Cancel" + + And I click on "Edit" "link" in the "Student One" "table_row" + And I should see "Student One (student1@example.com, yellow frog)" + And I press "Cancel" + + And I click on "Delete" "link" in the "Student One" "table_row" + And I should see "Student One (student1@example.com, yellow frog)"