Merge branch 'MDL-35443-wip' of git://github.com/mouneyrac/moodle

This commit is contained in:
Sam Hemelryk 2013-01-09 10:20:46 +13:00
commit 3913743aa3
5 changed files with 371 additions and 3 deletions

View File

@ -118,6 +118,7 @@ $string['missingusername'] = 'Missing username';
$string['missingversionfile'] = 'Coding error: version.php file is missing for the component {$a}';
$string['mobilewsdisabled'] = 'Disabled';
$string['mobilewsenabled'] = 'Enabled';
$string['nocapabilitytouseparameter'] = 'The user does not have the required capability to use the parameter {$a}';
$string['nofunctions'] = 'This service has no functions.';
$string['norequiredcapability'] = 'No required capability';
$string['notoken'] = 'The token list is empty.';

View File

@ -282,6 +282,15 @@ $functions = array(
'capabilities'=> 'moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update',
),
'core_user_get_users_by_field' => array(
'classname' => 'core_user_external',
'methodname' => 'get_users_by_field',
'classpath' => 'user/externallib.php',
'description' => 'Retrieve users information for a specified unique field - If you want to do a user search, use core_user_get_users()',
'type' => 'read',
'capabilities'=> 'moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update',
),
'core_user_get_users_by_id' => array(
'classname' => 'core_user_external',
'methodname' => 'get_users_by_id',

View File

@ -368,6 +368,153 @@ class core_user_external extends external_api {
return null;
}
/**
* Returns description of method parameters
*
* @return external_function_parameters
* @since Moodle 2.4
*/
public static function get_users_by_field_parameters() {
return new external_function_parameters(
array(
'field' => new external_value(PARAM_ALPHA, 'the search field can be
\'id\' or \'idnumber\' or \'username\' or \'email\''),
'values' => new external_multiple_structure(
new external_value(PARAM_RAW, 'the value to match'))
)
);
}
/**
* Get user information for a unique field.
*
* @param string $field
* @param array $values
* @return array An array of arrays containg user profiles.
* @since Moodle 2.4
*/
public static function get_users_by_field($field, $values) {
global $CFG, $USER, $DB;
require_once($CFG->dirroot . "/user/lib.php");
$params = self::validate_parameters(self::get_users_by_field_parameters(),
array('field' => $field, 'values' => $values));
// This array will keep all the users that are allowed to be searched,
// according to the current user's privileges.
$cleanedvalues = array();
switch ($field) {
case 'id':
$paramtype = PARAM_INT;
break;
case 'idnumber':
$paramtype = PARAM_RAW;
break;
case 'username':
$paramtype = PARAM_USERNAME;
break;
case 'email':
$paramtype = PARAM_EMAIL;
break;
default:
throw new coding_exception('invalid field parameter',
'The search field \'' . $field . '\' is not supported, look at the web service documentation');
}
// Clean the values
foreach ($values as $value) {
$cleanedvalue = clean_param($value, $paramtype);
if ( $value != $cleanedvalue) {
throw new invalid_parameter_exception('The field \'' . $field .
'\' value is invalid: ' . $value . '(cleaned value: '.$cleanedvalue.')');
}
$cleanedvalues[] = $cleanedvalue;
}
// Retrieve the users
$users = $DB->get_records_list('user', $field, $cleanedvalues, 'id');
// Finally retrieve each users information
$returnedusers = array();
foreach ($users as $user) {
$userdetails = user_get_user_details_courses($user);
// Return the user only if the searched field is returned
// Otherwise it means that the $USER was not allowed to search the returned user
if (!empty($userdetails) and !empty($userdetails[$field])) {
$returnedusers[] = $userdetails;
}
}
return $returnedusers;
}
/**
* Returns description of method result value
*
* @return external_multiple_structure
* @since Moodle 2.4
*/
public static function get_users_by_field_returns() {
return new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'ID of the user'),
'username' => new external_value(PARAM_USERNAME, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL),
'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
'fullname' => new external_value(PARAM_NOTAGS, 'The fullname of the user'),
'email' => new external_value(PARAM_EMAIL, 'An email address', VALUE_OPTIONAL),
'address' => new external_value(PARAM_TEXT, 'Postal address', VALUE_OPTIONAL),
'phone1' => new external_value(PARAM_NOTAGS, 'Phone 1', VALUE_OPTIONAL),
'phone2' => new external_value(PARAM_NOTAGS, 'Phone 2', VALUE_OPTIONAL),
'icq' => new external_value(PARAM_NOTAGS, 'icq number', VALUE_OPTIONAL),
'skype' => new external_value(PARAM_NOTAGS, 'skype id', VALUE_OPTIONAL),
'yahoo' => new external_value(PARAM_NOTAGS, 'yahoo id', VALUE_OPTIONAL),
'aim' => new external_value(PARAM_NOTAGS, 'aim id', VALUE_OPTIONAL),
'msn' => new external_value(PARAM_NOTAGS, 'msn number', VALUE_OPTIONAL),
'department' => new external_value(PARAM_TEXT, 'department', VALUE_OPTIONAL),
'institution' => new external_value(PARAM_TEXT, 'institution', VALUE_OPTIONAL),
'idnumber' => new external_value(PARAM_RAW, 'An arbitrary ID code number perhaps from the institution', VALUE_OPTIONAL),
'interests' => new external_value(PARAM_TEXT, 'user interests (separated by commas)', VALUE_OPTIONAL),
'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
'lastaccess' => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
'auth' => new external_value(PARAM_PLUGIN, 'Auth plugins include manual, ldap, imap, etc', VALUE_OPTIONAL),
'confirmed' => new external_value(PARAM_INT, 'Active user: 1 if confirmed, 0 otherwise', VALUE_OPTIONAL),
'lang' => new external_value(PARAM_SAFEDIR, 'Language code such as "en", must exist on server', VALUE_OPTIONAL),
'theme' => new external_value(PARAM_PLUGIN, 'Theme name such as "standard", must exist on server', VALUE_OPTIONAL),
'timezone' => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
'mailformat' => new external_value(PARAM_INT, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
'city' => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
'url' => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
'country' => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
'profileimageurlsmall' => new external_value(PARAM_URL, 'User image profile URL - small version'),
'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version'),
'customfields' => new external_multiple_structure(
new external_single_structure(
array(
'type' => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
)
), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
'preferences' => new external_multiple_structure(
new external_single_structure(
array(
'name' => new external_value(PARAM_ALPHANUMEXT, 'The name of the preferences'),
'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
)
), 'User preferences', VALUE_OPTIONAL)
)
)
);
}
/**
* Returns description of method parameters
*
@ -938,4 +1085,4 @@ class moodle_user_external extends external_api {
require_once($CFG->dirroot . '/enrol/externallib.php');
return core_enrol_external::get_enrolled_users_returns();
}
}
}

View File

@ -244,7 +244,7 @@ function user_get_user_details($user, $course = null, array $userfields = array(
} else {
$canviewhiddenuserfields = has_capability('moodle/user:viewhiddendetails', $context);
}
$canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
$canviewfullnames = has_capability('moodle/site:viewfullnames', $context);
if (!empty($course)) {
$canviewuseremail = has_capability('moodle/course:useremail', $context);
} else {
@ -484,6 +484,59 @@ function user_get_user_details($user, $course = null, array $userfields = array(
return $userdetails;
}
/**
* Tries to obtain user details, either recurring directly to the user's system profile
* or through one of the user's course enrollments (course profile).
*
* @param object $user The user.
* @return array if unsuccessful or the allowed user details.
*/
function user_get_user_details_courses($user) {
global $USER;
$userdetails = null;
// Get the courses that the user is enrolled in (only active).
$courses = enrol_get_users_courses($user->id, true);
$systemprofile = false;
if (can_view_user_details_cap($user) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
$systemprofile = true;
}
// Try using system profile.
if ($systemprofile) {
$userdetails = user_get_user_details($user, null);
} else {
// Try through course profile.
foreach ($courses as $course) {
if ($can_view_user_details_cap($user, $course) || ($user->id == $USER->id) || has_coursecontact_role($user->id)) {
$userdetails = user_get_user_details($user, $course);
}
}
}
return $userdetails;
}
/**
* Check if $USER have the necessary capabilities to obtain user details.
*
* @param object $user
* @param object $course if null then only consider system profile otherwise also consider the course's profile.
* @return bool true if $USER can view user details.
*/
function can_view_user_details_cap($user, $course = null) {
// Check $USER has the capability to view the user details at user context.
$usercontext = get_context_instance(CONTEXT_USER, $user->id);
$result = has_capability('moodle/user:viewdetails', $usercontext);
// Otherwise can $USER see them at course context.
if (!$result && !empty($course)) {
$context = get_context_instance(CONTEXT_COURSE, $course->id);
$result = has_capability('moodle/user:viewdetails', $context);
}
return $result;
}
/**
* Return a list of page types
* @param string $pagetype current page type
@ -492,4 +545,4 @@ function user_get_user_details($user, $course = null, array $userfields = array(
*/
function user_page_type_list($pagetype, $parentcontext, $currentcontext) {
return array('user-profile'=>get_string('page-user-profile', 'pagetype'));
}
}

