MDL-45242 Course: Enrol feature supports custom profile fields

This commit is contained in:
sam marshall 2020-10-21 18:44:10 +01:00
parent e86ead1d91
commit 987e55452f
18 changed files with 482 additions and 160 deletions

View File

@ -88,7 +88,8 @@ class award_criteria_profile extends award_criteria {
if (in_array($field, $existing)) {
$checked = true;
}
$this->config_options($mform, array('id' => $field, 'checked' => $checked, 'name' => \core\user_fields::get_display_name($field), 'error' => false));
$this->config_options($mform, array('id' => $field, 'checked' => $checked,
'name' => \core\user_fields::get_display_name($field), 'error' => false));
$none = false;
}
}

View File

@ -558,10 +558,20 @@ class core_enrol_external extends external_api {
$results = array();
// Add also extra user fields.
$identityfields = \core\user_fields::get_identity_fields($context, true);
$customprofilefields = [];
foreach ($identityfields as $key => $value) {
if ($fieldname = \core\user_fields::match_custom_field($value)) {
unset($identityfields[$key]);
$customprofilefields[$fieldname] = true;
}
}
if ($customprofilefields) {
$identityfields[] = 'customfields';
}
$requiredfields = array_merge(
['id', 'fullname', 'profileimageurl', 'profileimageurlsmall'],
// TODO Does not support custom user profile fields (MDL-70456).
\core\user_fields::get_identity_fields($context, false)
$identityfields
);
foreach ($users['users'] as $id => $user) {
// Note: We pass the course here to validate that the current user can at least view user details in this course.
@ -569,6 +579,15 @@ class core_enrol_external extends external_api {
// user records, and the user has been validated to have course:enrolreview in this course. Otherwise
// there is no way to find users who aren't in the course in order to enrol them.
if ($userdetails = user_get_user_details($user, $course, $requiredfields)) {
// For custom fields, only return the ones we actually need.
if ($customprofilefields && array_key_exists('customfields', $userdetails)) {
foreach ($userdetails['customfields'] as $key => $data) {
if (!array_key_exists($data['shortname'], $customprofilefields)) {
unset($userdetails['customfields'][$key]);
}
}
$userdetails['customfields'] = array_values($userdetails['customfields']);
}
$results[] = $userdetails;
}
}

View File

@ -23,6 +23,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core\user_fields;
defined('MOODLE_INTERNAL') || die();
/**
@ -238,14 +240,15 @@ class course_enrolment_manager {
list($instancessql, $params, $filter) = $this->get_instance_sql();
list($filtersql, $moreparams) = $this->get_filter_sql();
$params += $moreparams;
// TODO Does not support custom user profile fields (MDL-70456).
$extrafields = \core\user_fields::get_identity_fields($this->get_context(), false);
$extrafields[] = 'lastaccess';
$ufields = user_picture::fields('u', $extrafields);
$sql = "SELECT DISTINCT $ufields, COALESCE(ul.timeaccess, 0) AS lastcourseaccess
$userfields = user_fields::for_identity($this->get_context())->with_userpic()->excluding('lastaccess');
['selects' => $fieldselect, 'joins' => $fieldjoin, 'params' => $fieldjoinparams] =
(array)$userfields->get_sql('u', true, '', '', false);
$params += $fieldjoinparams;
$sql = "SELECT DISTINCT $fieldselect, COALESCE(ul.timeaccess, 0) AS lastcourseaccess
FROM {user} u
JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid $instancessql)
JOIN {enrol} e ON (e.id = ue.enrolid)
$fieldjoin
LEFT JOIN {user_lastaccess} ul ON (ul.courseid = e.courseid AND ul.userid = u.id)";
if ($this->groupfilter) {
$sql .= " LEFT JOIN ({groups_members} gm JOIN {groups} g ON (g.id = gm.groupid))
@ -270,7 +273,7 @@ class course_enrolment_manager {
// Search condition.
// TODO Does not support custom user profile fields (MDL-70456).
$extrafields = \core\user_fields::get_identity_fields($this->get_context(), false);
$extrafields = user_fields::get_identity_fields($this->get_context(), false);
list($sql, $params) = users_search_sql($this->searchfilter, 'u', true, $extrafields);
// Role condition.
@ -343,23 +346,26 @@ class course_enrolment_manager {
list($ctxcondition, $params) = $DB->get_in_or_equal($this->context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'ctx');
$params['courseid'] = $this->course->id;
$params['cid'] = $this->course->id;
// TODO Does not support custom user profile fields (MDL-70456).
$extrafields = \core\user_fields::get_identity_fields($this->get_context(), false);
$ufields = user_picture::fields('u', $extrafields);
$sql = "SELECT ra.id as raid, ra.contextid, ra.component, ctx.contextlevel, ra.roleid, $ufields,
coalesce(u.lastaccess,0) AS lastaccess
FROM {role_assignments} ra
JOIN {user} u ON u.id = ra.userid
JOIN {context} ctx ON ra.contextid = ctx.id
LEFT JOIN (
$userfields = user_fields::for_identity($this->get_context())->with_userpic();
['selects' => $fieldselect, 'joins' => $fieldjoin, 'params' => $fieldjoinparams] =
(array)$userfields->get_sql('u', true);
$params += $fieldjoinparams;
$sql = "SELECT ra.id as raid, ra.contextid, ra.component, ctx.contextlevel, ra.roleid,
coalesce(u.lastaccess,0) AS lastaccess
$fieldselect
FROM {role_assignments} ra
JOIN {user} u ON u.id = ra.userid
JOIN {context} ctx ON ra.contextid = ctx.id
$fieldjoin
LEFT JOIN (
SELECT ue.id, ue.userid
FROM {user_enrolments} ue
JOIN {enrol} e ON e.id = ue.enrolid
WHERE e.courseid = :courseid
) ue ON ue.userid=u.id
WHERE ctx.id $ctxcondition AND
ue.id IS NULL
ORDER BY $sort $direction, ctx.depth DESC";
WHERE ctx.id $ctxcondition AND
ue.id IS NULL
ORDER BY $sort $direction, ctx.depth DESC";
$this->otherusers[$key] = $DB->get_records_sql($sql, $params, $page*$perpage, $perpage);
}
return $this->otherusers[$key];
@ -372,20 +378,33 @@ class course_enrolment_manager {
* @param bool $searchanywhere Can the search term be anywhere, or must it be at the start.
* @return array with three elements:
* string list of fields to SELECT,
* string possible database joins for user fields
* string contents of SQL WHERE clause,
* array query params. Note that the SQL snippets use named parameters.
*/
protected function get_basic_search_conditions($search, $searchanywhere) {
global $DB, $CFG;
// Get custom user field SQL used for querying all the fields we need (identity, name, and
// user picture).
$userfields = user_fields::for_identity($this->context)->with_name()->with_userpic()
->excluding('username', 'lastaccess', 'maildisplay');
['selects' => $fieldselects, 'joins' => $fieldjoins, 'params' => $params, 'mappings' => $mappings] =
(array)$userfields->get_sql('u', true, '', '', false);
// Searchable fields are only the identity and name ones (not userpic).
$searchable = array_fill_keys($userfields->get_required_fields(
[user_fields::PURPOSE_IDENTITY, user_fields::PURPOSE_NAME]), true);
// Add some additional sensible conditions
$tests = array("u.id <> :guestid", 'u.deleted = 0', 'u.confirmed = 1');
$params = array('guestid' => $CFG->siteguest);
$params['guestid'] = $CFG->siteguest;
if (!empty($search)) {
// TODO Does not support custom user profile fields (MDL-70456).
$conditions = \core\user_fields::get_identity_fields($this->get_context(), false);
foreach (\core\user_fields::get_name_fields() as $field) {
$conditions[] = 'u.'.$field;
// Include identity and name fields as conditions.
foreach ($mappings as $fieldname => $fieldsql) {
if (array_key_exists($fieldname, $searchable)) {
$conditions[] = $fieldsql;
}
}
$conditions[] = $DB->sql_fullname('u.firstname', 'u.lastname');
if ($searchanywhere) {
@ -403,15 +422,8 @@ class course_enrolment_manager {
}
$wherecondition = implode(' AND ', $tests);
// TODO Does not support custom user profile fields (MDL-70456).
$userfieldsapi = \core\user_fields::for_identity($this->get_context(), false)->excluding('username', 'lastaccess');
$extrafields = $userfieldsapi->get_required_fields();
$extrafields[] = 'username';
$extrafields[] = 'lastaccess';
$extrafields[] = 'maildisplay';
$ufields = user_picture::fields('u', $extrafields);
return array($ufields, $params, $wherecondition);
$selects = $fieldselects . ', u.username, u.lastaccess, u.maildisplay';
return [$selects, $fieldjoins, $params, $wherecondition];
}
/**
@ -492,11 +504,12 @@ class course_enrolment_manager {
$addedenrollment = 0, $returnexactcount = false) {
global $DB;
list($ufields, $params, $wherecondition) = $this->get_basic_search_conditions($search, $searchanywhere);
[$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere);
$fields = 'SELECT '.$ufields;
$countfields = 'SELECT COUNT(1)';
$sql = " FROM {user} u
$joins
LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = :enrolid)
WHERE $wherecondition
AND ue.id IS NULL";
@ -524,11 +537,12 @@ class course_enrolment_manager {
public function search_other_users($search = '', $searchanywhere = false, $page = 0, $perpage = 25, $returnexactcount = false) {
global $DB, $CFG;
list($ufields, $params, $wherecondition) = $this->get_basic_search_conditions($search, $searchanywhere);
[$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere);
$fields = 'SELECT ' . $ufields;
$countfields = 'SELECT COUNT(u.id)';
$sql = " FROM {user} u
$joins
LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.contextid = :contextid)
WHERE $wherecondition
AND ra.id IS NULL";
@ -552,11 +566,12 @@ class course_enrolment_manager {
*/
public function search_users(string $search = '', bool $searchanywhere = false, int $page = 0, int $perpage = 25,
bool $returnexactcount = false) {
list($ufields, $params, $wherecondition) = $this->get_basic_search_conditions($search, $searchanywhere);
[$ufields, $joins, $params, $wherecondition] = $this->get_basic_search_conditions($search, $searchanywhere);
$fields = 'SELECT ' . $ufields;
$countfields = 'SELECT COUNT(u.id)';
$sql = " FROM {user} u
$joins
JOIN {user_enrolments} ue ON ue.userid = u.id
JOIN {enrol} e ON ue.enrolid = e.id
WHERE $wherecondition
@ -1053,7 +1068,7 @@ class course_enrolment_manager {
$context = $this->get_context();
$now = time();
// TODO Does not support custom user profile fields (MDL-70456).
$extrafields = \core\user_fields::get_identity_fields($context, false);
$extrafields = user_fields::get_identity_fields($context, false);
$users = array();
foreach ($userroles as $userrole) {
@ -1132,7 +1147,7 @@ class course_enrolment_manager {
$url = new moodle_url($pageurl, $this->get_url_params());
// TODO Does not support custom user profile fields (MDL-70456).
$extrafields = \core\user_fields::get_identity_fields($context, false);
$extrafields = user_fields::get_identity_fields($context, false);
$enabledplugins = $this->get_enrolment_plugins(true);

View File

@ -1,2 +1,2 @@
define ("enrol_manual/form-potential-user-selector",["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){return{processResults:function processResults(b,c){var d=[];if(a.isArray(c)){a.each(c,function(a,b){d.push({value:b.id,label:b._label})});return d}else{return c}},transport:function transport(e,f,g,h){var i,j=a(e).attr("courseid"),k=a(e).attr("userfields").split(",");if("undefined"==typeof j){j="1"}var l=a(e).attr("enrolid");if("undefined"==typeof l){l=""}var m=parseInt(a(e).attr("perpage"));if(isNaN(m)){m=100}i=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:j,enrolid:l,search:f,searchanywhere:!0,page:0,perpage:m+1}}]);i[0].then(function(b){var e=[],f=0;if(b.length<=m){a.each(b,function(b,d){var f=d,g=[];a.each(k,function(a,b){if("undefined"!=typeof d[b]&&""!==d[b]){f.hasidentity=!0;g.push(d[b])}});f.identity=g.join(", ");e.push(c.render("enrol_manual/form-user-selector-suggestion",f))});return a.when.apply(a.when,e).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[f];f++});g(b)})}else{return d.get_string("toomanyuserstoshow","core",">"+m).then(function(a){g(a)})}}).fail(h)}}});
define ("enrol_manual/form-potential-user-selector",["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){return{processResults:function processResults(b,c){var d=[];if(a.isArray(c)){a.each(c,function(a,b){d.push({value:b.id,label:b._label})});return d}else{return c}},transport:function transport(e,f,g,h){var i,j=a(e).attr("courseid"),k=a(e).attr("userfields").split(",");if("undefined"==typeof j){j="1"}var l=a(e).attr("enrolid");if("undefined"==typeof l){l=""}var m=parseInt(a(e).attr("perpage"));if(isNaN(m)){m=100}i=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:j,enrolid:l,search:f,searchanywhere:!0,page:0,perpage:m+1}}]);i[0].then(function(b){var e=[],f=0;if(b.length<=m){a.each(b,function(b,d){var f=d,g=[];a.each(k,function(a,b){var c=/^profile_field_(.*)$/.exec(b);if(c){if(d.customfields){d.customfields.forEach(function(a){if(a.shortname===c[1]){f.hasidentity=!0;g.push(a.value)}})}}else{if("undefined"!=typeof d[b]&&""!==d[b]){f.hasidentity=!0;g.push(d[b])}}});f.identity=g.join(", ");e.push(c.render("enrol_manual/form-user-selector-suggestion",f))});return a.when.apply(a.when,e).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[f];f++});g(b)})}else{return d.get_string("toomanyuserstoshow","core",">"+m).then(function(a){g(a)})}}).fail(h)}}});
//# sourceMappingURL=form-potential-user-selector.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -77,13 +77,27 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
if (results.length <= perpage) {
// Render the label.
const profileRegex = /^profile_field_(.*)$/;
$.each(results, function(index, user) {
var ctx = user,
identity = [];
$.each(userfields, function(i, k) {
if (typeof user[k] !== 'undefined' && user[k] !== '') {
ctx.hasidentity = true;
identity.push(user[k]);
const result = profileRegex.exec(k);
if (result) {
if (user.customfields) {
user.customfields.forEach(function(customfield) {
if (customfield.shortname === result[1]) {
ctx.hasidentity = true;
identity.push(customfield.value);
}
});
}
} else {
if (typeof user[k] !== 'undefined' && user[k] !== '') {
ctx.hasidentity = true;
identity.push(user[k]);
}
}
});
ctx.identity = identity.join(', ');

View File

@ -93,8 +93,7 @@ class enrol_manual_enrol_users_form extends moodleform {
'courseid' => $course->id,
'enrolid' => $instance->id,
'perpage' => $CFG->maxusersperpage,
// TODO Does not support custom user profile fields (MDL-70456).
'userfields' => implode(',', \core\user_fields::get_identity_fields($context, false))
'userfields' => implode(',', \core\user_fields::get_identity_fields($context, true))
);
$mform->addElement('autocomplete', 'userlist', get_string('selectusers', 'enrol_manual'), array(), $options);

View File

@ -5,108 +5,111 @@ Feature: Teacher can search and enrol users one by one into the course
I can search for the students and enrol them into the course
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher001 | Teacher | 001 | teacher001@example.com |
| student001 | Student | 001 | student001@example.com |
| student002 | Student | 002 | student002@example.com |
| student003 | Student | 003 | student003@example.com |
| student004 | Student | 004 | student004@example.com |
| student005 | Student | 005 | student005@example.com |
| student006 | Student | 006 | student006@example.com |
| student007 | Student | 007 | student007@example.com |
| student008 | Student | 008 | student008@example.com |
| student009 | Student | 009 | student009@example.com |
| student010 | Student | 010 | student010@example.com |
| student011 | Student | 011 | student011@example.com |
| student012 | Student | 012 | student012@example.com |
| student013 | Student | 013 | student013@example.com |
| student014 | Student | 014 | student014@example.com |
| student015 | Student | 015 | student015@example.com |
| student016 | Student | 016 | student016@example.com |
| student017 | Student | 017 | student017@example.com |
| student018 | Student | 018 | student018@example.com |
| student019 | Student | 019 | student019@example.com |
| student020 | Student | 020 | student020@example.com |
| student021 | Student | 021 | student021@example.com |
| student022 | Student | 022 | student022@example.com |
| student023 | Student | 023 | student023@example.com |
| student024 | Student | 024 | student024@example.com |
| student025 | Student | 025 | student025@example.com |
| student026 | Student | 026 | student026@example.com |
| student027 | Student | 027 | student027@example.com |
| student028 | Student | 028 | student028@example.com |
| student029 | Student | 029 | student029@example.com |
| student030 | Student | 030 | student030@example.com |
| student031 | Student | 031 | student031@example.com |
| student032 | Student | 032 | student032@example.com |
| student033 | Student | 033 | student033@example.com |
| student034 | Student | 034 | student034@example.com |
| student035 | Student | 035 | student035@example.com |
| student036 | Student | 036 | student036@example.com |
| student037 | Student | 037 | student037@example.com |
| student038 | Student | 038 | student038@example.com |
| student039 | Student | 039 | student039@example.com |
| student040 | Student | 040 | student040@example.com |
| student041 | Student | 041 | student041@example.com |
| student042 | Student | 042 | student042@example.com |
| student043 | Student | 043 | student043@example.com |
| student044 | Student | 044 | student044@example.com |
| student045 | Student | 045 | student045@example.com |
| student046 | Student | 046 | student046@example.com |
| student047 | Student | 047 | student047@example.com |
| student048 | Student | 048 | student048@example.com |
| student049 | Student | 049 | student049@example.com |
| student050 | Student | 050 | student050@example.com |
| student051 | Student | 051 | student051@example.com |
| student052 | Student | 052 | student052@example.com |
| student053 | Student | 053 | student053@example.com |
| student054 | Student | 054 | student054@example.com |
| student055 | Student | 055 | student055@example.com |
| student056 | Student | 056 | student056@example.com |
| student057 | Student | 057 | student057@example.com |
| student058 | Student | 058 | student058@example.com |
| student059 | Student | 059 | student059@example.com |
| student060 | Student | 060 | student060@example.com |
| student061 | Student | 061 | student061@example.com |
| student062 | Student | 062 | student062@example.com |
| student063 | Student | 063 | student063@example.com |
| student064 | Student | 064 | student064@example.com |
| student065 | Student | 065 | student065@example.com |
| student066 | Student | 066 | student066@example.com |
| student067 | Student | 067 | student067@example.com |
| student068 | Student | 068 | student068@example.com |
| student069 | Student | 069 | student069@example.com |
| student070 | Student | 070 | student070@example.com |
| student071 | Student | 071 | student071@example.com |
| student072 | Student | 072 | student072@example.com |
| student073 | Student | 073 | student073@example.com |
| student074 | Student | 074 | student074@example.com |
| student075 | Student | 075 | student075@example.com |
| student076 | Student | 076 | student076@example.com |
| student077 | Student | 077 | student077@example.com |
| student078 | Student | 078 | student078@example.com |
| student079 | Student | 079 | student079@example.com |
| student080 | Student | 080 | student080@example.com |
| student081 | Student | 081 | student081@example.com |
| student082 | Student | 082 | student082@example.com |
| student083 | Student | 083 | student083@example.com |
| student084 | Student | 084 | student084@example.com |
| student085 | Student | 085 | student085@example.com |
| student086 | Student | 086 | student086@example.com |
| student087 | Student | 087 | student087@example.com |
| student088 | Student | 088 | student088@example.com |
| student089 | Student | 089 | student089@example.com |
| student090 | Student | 090 | student090@example.com |
| student091 | Student | 091 | student091@example.com |
| student092 | Student | 092 | student092@example.com |
| student093 | Student | 093 | student093@example.com |
| student094 | Student | 094 | student094@example.com |
| student095 | Student | 095 | student095@example.com |
| student096 | Student | 096 | student096@example.com |
| student097 | Student | 097 | student097@example.com |
| student098 | Student | 098 | student098@example.com |
| student099 | Student | 099 | student099@example.com |
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | customid | Custom user id |
And the following "users" exist:
| username | firstname | lastname | email | profile_field_customid |
| teacher001 | Teacher | 001 | teacher001@example.com | |
| student001 | Student | 001 | student001@example.com | Q994 |
| student002 | Student | 002 | student002@example.com | Q008 |
| student003 | Student | 003 | student003@example.com | Z442 |
| student004 | Student | 004 | student004@example.com | |
| student005 | Student | 005 | student005@example.com | |
| student006 | Student | 006 | student006@example.com | |
| student007 | Student | 007 | student007@example.com | |
| student008 | Student | 008 | student008@example.com | |
| student009 | Student | 009 | student009@example.com | |
| student010 | Student | 010 | student010@example.com | |
| student011 | Student | 011 | student011@example.com | |
| student012 | Student | 012 | student012@example.com | |
| student013 | Student | 013 | student013@example.com | |
| student014 | Student | 014 | student014@example.com | |
| student015 | Student | 015 | student015@example.com | |
| student016 | Student | 016 | student016@example.com | |
| student017 | Student | 017 | student017@example.com | |
| student018 | Student | 018 | student018@example.com | |
| student019 | Student | 019 | student019@example.com | |
| student020 | Student | 020 | student020@example.com | |
| student021 | Student | 021 | student021@example.com | |
| student022 | Student | 022 | student022@example.com | |
| student023 | Student | 023 | student023@example.com | |
| student024 | Student | 024 | student024@example.com | |
| student025 | Student | 025 | student025@example.com | |
| student026 | Student | 026 | student026@example.com | |
| student027 | Student | 027 | student027@example.com | |
| student028 | Student | 028 | student028@example.com | |
| student029 | Student | 029 | student029@example.com | |
| student030 | Student | 030 | student030@example.com | |
| student031 | Student | 031 | student031@example.com | |
| student032 | Student | 032 | student032@example.com | |
| student033 | Student | 033 | student033@example.com | |
| student034 | Student | 034 | student034@example.com | |
| student035 | Student | 035 | student035@example.com | |
| student036 | Student | 036 | student036@example.com | |
| student037 | Student | 037 | student037@example.com | |
| student038 | Student | 038 | student038@example.com | |
| student039 | Student | 039 | student039@example.com | |
| student040 | Student | 040 | student040@example.com | |
| student041 | Student | 041 | student041@example.com | |
| student042 | Student | 042 | student042@example.com | |
| student043 | Student | 043 | student043@example.com | |
| student044 | Student | 044 | student044@example.com | |
| student045 | Student | 045 | student045@example.com | |
| student046 | Student | 046 | student046@example.com | |
| student047 | Student | 047 | student047@example.com | |
| student048 | Student | 048 | student048@example.com | |
| student049 | Student | 049 | student049@example.com | |
| student050 | Student | 050 | student050@example.com | |
| student051 | Student | 051 | student051@example.com | |
| student052 | Student | 052 | student052@example.com | |
| student053 | Student | 053 | student053@example.com | |
| student054 | Student | 054 | student054@example.com | |
| student055 | Student | 055 | student055@example.com | |
| student056 | Student | 056 | student056@example.com | |
| student057 | Student | 057 | student057@example.com | |
| student058 | Student | 058 | student058@example.com | |
| student059 | Student | 059 | student059@example.com | |
| student060 | Student | 060 | student060@example.com | |
| student061 | Student | 061 | student061@example.com | |
| student062 | Student | 062 | student062@example.com | |
| student063 | Student | 063 | student063@example.com | |
| student064 | Student | 064 | student064@example.com | |
| student065 | Student | 065 | student065@example.com | |
| student066 | Student | 066 | student066@example.com | |
| student067 | Student | 067 | student067@example.com | |
| student068 | Student | 068 | student068@example.com | |
| student069 | Student | 069 | student069@example.com | |
| student070 | Student | 070 | student070@example.com | |
| student071 | Student | 071 | student071@example.com | |
| student072 | Student | 072 | student072@example.com | |
| student073 | Student | 073 | student073@example.com | |
| student074 | Student | 074 | student074@example.com | |
| student075 | Student | 075 | student075@example.com | |
| student076 | Student | 076 | student076@example.com | |
| student077 | Student | 077 | student077@example.com | |
| student078 | Student | 078 | student078@example.com | |
| student079 | Student | 079 | student079@example.com | |
| student080 | Student | 080 | student080@example.com | |
| student081 | Student | 081 | student081@example.com | |
| student082 | Student | 082 | student082@example.com | |
| student083 | Student | 083 | student083@example.com | |
| student084 | Student | 084 | student084@example.com | |
| student085 | Student | 085 | student085@example.com | |
| student086 | Student | 086 | student086@example.com | |
| student087 | Student | 087 | student087@example.com | |
| student088 | Student | 088 | student088@example.com | |
| student089 | Student | 089 | student089@example.com | |
| student090 | Student | 090 | student090@example.com | |
| student091 | Student | 091 | student091@example.com | |
| student092 | Student | 092 | student092@example.com | |
| student093 | Student | 093 | student093@example.com | |
| student094 | Student | 094 | student094@example.com | |
| student095 | Student | 095 | student095@example.com | |
| student096 | Student | 096 | student096@example.com | |
| student097 | Student | 097 | student097@example.com | |
| student098 | Student | 098 | student098@example.com | |
| student099 | Student | 099 | student099@example.com | |
And the following "courses" exist:
| fullname | shortname | format | startdate |
| Course 001 | C001 | weeks | ##1 month ago## |
@ -189,6 +192,26 @@ Feature: Teacher can search and enrol users one by one into the course
And I type "student100@example.com"
And I should see "student100@example.com, 1234567892, 1234567893, ABC1, ABC2"
@javascript
Scenario: Custom user profile fields work for search and display, if user has permission
Given the following config values are set as admin:
| showuseridentity | email,profile_field_customid |
And I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "Q994"
Then I should see "student001@example.com, Q994"
And I click on "Cancel" "button" in the "Enrol users" "dialogue"
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/site:viewuseridentity | Prevent | editingteacher | Course | C001 |
And I press "Enrol users"
# Do this by keyboard because the 'I set the field' step doesn't let you set it to a missing value.
And I press tab
And I press tab
And I press tab
And I type "Q994"
And I should see "No suggestions"
# The following tests are commented out as a result of MDL-66339.
# @javascript
# Scenario: Enrol user from participants page

View File

@ -254,6 +254,127 @@ class core_course_enrolment_manager_testcase extends advanced_testcase {
$this->assertArrayHasKey($this->users['user22']->id, $users);
}
/**
* Sets up a custom profile field and the showuseridentity option, and creates a test user
* with suitable values set.
*
* @return stdClass Test user
*/
protected function setup_for_user_identity_tests(): stdClass {
// Configure extra fields to include one normal user field and one profile field, and
// set the values for a new test user.
$generator = $this->getDataGenerator();
$generator->create_custom_profile_field(['datatype' => 'text',
'shortname' => 'researchtopic', 'name' => 'Research topic']);
set_config('showuseridentity', 'email,department,profile_field_researchtopic');
return $generator->create_user(
['username' => 'newuser', 'department' => 'Amphibian studies', 'email' => 'x@x.org',
'profile_field_researchtopic' => 'Frogs', 'imagealt' => 'Smart suit']);
}
/**
* Checks that the get_users function returns the correct user fields.
*/
public function test_get_users_fields() {
global $PAGE;
$this->resetAfterTest();
$newuser = $this->setup_for_user_identity_tests();
// Enrol the user in test course.
$this->getDataGenerator()->enrol_user($newuser->id, $this->course->id, 'student');
// Get all users and fish out the one we're interested in.
$manager = new course_enrolment_manager($PAGE, $this->course);
$users = $manager->get_users('id');
$user = $users[$newuser->id];
// Should include core required fields...
$this->assertEquals($newuser->id, $user->id);
// ...And the ones specified in showuseridentity (one of which is also needed for user pics).
$this->assertEquals('Amphibian studies', $user->department);
$this->assertEquals('Frogs', $user->profile_field_researchtopic);
$this->assertEquals('x@x.org', $user->email);
// And the ones necessary for user pics.
$this->assertEquals('Smart suit', $user->imagealt);
// But not some random other field like city.
$this->assertObjectNotHasAttribute('city', $user);
}
/**
* Checks that the get_other_users function returns the correct user fields.
*/
public function test_get_other_users_fields() {
global $PAGE, $DB;
$this->resetAfterTest();
// Configure extra fields to include one normal user field and one profile field, and
// set the values for a new test user.
$newuser = $this->setup_for_user_identity_tests();
$context = \context_course::instance($this->course->id);
role_assign($DB->get_field('role', 'id', ['shortname' => 'manager']), $newuser->id, $context->id);
// Get the 'other' (role but not enrolled) users and fish out the one we're interested in.
$manager = new course_enrolment_manager($PAGE, $this->course);
$users = array_values($manager->get_other_users('id'));
$user = $users[0];
// Should include core required fields...
$this->assertEquals($newuser->id, $user->id);
// ...And the ones specified in showuseridentity (one of which is also needed for user pics).
$this->assertEquals('Amphibian studies', $user->department);
$this->assertEquals('Frogs', $user->profile_field_researchtopic);
$this->assertEquals('x@x.org', $user->email);
// And the ones necessary for user pics.
$this->assertEquals('Smart suit', $user->imagealt);
// But not some random other field like city.
$this->assertObjectNotHasAttribute('city', $user);
}
/**
* Checks that the get_potential_users function returns the correct user fields.
*/
public function test_get_potential_users_fields() {
global $PAGE;
$this->resetAfterTest();
// Configure extra fields to include one normal user field and one profile field, and
// set the values for a new test user.
$newuser = $this->setup_for_user_identity_tests();
// Get the 'potential' (not enrolled) users and fish out the one we're interested in.
$manager = new course_enrolment_manager($PAGE, $this->course);
foreach (enrol_get_instances($this->course->id, true) as $enrolinstance) {
if ($enrolinstance->enrol === 'manual') {
$enrolid = $enrolinstance->id;
}
}
$users = array_values($manager->get_potential_users($enrolid));
$user = $users[0][$newuser->id];
// Should include core required fields...
$this->assertEquals($newuser->id, $user->id);
// ...And the ones specified in showuseridentity (one of which is also needed for user pics).
$this->assertEquals('Amphibian studies', $user->department);
$this->assertEquals('Frogs', $user->profile_field_researchtopic);
$this->assertEquals('x@x.org', $user->email);
// And the ones necessary for user pics.
$this->assertEquals('Smart suit', $user->imagealt);
// But not some random other field like city.
$this->assertObjectNotHasAttribute('city', $user);
}
/**
* Test get_potential_users without returnexactcount param.
*
@ -290,6 +411,58 @@ class core_course_enrolment_manager_testcase extends advanced_testcase {
}
}
/**
* Tests get_potential_users when the search term includes a custom field.
*/
public function test_get_potential_users_search_fields() {
global $PAGE;
$this->resetAfterTest();
// Configure extra fields to include one normal user field and one profile field, and
// set the values for a new test user.
$newuser = $this->setup_for_user_identity_tests();
// Set up the enrolment manager.
$manager = new course_enrolment_manager($PAGE, $this->course);
foreach (enrol_get_instances($this->course->id, true) as $enrolinstance) {
if ($enrolinstance->enrol === 'manual') {
$enrolid = $enrolinstance->id;
}
}
// Search for text included in a 'standard' (user table) identity field.
$users = array_values($manager->get_potential_users($enrolid, 'Amphibian studies'));
$this->assertEquals([$newuser->id], array_keys($users[0]));
// And for text included in a custom field.
$users = array_values($manager->get_potential_users($enrolid, 'Frogs'));
$this->assertEquals([$newuser->id], array_keys($users[0]));
// With partial matches.
$users = array_values($manager->get_potential_users($enrolid, 'Amphibian'));
$this->assertEquals([$newuser->id], array_keys($users[0]));
$users = array_values($manager->get_potential_users($enrolid, 'Fro'));
$this->assertEquals([$newuser->id], array_keys($users[0]));
// With partial in-the-middle matches.
$users = array_values($manager->get_potential_users($enrolid, 'phibian'));
$this->assertEquals([], array_keys($users[0]));
$users = array_values($manager->get_potential_users($enrolid, 'rog'));
$this->assertEquals([], array_keys($users[0]));
$users = array_values($manager->get_potential_users($enrolid, 'phibian', true));
$this->assertEquals([$newuser->id], array_keys($users[0]));
$users = array_values($manager->get_potential_users($enrolid, 'rog', true));
$this->assertEquals([$newuser->id], array_keys($users[0]));
// If the current user doesn't have access to identity fields then these searches won't work.
$this->setUser($this->getDataGenerator()->create_user());
$users = array_values($manager->get_potential_users($enrolid, 'Amphibian studies'));
$this->assertEquals([], array_keys($users[0]));
$users = array_values($manager->get_potential_users($enrolid, 'Frogs'));
$this->assertEquals([], array_keys($users[0]));
}
/**
* Test search_other_users with returnexactcount param.
*

View File

@ -1476,4 +1476,79 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
$result = core_enrol_external::search_users($course1->id, 'yada yada', true, 0, 30);
$this->assertCount(0, $result);
}
/**
* Tests the get_potential_users external function (not too much detail because the back-end
* is covered in another test).
*/
public function test_get_potential_users(): void {
$this->resetAfterTest();
// Create a couple of custom profile fields, one of which is in user identity.
$generator = $this->getDataGenerator();
$generator->create_custom_profile_field(['datatype' => 'text',
'shortname' => 'researchtopic', 'name' => 'Research topic']);
$generator->create_custom_profile_field(['datatype' => 'text',
'shortname' => 'specialid', 'name' => 'Special id']);
set_config('showuseridentity', 'department,profile_field_specialid');
// Create a course.
$course = $generator->create_course();
// Get enrol id for manual enrol plugin.
foreach (enrol_get_instances($course->id, true) as $instance) {
if ($instance->enrol === 'manual') {
$enrolid = $instance->id;
}
}
// Create a couple of test users.
$user1 = $generator->create_user(['firstname' => 'Eigh', 'lastname' => 'User',
'department' => 'Amphibians', 'profile_field_specialid' => 'Q123',
'profile_field_researchtopic' => 'Frogs']);
$user2 = $generator->create_user(['firstname' => 'Anne', 'lastname' => 'Other',
'department' => 'Amphibians', 'profile_field_specialid' => 'Q456',
'profile_field_researchtopic' => 'Toads']);
// Do this as admin user.
$this->setAdminUser();
// Get potential users and extract the 2 we care about.
$result = core_enrol_external::get_potential_users($course->id, $enrolid, '', false, 0, 10);
$result1 = $this->extract_user_from_result($result, $user1->id);
$result2 = $this->extract_user_from_result($result, $user2->id);
// Check the fields are the expected ones.
$this->assertEquals(['id', 'fullname', 'customfields',
'profileimageurl', 'profileimageurlsmall', 'department'], array_keys($result1));
$this->assertEquals('Eigh User', $result1['fullname']);
$this->assertEquals('Amphibians', $result1['department']);
// Check the custom fields ONLY include the user identity one.
$fieldvalues = [];
foreach ($result1['customfields'] as $customfield) {
$fieldvalues[$customfield['shortname']] = $customfield['value'];
}
$this->assertEquals(['specialid'], array_keys($fieldvalues));
$this->AssertEquals('Q123', $fieldvalues['specialid']);
// Just check user 2 is the right user.
$this->assertEquals('Anne Other', $result2['fullname']);
}
/**
* Utility function to get one user out of the get_potential_users result.
*
* @param array $result Result array
* @param int $userid User id
* @return array Data for that user
*/
protected function extract_user_from_result(array $result, int $userid): array {
foreach ($result as $item) {
if ($item['id'] == $userid) {
return $item;
}
}
$this->fail('User not in result: ' . $userid);
}
}

View File

@ -1963,7 +1963,7 @@ class grade_report_grader extends grade_report {
foreach ($extrafields as $field) {
$fieldlink = html_writer::link(new moodle_url($this->baseurl,
array('sortitemid'=>$field)), \core\user_fields::get_display_name($field));
array('sortitemid' => $field)), \core\user_fields::get_display_name($field));
$arrows[$field] = $fieldlink;
if ($field == $this->sortitemid) {

View File

@ -3645,9 +3645,9 @@ function fullname($user, $override=false) {
* @return object User name fields.
*/
function username_load_fields_from_object($addtoobject, $secondobject, $prefix = null, $additionalfields = null) {
$fields = \core\user_fields::get_name_fields();
foreach ($fields as &$field) {
$field = $prefix . $field;
$fields = [];
foreach (\core\user_fields::get_name_fields() as $field) {
$fields[$field] = $prefix . $field;
}
if ($additionalfields) {
// Additional fields can specify their own 'alias' such as 'id' => 'userid'. This checks to see if

View File

@ -230,7 +230,7 @@ class user_picture implements renderable {
}
if ($needrec) {
$this->user = $DB->get_record('user', array('id'=>$user->id),
$this->user = $DB->get_record('user', array('id' => $user->id),
implode(',', \core\user_fields::get_picture_fields()), MUST_EXIST);
} else {
$this->user = clone($user);

View File

@ -907,7 +907,7 @@ function chat_format_message($message, $courseid, $currentuser, $chatlastrow=nul
if (isset($users[$message->userid])) {
$user = $users[$message->userid];
} else if ($user = $DB->get_record('user', array('id' => $message->userid), implode(',', \core\user_fields::get_picture_fields()))) {
} else if ($user = $DB->get_record('user', ['id' => $message->userid], implode(',', \core\user_fields::get_picture_fields()))) {
$users[$message->userid] = $user;
} else {
return null;
@ -938,7 +938,8 @@ function chat_format_message_theme ($message, $chatuser, $currentuser, $grouping
if (isset($users[$message->userid])) {
$sender = $users[$message->userid];
} else if ($sender = $DB->get_record('user', array('id' => $message->userid), implode(',', \core\user_fields::get_picture_fields()))) {
} else if ($sender = $DB->get_record('user', array('id' => $message->userid),
implode(',', \core\user_fields::get_picture_fields()))) {
$users[$message->userid] = $sender;
} else {
return null;

View File

@ -512,7 +512,7 @@ if (!$csv) {
$row[] = get_string('id', 'report_completion');
$row[] = get_string('name', 'report_completion');
foreach ($extrafields as $field) {
$row[] = \core\user_fields::get_display_name($field);
$row[] = \core\user_fields::get_display_name($field);
}
// Add activity headers

View File

@ -296,7 +296,7 @@ function report_log_print_mnet_selector_form($hostid, $course, $selecteduser=0,
} else {
// this may be a lot of users :-(
$userfieldsapi = \core\user_fields::for_name();
$courseusers = $DB->get_records('user', array('deleted'=>0), 'lastaccess DESC', 'id, ' .
$courseusers = $DB->get_records('user', array('deleted' => 0), 'lastaccess DESC', 'id, ' .
$userfieldsapi->get_sql('', false, '', '', false)->selects,
$limitfrom, $limitnum);
}

View File

@ -302,7 +302,8 @@ function user_get_user_details($user, $course = null, array $userfields = array(
$currentuser = ($user->id == $USER->id);
$isadmin = is_siteadmin($USER);
// TODO Does not support custom user profile fields (MDL-70456).
// This does not need to include custom profile fields as it is only used to check specific
// fields below.
$showuseridentityfields = \core\user_fields::get_identity_fields($context, false);
if (!empty($course)) {

View File

@ -23,7 +23,8 @@ $PAGE->set_title($title);
$PAGE->set_heading($title);
echo $OUTPUT->header();
$rs = $DB->get_recordset_select("user", "deleted = 0 AND picture > 0", array(), "lastaccess DESC", implode(',', \core\user_fields::get_picture_fields()));
$rs = $DB->get_recordset_select("user", "deleted = 0 AND picture > 0", array(), "lastaccess DESC",
implode(',', \core\user_fields::get_picture_fields()));
foreach ($rs as $user) {
$fullname = s(fullname($user));
echo "<a href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=1\" ".