mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 12:32:08 +02:00
Merge branch 'MDL-78312-master' of https://github.com/NashTechOpenUniversity/moodle
This commit is contained in:
commit
4355e38e88
@ -708,7 +708,7 @@ class external extends external_api {
|
||||
$fields .= ',' . implode(',', $extrafields);
|
||||
}
|
||||
|
||||
list($sql, $params) = users_search_sql($query, '', false, $extrafields, $excludedusers);
|
||||
list($sql, $params) = users_search_sql($query, '', USER_SEARCH_STARTS_WITH, $extrafields, $excludedusers);
|
||||
$users = $DB->get_records_select('user', $sql, $params, $sort, $fields, 0, 30);
|
||||
$useroptions = [];
|
||||
foreach ($users as $user) {
|
||||
|
@ -874,7 +874,7 @@ class external extends external_api {
|
||||
$fields = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
|
||||
$extrasearchfields = $userfieldsapi->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
|
||||
|
||||
list($wheresql, $whereparams) = users_search_sql($query, 'u', true, $extrasearchfields);
|
||||
list($wheresql, $whereparams) = users_search_sql($query, 'u', USER_SEARCH_CONTAINS, $extrasearchfields);
|
||||
list($sortsql, $sortparams) = users_order_by_sql('u', $query, $context);
|
||||
|
||||
$countsql = "SELECT COUNT('x') FROM {user} u WHERE $wheresql AND u.id $filtercapsql";
|
||||
|
@ -58,7 +58,7 @@ $outcome->success = true;
|
||||
$outcome->response = new stdClass();
|
||||
$outcome->error = '';
|
||||
|
||||
$searchanywhere = get_user_preferences('userselector_searchanywhere', false);
|
||||
$searchanywhere = get_user_preferences('userselector_searchtype') === USER_SEARCH_CONTAINS;
|
||||
|
||||
switch ($action) {
|
||||
case 'unenrol':
|
||||
|
@ -274,7 +274,7 @@ class course_enrolment_manager {
|
||||
// Search condition.
|
||||
// TODO Does not support custom user profile fields (MDL-70456).
|
||||
$extrafields = fields::get_identity_fields($this->get_context(), false);
|
||||
list($sql, $params) = users_search_sql($this->searchfilter, 'u', true, $extrafields);
|
||||
list($sql, $params) = users_search_sql($this->searchfilter, 'u', USER_SEARCH_CONTAINS, $extrafields);
|
||||
|
||||
// Role condition.
|
||||
if ($this->rolefilter) {
|
||||
|
@ -60,7 +60,7 @@ $outcome->response = new stdClass();
|
||||
$outcome->error = '';
|
||||
$outcome->count = 0;
|
||||
|
||||
$searchanywhere = get_user_preferences('userselector_searchanywhere', false);
|
||||
$searchanywhere = get_user_preferences('userselector_searchtype') === USER_SEARCH_CONTAINS;
|
||||
|
||||
switch ($action) {
|
||||
case 'enrol':
|
||||
|
@ -138,7 +138,7 @@ class helper {
|
||||
}
|
||||
$params = array();
|
||||
if (!empty($search)) {
|
||||
list($filtersql, $params) = users_search_sql($search, 'u', true, $extrafields);
|
||||
list($filtersql, $params) = users_search_sql($search, 'u', USER_SEARCH_CONTAINS, $extrafields);
|
||||
$filtersql .= ' AND ';
|
||||
} else {
|
||||
$filtersql = '';
|
||||
|
@ -2369,7 +2369,10 @@ $string['userpic'] = 'User picture';
|
||||
$string['users'] = 'Users';
|
||||
$string['userselectorautoselectunique'] = 'If only one user matches the search, select them automatically';
|
||||
$string['userselectorpreserveselected'] = 'Keep selected users, even if they no longer match the search';
|
||||
$string['userselectorsearchanywhere'] = 'Match the search text anywhere in the displayed fields';
|
||||
$string['userselectorsearchmatching'] = 'Matching:';
|
||||
$string['userselectorsearchfromstart'] = 'from start';
|
||||
$string['userselectorsearchanywhere'] = 'anywhere';
|
||||
$string['userselectorsearchexactmatchonly'] = 'exact matches only';
|
||||
$string['usersnew'] = 'New users';
|
||||
$string['usersnoaccesssince'] = 'Inactive for more than';
|
||||
$string['userpreferences'] = 'User preferences';
|
||||
|
@ -243,7 +243,7 @@ class core_user {
|
||||
}
|
||||
|
||||
// Start building the WHERE clause based on name.
|
||||
list ($where, $whereparams) = users_search_sql($query, 'u', false);
|
||||
list ($where, $whereparams) = users_search_sql($query, 'u');
|
||||
|
||||
// We allow users to search with extra identity fields (as well as name) but only if they
|
||||
// have the permission to display those identity fields.
|
||||
@ -1021,10 +1021,10 @@ class core_user {
|
||||
'default' => false,
|
||||
'permissioncallback' => [static::class, 'is_current_user'],
|
||||
];
|
||||
$preferences['userselector_searchanywhere'] = [
|
||||
'type' => PARAM_BOOL,
|
||||
$preferences['userselector_searchtype'] = [
|
||||
'type' => PARAM_INT,
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => false,
|
||||
'default' => USER_SEARCH_STARTS_WITH,
|
||||
'permissioncallback' => [static::class, 'is_current_user'],
|
||||
];
|
||||
$preferences['question_bank_advanced_search'] = [
|
||||
|
@ -52,6 +52,12 @@ define('MAX_COURSE_CATEGORIES', 10000);
|
||||
if (!defined('LASTACCESS_UPDATE_SECS')) {
|
||||
define('LASTACCESS_UPDATE_SECS', 60);
|
||||
}
|
||||
/**
|
||||
* The constant value when we use the search option.
|
||||
*/
|
||||
define('USER_SEARCH_STARTS_WITH', 0);
|
||||
define('USER_SEARCH_CONTAINS', 1);
|
||||
define('USER_SEARCH_EXACT_MATCH', 2);
|
||||
|
||||
/**
|
||||
* Returns $user object of the main admin user
|
||||
@ -216,8 +222,8 @@ function search_users($courseid, $groupid, $searchtext, $sort='', array $excepti
|
||||
* @param string $search the text to search for (empty string = find all)
|
||||
* @param string $u the table alias for the user table in the query being
|
||||
* built. May be ''.
|
||||
* @param bool $searchanywhere If true (default), searches in the middle of
|
||||
* names, otherwise only searches at start
|
||||
* @param int $searchtype If 0(default): searches at start, 1: searches in the middle of names
|
||||
* 2: search exact match.
|
||||
* @param array $extrafields Array of extra user fields to include in search, must be prefixed with table alias if they are not in
|
||||
* the user table.
|
||||
* @param array $exclude Array of user ids to exclude (empty = don't exclude)
|
||||
@ -227,7 +233,7 @@ function search_users($courseid, $groupid, $searchtext, $sort='', array $excepti
|
||||
* where clause the query, and an associative array containing any required
|
||||
* parameters (using named placeholders).
|
||||
*/
|
||||
function users_search_sql(string $search, string $u = 'u', bool $searchanywhere = true, array $extrafields = [],
|
||||
function users_search_sql(string $search, string $u = 'u', int $searchtype = USER_SEARCH_STARTS_WITH, array $extrafields = [],
|
||||
array $exclude = null, array $includeonly = null): array {
|
||||
global $DB, $CFG;
|
||||
$params = array();
|
||||
@ -237,7 +243,6 @@ function users_search_sql(string $search, string $u = 'u', bool $searchanywhere
|
||||
$u .= '.';
|
||||
}
|
||||
|
||||
// If we have a $search string, put a field LIKE '$search%' condition on each field.
|
||||
if ($search) {
|
||||
$conditions = array(
|
||||
$DB->sql_fullname($u . 'firstname', $u . 'lastname'),
|
||||
@ -247,14 +252,26 @@ function users_search_sql(string $search, string $u = 'u', bool $searchanywhere
|
||||
// Add the table alias for the user table if the field doesn't already have an alias.
|
||||
$conditions[] = strpos($field, '.') !== false ? $field : $u . $field;
|
||||
}
|
||||
if ($searchanywhere) {
|
||||
$searchparam = '%' . $search . '%';
|
||||
} else {
|
||||
$searchparam = $search . '%';
|
||||
switch ($searchtype) {
|
||||
case USER_SEARCH_STARTS_WITH:
|
||||
// Put a field LIKE 'search%' condition on each field.
|
||||
$searchparam = $search . '%';
|
||||
break;
|
||||
case USER_SEARCH_CONTAINS:
|
||||
// Put a field LIKE '$search%' condition on each field.
|
||||
$searchparam = '%' . $search . '%';
|
||||
break;
|
||||
case USER_SEARCH_EXACT_MATCH:
|
||||
// Match exact the $search string.
|
||||
$searchparam = $search;
|
||||
break;
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($conditions as $key => $condition) {
|
||||
$conditions[$key] = $DB->sql_like($condition, ":con{$i}00", false, false);
|
||||
if ($searchtype === USER_SEARCH_EXACT_MATCH) {
|
||||
$conditions[$key] = "$condition = :con{$i}00";
|
||||
}
|
||||
$params["con{$i}00"] = $searchparam;
|
||||
$i++;
|
||||
}
|
||||
|
@ -3594,5 +3594,12 @@ privatefiles,moodle|/user/files.php';
|
||||
upgrade_main_savepoint(true, 2023090200.01);
|
||||
}
|
||||
|
||||
if ($oldversion < 2023091300.03) {
|
||||
// Delete all the searchanywhere prefs in user_preferences table.
|
||||
$DB->delete_records('user_preferences', ['name' => 'userselector_searchanywhere']);
|
||||
// Main savepoint reached.
|
||||
upgrade_main_savepoint(true, 2023091300.03);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -77,42 +77,48 @@ class datalib_test extends \advanced_testcase {
|
||||
$user2 = self::getDataGenerator()->create_user($user2);
|
||||
|
||||
// Search by name (anywhere in text).
|
||||
list($sql, $params) = users_search_sql('User Test 2', '');
|
||||
list($sql, $params) = users_search_sql('User Test 2', '', USER_SEARCH_CONTAINS);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Search by (most of) full name.
|
||||
list($sql, $params) = users_search_sql('First Name User Test 2 Last Name User', '');
|
||||
list($sql, $params) = users_search_sql('First Name User Test 2 Last Name User', '', USER_SEARCH_CONTAINS);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Search by name (start of text) valid or not.
|
||||
list($sql, $params) = users_search_sql('User Test 2', '', false);
|
||||
list($sql, $params) = users_search_sql('User Test 2', '');
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertEquals(0, count($results));
|
||||
list($sql, $params) = users_search_sql('First Name User Test 2', '', false);
|
||||
list($sql, $params) = users_search_sql('First Name User Test 2', '');
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Search by extra fields included or not (address).
|
||||
list($sql, $params) = users_search_sql('Test Street', '', true);
|
||||
list($sql, $params) = users_search_sql('Test Street', '', USER_SEARCH_CONTAINS);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertCount(0, $results);
|
||||
list($sql, $params) = users_search_sql('Test Street', '', true, array('address'));
|
||||
list($sql, $params) = users_search_sql('Test Street', '', USER_SEARCH_CONTAINS, array('address'));
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertCount(2, $results);
|
||||
|
||||
// Exclude user.
|
||||
list($sql, $params) = users_search_sql('User Test', '', true, array(), array($user1->id));
|
||||
list($sql, $params) = users_search_sql('User Test', '', USER_SEARCH_CONTAINS, array(), array($user1->id));
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertFalse(array_key_exists($user1->id, $results));
|
||||
$this->assertTrue(array_key_exists($user2->id, $results));
|
||||
|
||||
// Include only user.
|
||||
list($sql, $params) = users_search_sql('User Test', '', true, array(), array(), array($user1->id));
|
||||
list($sql, $params) = users_search_sql('User Test', '', USER_SEARCH_CONTAINS, array(), array(), array($user1->id));
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertTrue(array_key_exists($user1->id, $results));
|
||||
$this->assertFalse(array_key_exists($user2->id, $results));
|
||||
|
||||
// Exact match only.
|
||||
[$sql, $params] = users_search_sql('Last Name User Test 1', '', USER_SEARCH_EXACT_MATCH, [], null, null, true);
|
||||
$results = $DB->get_records_sql("SELECT id FROM {user} WHERE $sql ORDER BY username", $params);
|
||||
$this->assertTrue(array_key_exists($user1->id, $results));
|
||||
$this->assertFalse(array_key_exists($user2->id, $results));
|
||||
@ -120,7 +126,7 @@ class datalib_test extends \advanced_testcase {
|
||||
// Join with another table and use different prefix.
|
||||
set_user_preference('amphibian', 'frog', $user1);
|
||||
set_user_preference('amphibian', 'salamander', $user2);
|
||||
list($sql, $params) = users_search_sql('User Test 1', 'qq');
|
||||
list($sql, $params) = users_search_sql('User Test 1', 'qq', USER_SEARCH_CONTAINS);
|
||||
$results = $DB->get_records_sql("
|
||||
SELECT up.id, up.value
|
||||
FROM {user} qq
|
||||
@ -135,7 +141,7 @@ class datalib_test extends \advanced_testcase {
|
||||
// Join with another table and include other table fields in search.
|
||||
set_user_preference('reptile', 'snake', $user1);
|
||||
set_user_preference('reptile', 'lizard', $user2);
|
||||
list($sql, $params) = users_search_sql('snake', 'qq', true, ['up.value']);
|
||||
list($sql, $params) = users_search_sql('snake', 'qq', USER_SEARCH_CONTAINS, ['up.value']);
|
||||
$results = $DB->get_records_sql("
|
||||
SELECT up.id, up.value
|
||||
FROM {user} qq
|
||||
|
@ -182,6 +182,9 @@ being forced open in all behat tests.
|
||||
* The $CFG->svgicons setting has been removed because all modern browsers now handle SVG files correctly.
|
||||
* The method `\core_renderer->supportemail()` has an updated signature. It now allows a second optional parameter.
|
||||
Set it to true if you want to embed the generated link in other inline content.
|
||||
* The users_search_sql function parameter $searchanywhere has been change to $searchtype for different type of search. $searchtype is a int parameter and has three constant value:
|
||||
USER_SEARCH_STARTS_WITH: 0, USER_SEARCH_CONTAINS: 1, USER_SEARCH_EXACT_MATCH: 2
|
||||
See MDL-78312 for further information.
|
||||
|
||||
=== 4.2 ===
|
||||
|
||||
|
2
user/classes/external/search_identity.php
vendored
2
user/classes/external/search_identity.php
vendored
@ -68,7 +68,7 @@ class search_identity extends external_api {
|
||||
$fields = \core_user\fields::for_name()->with_identity($context, false);
|
||||
$extrafields = $fields->get_required_fields([\core_user\fields::PURPOSE_IDENTITY]);
|
||||
|
||||
list($searchsql, $searchparams) = users_search_sql($query, '', true, $extrafields);
|
||||
list($searchsql, $searchparams) = users_search_sql($query, '', USER_SEARCH_CONTAINS, $extrafields);
|
||||
list($sortsql, $sortparams) = users_order_by_sql('', $query, $context);
|
||||
$params = array_merge($searchparams, $sortparams);
|
||||
|
||||
|
@ -58,9 +58,9 @@ abstract class user_selector_base {
|
||||
protected $preserveselected = false;
|
||||
/** @var boolean If only one user matches the search, should we select them automatically. */
|
||||
protected $autoselectunique = false;
|
||||
/** @var boolean When searching, do we only match the starts of fields (better performance)
|
||||
* or do we match occurrences anywhere? */
|
||||
protected $searchanywhere = false;
|
||||
/** @var int When searching, do we only match the starts of fields (better performance)
|
||||
* or do we match occurrences anywhere or do we match exact the fields. */
|
||||
protected $searchtype = USER_SEARCH_STARTS_WITH;
|
||||
/** @var mixed This is used by get selected users */
|
||||
protected $validatinguserids = null;
|
||||
|
||||
@ -156,8 +156,7 @@ abstract class user_selector_base {
|
||||
// Read the user prefs / optional_params that we use.
|
||||
$this->preserveselected = $this->initialise_option('userselector_preserveselected', $this->preserveselected);
|
||||
$this->autoselectunique = $this->initialise_option('userselector_autoselectunique', $this->autoselectunique);
|
||||
$this->searchanywhere = $this->initialise_option('userselector_searchanywhere', $this->searchanywhere);
|
||||
|
||||
$this->searchtype = (int) $this->initialise_option('userselector_searchtype', $this->searchtype, PARAM_INT);
|
||||
if (!empty($CFG->maxusersperpage)) {
|
||||
$this->maxusersperpage = $CFG->maxusersperpage;
|
||||
}
|
||||
@ -278,7 +277,6 @@ abstract class user_selector_base {
|
||||
$this->name . '_clearbutton" value="' . get_string('clear') . '" class="btn btn-secondary"/>';
|
||||
|
||||
// And the search options.
|
||||
$optionsoutput = false;
|
||||
if (!user_selector_base::$searchoptionsoutput) {
|
||||
$output .= print_collapsible_region_start('', 'userselector_options',
|
||||
get_string('searchoptions'), 'userselector_optionscollapsed', true, true);
|
||||
@ -286,8 +284,7 @@ abstract class user_selector_base {
|
||||
get_string('userselectorpreserveselected'));
|
||||
$output .= $this->option_checkbox('autoselectunique', $this->autoselectunique,
|
||||
get_string('userselectorautoselectunique'));
|
||||
$output .= $this->option_checkbox('searchanywhere', $this->searchanywhere,
|
||||
get_string('userselectorsearchanywhere'));
|
||||
$output .= $this->output_searchtype_radios();
|
||||
$output .= print_collapsible_region_end(true);
|
||||
|
||||
$PAGE->requires->js_init_call('M.core_user.init_user_selector_options_tracker', array(), false, self::$jsmodule);
|
||||
@ -499,8 +496,7 @@ abstract class user_selector_base {
|
||||
$extrafields = $this->includecustomfields
|
||||
? array_values($this->userfieldsmappings)
|
||||
: $this->extrafields;
|
||||
|
||||
return users_search_sql($search, $u, $this->searchanywhere, $extrafields,
|
||||
return users_search_sql($search, $u, $this->searchtype, $extrafields,
|
||||
$this->exclude, $this->validatinguserids);
|
||||
}
|
||||
|
||||
@ -644,10 +640,11 @@ abstract class user_selector_base {
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
* @param string $paramtype allow the option to custom param type. default is bool
|
||||
* @return mixed|null|string
|
||||
*/
|
||||
private function initialise_option($name, $default) {
|
||||
$param = optional_param($name, null, PARAM_BOOL);
|
||||
private function initialise_option($name, $default, $paramtype = PARAM_BOOL) {
|
||||
$param = optional_param($name, null, $paramtype);
|
||||
if (is_null($param)) {
|
||||
return get_user_preferences($name, $default);
|
||||
} else {
|
||||
@ -673,7 +670,7 @@ abstract class user_selector_base {
|
||||
$name = 'userselector_' . $name;
|
||||
// For the benefit of brain-dead IE, the id must be different from the name of the hidden form field above.
|
||||
// It seems that document.getElementById('frog') in IE will return and element with name="frog".
|
||||
$output = '<div class="form-check"><input type="hidden" name="' . $name . '" value="0" />' .
|
||||
$output = '<div class="form-check justify-content-start ml-1"><input type="hidden" name="' . $name . '" value="0" />' .
|
||||
'<label class="form-check-label" for="' . $name . 'id">' .
|
||||
'<input class="form-check-input" type="checkbox" id="' . $name . 'id" name="' . $name .
|
||||
'" value="1"' . $checked . ' /> ' . $label .
|
||||
@ -682,6 +679,48 @@ abstract class user_selector_base {
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the data for each input in the user selector search type.
|
||||
*
|
||||
* @param string $name
|
||||
* @param bool $checked
|
||||
* @param string $label
|
||||
* @param int $value
|
||||
* @param string $class
|
||||
* @return array a list of attributes for input.
|
||||
*/
|
||||
private function get_radio_searchtype_data(string $name, bool $checked, string $label, int $value, string $class): array {
|
||||
$name = 'userselector_' . $name;
|
||||
$id = $name . 'id';
|
||||
$attrs = [
|
||||
'value' => $value,
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
'class' => $class,
|
||||
'label' => $label,
|
||||
];
|
||||
if ($checked) {
|
||||
$attrs['checked'] = true;
|
||||
}
|
||||
return $attrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the search type radio buttons.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function output_searchtype_radios(): string {
|
||||
global $OUTPUT;
|
||||
$fields[] = $this->get_radio_searchtype_data('searchexactmatchesonly', $this->searchtype === USER_SEARCH_EXACT_MATCH,
|
||||
get_string('userselectorsearchexactmatchonly'), USER_SEARCH_EXACT_MATCH, 'mr-1');
|
||||
$fields[] = $this->get_radio_searchtype_data('searchfromstart', $this->searchtype === USER_SEARCH_STARTS_WITH,
|
||||
get_string('userselectorsearchfromstart'), USER_SEARCH_STARTS_WITH, 'mr-1');
|
||||
$fields[] = $this->get_radio_searchtype_data('searchanywhere', $this->searchtype === USER_SEARCH_CONTAINS,
|
||||
get_string('userselectorsearchanywhere'), USER_SEARCH_CONTAINS, 'mr-1');
|
||||
return $OUTPUT->render_from_template('core_user/form_user_selector_searchtype', (object) ['fields' => $fields]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises JS for this control.
|
||||
*
|
||||
@ -689,7 +728,7 @@ abstract class user_selector_base {
|
||||
* @return string any HTML needed here.
|
||||
*/
|
||||
protected function initialise_javascript($search) {
|
||||
global $USER, $PAGE, $OUTPUT;
|
||||
global $USER, $PAGE;
|
||||
$output = '';
|
||||
|
||||
// Put the options into the session, to allow search.php to respond to the ajax requests.
|
||||
@ -700,7 +739,7 @@ abstract class user_selector_base {
|
||||
// Initialise the selector.
|
||||
$PAGE->requires->js_init_call(
|
||||
'M.core_user.init_user_selector',
|
||||
array($this->name, $hash, $this->extrafields, $search),
|
||||
array($this->name, $hash, $this->extrafields, $search, $this->searchtype),
|
||||
false,
|
||||
self::$jsmodule
|
||||
);
|
||||
|
@ -25,8 +25,9 @@ M.core_user.get_user_selector = function (name) {
|
||||
* @param {string} hash the hash that identifies this selector in the user's session.
|
||||
* @param {array} extrafields extra fields we are displaying for each user in addition to fullname.
|
||||
* @param {string} lastsearch The last search that took place
|
||||
* @param {int} searchtype the last search option that took place
|
||||
*/
|
||||
M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearch) {
|
||||
M.core_user.init_user_selector = function(Y, name, hash, extrafields, lastsearch, searchtype) {
|
||||
// Creates a new user_selector object
|
||||
var user_selector = {
|
||||
/** This id/name used for this control in the HTML. */
|
||||
@ -50,6 +51,8 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
|
||||
/** Whether any options where selected last time we checked. Used by
|
||||
* handle_selection_change to track when this status changes. */
|
||||
selectionempty : true,
|
||||
/** The last search option that we use for*/
|
||||
searchtype: searchtype,
|
||||
/**
|
||||
* Initialises the user selector object
|
||||
* @constructor
|
||||
@ -69,7 +72,9 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
|
||||
this.listbox.on('change', this.handle_selection_change, this);
|
||||
|
||||
// And when the search any substring preference changes. Do an immediate re-search.
|
||||
Y.one('#userselector_searchanywhereid').on('click', this.handle_searchanywhere_change, this);
|
||||
Y.one('#userselector_searchfromstartid').on('click', this.handle_searchtype_change, this);
|
||||
Y.one('#userselector_searchanywhereid').on('click', this.handle_searchtype_change, this);
|
||||
Y.one('#userselector_searchexactmatchesonlyid').on('click', this.handle_searchtype_change, this);
|
||||
|
||||
// Define our custom event.
|
||||
//this.createEvent('selectionchanged');
|
||||
@ -114,13 +119,22 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
|
||||
this.selectionempty = isselectionempty;
|
||||
},
|
||||
/**
|
||||
* Trigger a re-search when the 'search any substring' option is changed.
|
||||
* Trigger a re-search and set the user prefs when the search radio option is changed.
|
||||
*
|
||||
* @param {Y.Event} e the change event.
|
||||
*/
|
||||
handle_searchanywhere_change : function() {
|
||||
handle_searchtype_change: function(e) {
|
||||
this.clear_search_radio_state();
|
||||
e.currentTarget.set('checked', 1);
|
||||
this.searchtype = e.currentTarget.get('value');
|
||||
require(['core_user/repository'], function(UserRepository) {
|
||||
UserRepository.setUserPreference('userselector_searchtype', e.currentTarget.get('value'));
|
||||
});
|
||||
if (this.lastsearch != '' && this.get_search_text() != '') {
|
||||
this.send_query(true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Click handler for the clear button..
|
||||
*/
|
||||
@ -129,6 +143,16 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
|
||||
this.clearbutton.set('disabled',true);
|
||||
this.send_query(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear all checked state in the radio search option.
|
||||
*/
|
||||
clear_search_radio_state: function() {
|
||||
Y.one('#userselector_searchfromstartid').set('checked', 0);
|
||||
Y.one('#userselector_searchanywhereid').set('checked', 0);
|
||||
Y.one('#userselector_searchexactmatchesonlyid').set('checked', 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fires off the ajax search request.
|
||||
*/
|
||||
@ -146,10 +170,10 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
|
||||
Y.Object.each(this.iotransactions, function(trans) {
|
||||
trans.abort();
|
||||
});
|
||||
|
||||
var iotrans = Y.io(M.cfg.wwwroot + '/user/selector/search.php', {
|
||||
method: 'POST',
|
||||
data: 'selectorid=' + hash + '&sesskey=' + M.cfg.sesskey + '&search=' + value + '&userselector_searchanywhere=' + this.get_option('searchanywhere'),
|
||||
data: 'selectorid=' + hash + '&sesskey=' + M.cfg.sesskey +
|
||||
'&search=' + value + '&userselector_searchtype=' + this.searchtype,
|
||||
on: {
|
||||
complete: this.handle_response
|
||||
},
|
||||
@ -355,7 +379,6 @@ M.core_user.init_user_selector_options_tracker = function(Y) {
|
||||
var settings = [
|
||||
'userselector_preserveselected',
|
||||
'userselector_autoselectunique',
|
||||
'userselector_searchanywhere'
|
||||
];
|
||||
for (var s in settings) {
|
||||
var setting = settings[s];
|
||||
|
47
user/templates/form_user_selector_searchtype.mustache
Normal file
47
user/templates/form_user_selector_searchtype.mustache
Normal file
@ -0,0 +1,47 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_user/form_user_selector_searchtype
|
||||
|
||||
Template for the form_user_selector search type.
|
||||
|
||||
Context variables required for this template:
|
||||
* defaultvalue int - The user's full name.
|
||||
* fields list - the input element attributes and label
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"fields": [
|
||||
{
|
||||
"id": "id",
|
||||
"name": "userselector_searchexactmatchesonly",
|
||||
"class": "class",
|
||||
"label": "Search anywhere",
|
||||
"checked": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
<div class="form-check justify-content-start ml-1">
|
||||
<span class="mr-1">{{#str}}userselectorsearchmatching, core{{/str}}</span>
|
||||
{{#fields}}
|
||||
<label for="{{id}}">
|
||||
<input id="{{id}}" type="radio" value="{{value}}" name="{{name}}" class="{{class}}" {{#checked}}checked{{/checked}}>
|
||||
{{label}}
|
||||
</label>
|
||||
{{/fields}}
|
||||
</div>
|
24
user/tests/behat/user_permission.feature
Normal file
24
user/tests/behat/user_permission.feature
Normal file
@ -0,0 +1,24 @@
|
||||
@core @core_user @javascript
|
||||
Feature: The admin can check student permission in moodle system.
|
||||
In order to check permission of a user in moodle
|
||||
As an admin user
|
||||
I can search student and see their permission
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| user1 | User | 1 | user1@example.com |
|
||||
|
||||
Scenario: The search setting is saved for each user.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Permissions > Check system permissions" in site administration
|
||||
And I follow "Search options"
|
||||
And the field "from start" matches value "1"
|
||||
And I click on "anywhere" "radio"
|
||||
And I click on "Keep selected users, even if they no longer match the search" "checkbox"
|
||||
And I click on "If only one user matches the search, select them automatically" "checkbox"
|
||||
And I reload the page
|
||||
Then the field "from start" matches value "0"
|
||||
And the field "anywhere" matches value "1"
|
||||
And the field "Keep selected users, even if they no longer match the search" matches value "1"
|
||||
And the field "If only one user matches the search, select them automatically" matches value "1"
|
@ -22,6 +22,9 @@ This files describes API changes for code that uses the user API.
|
||||
- `user_get_participants`
|
||||
- `user_get_participants_sql`
|
||||
- `user_get_total_participants`
|
||||
* The users_search_sql function parameter $searchanywhere has been change to $searchtype for different type of search. $searchtype is a int parameter and has three constant value:
|
||||
USER_SEARCH_STARTS_WITH: 0, USER_SEARCH_CONTAINS: 1, USER_SEARCH_EXACT_MATCH: 2
|
||||
users_search_sql('User Test 2', '', false) => users_search_sql('Test Street', '', USER_SEARCH_CONTAINS)
|
||||
|
||||
=== 4.2 ===
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2023091300.02; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2023091300.03; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.3dev+ (Build: 20230913)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user