View File

@ -33,6 +33,164 @@ require_once($CFG->dirroot . '/user/externallib.php');
class core_user_external_testcase extends externallib_advanced_testcase {
/**
* Test get_users_by_field
*/
public function test_get_users_by_field() {
global $USER, $CFG;
$this->resetAfterTest(true);
$course = self::getDataGenerator()->create_course();
$user1 = array(
'username' => 'usernametest1',
'idnumber' => 'idnumbertest1',
'firstname' => 'First Name User Test 1',
'lastname' => 'Last Name User Test 1',
'email' => 'usertest1@email.com',
'address' => '2 Test Street Perth 6000 WA',
'phone1' => '01010101010',
'phone2' => '02020203',
'icq' => 'testuser1',
'skype' => 'testuser1',
'yahoo' => 'testuser1',
'aim' => 'testuser1',
'msn' => 'testuser1',
'department' => 'Department of user 1',
'institution' => 'Institution of user 1',
'description' => 'This is a description for user 1',
'descriptionformat' => FORMAT_MOODLE,
'city' => 'Perth',
'url' => 'http://moodle.org',
'country' => 'au'
);
$user1 = self::getDataGenerator()->create_user($user1);
if (!empty($CFG->usetags)) {
require_once($CFG->dirroot . '/user/editlib.php');
require_once($CFG->dirroot . '/tag/lib.php');
$user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking');
useredit_update_interests($user1, $user1->interests);
}
$user2 = self::getDataGenerator()->create_user(
array('username' => 'usernametest2', 'idnumber' => 'idnumbertest2'));
$generatedusers = array();
$generatedusers[$user1->id] = $user1;
$generatedusers[$user2->id] = $user2;
$context = context_course::instance($course->id);
$roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id);
// Enrol the users in the course.
// We use the manual plugin.
$enrol = enrol_get_plugin('manual');
$enrolinstances = enrol_get_instances($course->id, true);
foreach ($enrolinstances as $courseenrolinstance) {
if ($courseenrolinstance->enrol == "manual") {
$instance = $courseenrolinstance;
break;
}
}
$enrol->enrol_user($instance, $user1->id, $roleid);
$enrol->enrol_user($instance, $user2->id, $roleid);
$enrol->enrol_user($instance, $USER->id, $roleid);
// call as admin and receive all possible fields.
$this->setAdminUser();
$fieldstosearch = array('id', 'idnumber', 'username', 'email');
foreach ($fieldstosearch as $fieldtosearch) {
// Call the external function.
$returnedusers = core_user_external::get_users_by_field($fieldtosearch,
array($USER->{$fieldtosearch}, $user1->{$fieldtosearch}, $user2->{$fieldtosearch}));
// Expected result differ following the searched field
// Admin user in the PHPunit framework doesn't have email or idnumber.
if ($fieldtosearch == 'email' or $fieldtosearch == 'idnumber') {
$expectedreturnedusers = 2;
} else {
$expectedreturnedusers = 3;
}
// Check we retrieve the good total number of enrolled users + no error on capability.
$this->assertEquals($expectedreturnedusers, count($returnedusers));
foreach($returnedusers as $returneduser) {
$generateduser = ($returneduser['id'] == $USER->id) ?
$USER : $generatedusers[$returneduser['id']];
$this->assertEquals($generateduser->username, $returneduser['username']);
if (!empty($generateduser->idnumber)) {
$this->assertEquals($generateduser->idnumber, $returneduser['idnumber']);
}
$this->assertEquals($generateduser->firstname, $returneduser['firstname']);
$this->assertEquals($generateduser->lastname, $returneduser['lastname']);
if ($generateduser->email != $USER->email) { //don't check the tmp modified $USER email
$this->assertEquals($generateduser->email, $returneduser['email']);
}
if (!empty($generateduser->address)) {
$this->assertEquals($generateduser->address, $returneduser['address']);
}
if (!empty($generateduser->phone1)) {
$this->assertEquals($generateduser->phone1, $returneduser['phone1']);
}
if (!empty($generateduser->phone2)) {
$this->assertEquals($generateduser->phone2, $returneduser['phone2']);
}
if (!empty($generateduser->icq)) {
$this->assertEquals($generateduser->icq, $returneduser['icq']);
}
if (!empty($generateduser->skype)) {
$this->assertEquals($generateduser->skype, $returneduser['skype']);
}
if (!empty($generateduser->yahoo)) {
$this->assertEquals($generateduser->yahoo, $returneduser['yahoo']);
}
if (!empty($generateduser->aim)) {
$this->assertEquals($generateduser->aim, $returneduser['aim']);
}
if (!empty($generateduser->msn)) {
$this->assertEquals($generateduser->msn, $returneduser['msn']);
}
if (!empty($generateduser->department)) {
$this->assertEquals($generateduser->department, $returneduser['department']);
}
if (!empty($generateduser->institution)) {
$this->assertEquals($generateduser->institution, $returneduser['institution']);
}
if (!empty($generateduser->description)) {
$this->assertEquals($generateduser->description, $returneduser['description']);
}
if (!empty($generateduser->descriptionformat)) {
$this->assertEquals(FORMAT_HTML, $returneduser['descriptionformat']);
}
if (!empty($generateduser->city)) {
$this->assertEquals($generateduser->city, $returneduser['city']);
}
if (!empty($generateduser->country)) {
$this->assertEquals($generateduser->country, $returneduser['country']);
}
if (!empty($generateduser->url)) {
$this->assertEquals($generateduser->url, $returneduser['url']);
}
if (!empty($CFG->usetags) and !empty($generateduser->interests)) {
$this->assertEquals(implode(', ', $generateduser->interests), $returneduser['interests']);
}
}
}
// Test that no result are returned for search by username if we are not admin
$this->setGuestUser();
// Call the external function.
$returnedusers = core_user_external::get_users_by_field('username',
array($USER->username, $user1->username, $user2->username));
// Only the own $USER username should be returned
$this->assertEquals(1, count($returnedusers));
}
/**
* Test get_course_user_profiles
*/