Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * User external PHPunit tests 19 * 20 * @package core_user 21 * @category external 22 * @copyright 2012 Jerome Mouneyrac 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @since Moodle 2.4 25 */ 26 27 namespace core_user; 28 29 use core_files_external; 30 use core_user_external; 31 use externallib_advanced_testcase; 32 33 defined('MOODLE_INTERNAL') || die(); 34 35 global $CFG; 36 37 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 38 require_once($CFG->dirroot . '/user/externallib.php'); 39 require_once($CFG->dirroot . '/files/externallib.php'); 40 41 class externallib_test extends externallib_advanced_testcase { 42 43 /** 44 * Test get_users 45 */ 46 public function test_get_users() { 47 global $USER, $CFG; 48 49 $this->resetAfterTest(true); 50 51 $course = self::getDataGenerator()->create_course(); 52 53 $user1 = array( 54 'username' => 'usernametest1', 55 'idnumber' => 'idnumbertest1', 56 'firstname' => 'First Name User Test 1', 57 'lastname' => 'Last Name User Test 1', 58 'email' => 'usertest1@example.com', 59 'address' => '2 Test Street Perth 6000 WA', 60 'phone1' => '01010101010', 61 'phone2' => '02020203', 62 'department' => 'Department of user 1', 63 'institution' => 'Institution of user 1', 64 'description' => 'This is a description for user 1', 65 'descriptionformat' => FORMAT_MOODLE, 66 'city' => 'Perth', 67 'country' => 'AU' 68 ); 69 70 $user1 = self::getDataGenerator()->create_user($user1); 71 set_config('usetags', 1); 72 require_once($CFG->dirroot . '/user/editlib.php'); 73 $user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking'); 74 useredit_update_interests($user1, $user1->interests); 75 76 $user2 = self::getDataGenerator()->create_user( 77 array('username' => 'usernametest2', 'idnumber' => 'idnumbertest2')); 78 79 $generatedusers = array(); 80 $generatedusers[$user1->id] = $user1; 81 $generatedusers[$user2->id] = $user2; 82 83 $context = \context_course::instance($course->id); 84 $roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id); 85 86 // Enrol the users in the course. 87 $this->getDataGenerator()->enrol_user($user1->id, $course->id, $roleid); 88 $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleid); 89 $this->getDataGenerator()->enrol_user($USER->id, $course->id, $roleid); 90 91 // call as admin and receive all possible fields. 92 $this->setAdminUser(); 93 94 $searchparams = array( 95 array('key' => 'invalidkey', 'value' => 'invalidkey'), 96 array('key' => 'email', 'value' => $user1->email), 97 array('key' => 'firstname', 'value' => $user1->firstname)); 98 99 // Call the external function. 100 $result = core_user_external::get_users($searchparams); 101 102 // We need to execute the return values cleaning process to simulate the web service server 103 $result = \external_api::clean_returnvalue(core_user_external::get_users_returns(), $result); 104 105 // Check we retrieve the good total number of enrolled users + no error on capability. 106 $expectedreturnedusers = 1; 107 $returnedusers = $result['users']; 108 $this->assertEquals($expectedreturnedusers, count($returnedusers)); 109 110 foreach($returnedusers as $returneduser) { 111 $generateduser = ($returneduser['id'] == $USER->id) ? 112 $USER : $generatedusers[$returneduser['id']]; 113 $this->assertEquals($generateduser->username, $returneduser['username']); 114 if (!empty($generateduser->idnumber)) { 115 $this->assertEquals($generateduser->idnumber, $returneduser['idnumber']); 116 } 117 $this->assertEquals($generateduser->firstname, $returneduser['firstname']); 118 $this->assertEquals($generateduser->lastname, $returneduser['lastname']); 119 if ($generateduser->email != $USER->email) { // Don't check the tmp modified $USER email. 120 $this->assertEquals($generateduser->email, $returneduser['email']); 121 } 122 if (!empty($generateduser->address)) { 123 $this->assertEquals($generateduser->address, $returneduser['address']); 124 } 125 if (!empty($generateduser->phone1)) { 126 $this->assertEquals($generateduser->phone1, $returneduser['phone1']); 127 } 128 if (!empty($generateduser->phone2)) { 129 $this->assertEquals($generateduser->phone2, $returneduser['phone2']); 130 } 131 if (!empty($generateduser->department)) { 132 $this->assertEquals($generateduser->department, $returneduser['department']); 133 } 134 if (!empty($generateduser->institution)) { 135 $this->assertEquals($generateduser->institution, $returneduser['institution']); 136 } 137 if (!empty($generateduser->description)) { 138 $this->assertEquals($generateduser->description, $returneduser['description']); 139 } 140 if (!empty($generateduser->descriptionformat)) { 141 $this->assertEquals(FORMAT_HTML, $returneduser['descriptionformat']); 142 } 143 if (!empty($generateduser->city)) { 144 $this->assertEquals($generateduser->city, $returneduser['city']); 145 } 146 if (!empty($generateduser->country)) { 147 $this->assertEquals($generateduser->country, $returneduser['country']); 148 } 149 if (!empty($CFG->usetags) and !empty($generateduser->interests)) { 150 $this->assertEquals(implode(', ', $generateduser->interests), $returneduser['interests']); 151 } 152 } 153 154 // Test the invalid key warning. 155 $warnings = $result['warnings']; 156 $this->assertEquals(count($warnings), 1); 157 $warning = array_pop($warnings); 158 $this->assertEquals($warning['item'], 'invalidkey'); 159 $this->assertEquals($warning['warningcode'], 'invalidfieldparameter'); 160 161 // Test sending twice the same search field. 162 try { 163 $searchparams = array( 164 array('key' => 'firstname', 'value' => 'Canard'), 165 array('key' => 'email', 'value' => $user1->email), 166 array('key' => 'firstname', 'value' => $user1->firstname)); 167 168 // Call the external function. 169 $result = core_user_external::get_users($searchparams); 170 $this->fail('Expecting \'keyalreadyset\' moodle_exception to be thrown.'); 171 } catch (\moodle_exception $e) { 172 $this->assertEquals('keyalreadyset', $e->errorcode); 173 } catch (\Exception $e) { 174 $this->fail('Expecting \'keyalreadyset\' moodle_exception to be thrown.'); 175 } 176 } 177 178 /** 179 * Test get_users_by_field 180 */ 181 public function test_get_users_by_field() { 182 global $USER, $CFG; 183 184 $this->resetAfterTest(true); 185 186 $course = self::getDataGenerator()->create_course(); 187 $user1 = array( 188 'username' => 'usernametest1', 189 'idnumber' => 'idnumbertest1', 190 'firstname' => 'First Name User Test 1', 191 'lastname' => 'Last Name User Test 1', 192 'email' => 'usertest1@example.com', 193 'address' => '2 Test Street Perth 6000 WA', 194 'phone1' => '01010101010', 195 'phone2' => '02020203', 196 'department' => 'Department of user 1', 197 'institution' => 'Institution of user 1', 198 'description' => 'This is a description for user 1', 199 'descriptionformat' => FORMAT_MOODLE, 200 'city' => 'Perth', 201 'country' => 'AU', 202 ); 203 $user1 = self::getDataGenerator()->create_user($user1); 204 if (!empty($CFG->usetags)) { 205 require_once($CFG->dirroot . '/user/editlib.php'); 206 $user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking'); 207 useredit_update_interests($user1, $user1->interests); 208 } 209 $user2 = self::getDataGenerator()->create_user( 210 array('username' => 'usernametest2', 'idnumber' => 'idnumbertest2')); 211 212 $generatedusers = array(); 213 $generatedusers[$user1->id] = $user1; 214 $generatedusers[$user2->id] = $user2; 215 216 $context = \context_course::instance($course->id); 217 $roleid = $this->assignUserCapability('moodle/user:viewdetails', $context->id); 218 219 // Enrol the users in the course. 220 $this->getDataGenerator()->enrol_user($user1->id, $course->id, $roleid, 'manual'); 221 $this->getDataGenerator()->enrol_user($user2->id, $course->id, $roleid, 'manual'); 222 $this->getDataGenerator()->enrol_user($USER->id, $course->id, $roleid, 'manual'); 223 224 // call as admin and receive all possible fields. 225 $this->setAdminUser(); 226 227 $fieldstosearch = array('id', 'idnumber', 'username', 'email'); 228 229 foreach ($fieldstosearch as $fieldtosearch) { 230 231 // Call the external function. 232 $returnedusers = core_user_external::get_users_by_field($fieldtosearch, 233 array($USER->{$fieldtosearch}, $user1->{$fieldtosearch}, $user2->{$fieldtosearch})); 234 $returnedusers = \external_api::clean_returnvalue(core_user_external::get_users_by_field_returns(), $returnedusers); 235 236 // Expected result differ following the searched field 237 // Admin user in the PHPunit framework doesn't have an idnumber. 238 if ($fieldtosearch == 'idnumber') { 239 $expectedreturnedusers = 2; 240 } else { 241 $expectedreturnedusers = 3; 242 } 243 244 // Check we retrieve the good total number of enrolled users + no error on capability. 245 $this->assertEquals($expectedreturnedusers, count($returnedusers)); 246 247 foreach($returnedusers as $returneduser) { 248 $generateduser = ($returneduser['id'] == $USER->id) ? 249 $USER : $generatedusers[$returneduser['id']]; 250 $this->assertEquals($generateduser->username, $returneduser['username']); 251 if (!empty($generateduser->idnumber)) { 252 $this->assertEquals($generateduser->idnumber, $returneduser['idnumber']); 253 } 254 $this->assertEquals($generateduser->firstname, $returneduser['firstname']); 255 $this->assertEquals($generateduser->lastname, $returneduser['lastname']); 256 if ($generateduser->email != $USER->email) { //don't check the tmp modified $USER email 257 $this->assertEquals($generateduser->email, $returneduser['email']); 258 } 259 if (!empty($generateduser->address)) { 260 $this->assertEquals($generateduser->address, $returneduser['address']); 261 } 262 if (!empty($generateduser->phone1)) { 263 $this->assertEquals($generateduser->phone1, $returneduser['phone1']); 264 } 265 if (!empty($generateduser->phone2)) { 266 $this->assertEquals($generateduser->phone2, $returneduser['phone2']); 267 } 268 if (!empty($generateduser->department)) { 269 $this->assertEquals($generateduser->department, $returneduser['department']); 270 } 271 if (!empty($generateduser->institution)) { 272 $this->assertEquals($generateduser->institution, $returneduser['institution']); 273 } 274 if (!empty($generateduser->description)) { 275 $this->assertEquals($generateduser->description, $returneduser['description']); 276 } 277 if (!empty($generateduser->descriptionformat) and isset($returneduser['descriptionformat'])) { 278 $this->assertEquals($generateduser->descriptionformat, $returneduser['descriptionformat']); 279 } 280 if (!empty($generateduser->city)) { 281 $this->assertEquals($generateduser->city, $returneduser['city']); 282 } 283 if (!empty($generateduser->country)) { 284 $this->assertEquals($generateduser->country, $returneduser['country']); 285 } 286 if (!empty($CFG->usetags) and !empty($generateduser->interests)) { 287 $this->assertEquals(implode(', ', $generateduser->interests), $returneduser['interests']); 288 } 289 // Default language and no theme were used for the user. 290 $this->assertEquals($CFG->lang, $returneduser['lang']); 291 $this->assertEmpty($returneduser['theme']); 292 } 293 } 294 295 // Test that no result are returned for search by username if we are not admin 296 $this->setGuestUser(); 297 298 // Call the external function. 299 $returnedusers = core_user_external::get_users_by_field('username', 300 array($USER->username, $user1->username, $user2->username)); 301 $returnedusers = \external_api::clean_returnvalue(core_user_external::get_users_by_field_returns(), $returnedusers); 302 303 // Only the own $USER username should be returned 304 $this->assertEquals(1, count($returnedusers)); 305 306 // And finally test as one of the enrolled users. 307 $this->setUser($user1); 308 309 // Call the external function. 310 $returnedusers = core_user_external::get_users_by_field('username', 311 array($USER->username, $user1->username, $user2->username)); 312 $returnedusers = \external_api::clean_returnvalue(core_user_external::get_users_by_field_returns(), $returnedusers); 313 314 // Only the own $USER username should be returned still. 315 $this->assertEquals(1, count($returnedusers)); 316 } 317 318 public function get_course_user_profiles_setup($capability) { 319 global $USER, $CFG; 320 321 $this->resetAfterTest(true); 322 323 $return = new \stdClass(); 324 325 // Create the course and fetch its context. 326 $return->course = self::getDataGenerator()->create_course(); 327 $return->user1 = array( 328 'username' => 'usernametest1', 329 'idnumber' => 'idnumbertest1', 330 'firstname' => 'First Name User Test 1', 331 'lastname' => 'Last Name User Test 1', 332 'email' => 'usertest1@example.com', 333 'address' => '2 Test Street Perth 6000 WA', 334 'phone1' => '01010101010', 335 'phone2' => '02020203', 336 'department' => 'Department of user 1', 337 'institution' => 'Institution of user 1', 338 'description' => 'This is a description for user 1', 339 'descriptionformat' => FORMAT_MOODLE, 340 'city' => 'Perth', 341 'country' => 'AU' 342 ); 343 $return->user1 = self::getDataGenerator()->create_user($return->user1); 344 if (!empty($CFG->usetags)) { 345 require_once($CFG->dirroot . '/user/editlib.php'); 346 $return->user1->interests = array('Cinema', 'Tennis', 'Dance', 'Guitar', 'Cooking'); 347 useredit_update_interests($return->user1, $return->user1->interests); 348 } 349 $return->user2 = self::getDataGenerator()->create_user(); 350 351 $context = \context_course::instance($return->course->id); 352 $return->roleid = $this->assignUserCapability($capability, $context->id); 353 354 // Enrol the users in the course. 355 $this->getDataGenerator()->enrol_user($return->user1->id, $return->course->id, $return->roleid, 'manual'); 356 $this->getDataGenerator()->enrol_user($return->user2->id, $return->course->id, $return->roleid, 'manual'); 357 $this->getDataGenerator()->enrol_user($USER->id, $return->course->id, $return->roleid, 'manual'); 358 359 return $return; 360 } 361 362 /** 363 * Test get_course_user_profiles 364 */ 365 public function test_get_course_user_profiles() { 366 global $USER, $CFG; 367 368 $this->resetAfterTest(true); 369 370 $data = $this->get_course_user_profiles_setup('moodle/user:viewdetails'); 371 372 // Call the external function. 373 $enrolledusers = core_user_external::get_course_user_profiles(array( 374 array('userid' => $USER->id, 'courseid' => $data->course->id))); 375 376 // We need to execute the return values cleaning process to simulate the web service server. 377 $enrolledusers = \external_api::clean_returnvalue(core_user_external::get_course_user_profiles_returns(), $enrolledusers); 378 379 // Check we retrieve the good total number of enrolled users + no error on capability. 380 $this->assertEquals(1, count($enrolledusers)); 381 } 382 383 public function test_get_user_course_profile_as_admin() { 384 global $USER, $CFG; 385 386 global $USER, $CFG; 387 388 $this->resetAfterTest(true); 389 390 $data = $this->get_course_user_profiles_setup('moodle/user:viewdetails'); 391 392 // Do the same call as admin to receive all possible fields. 393 $this->setAdminUser(); 394 $USER->email = "admin@example.com"; 395 396 // Call the external function. 397 $enrolledusers = core_user_external::get_course_user_profiles(array( 398 array('userid' => $data->user1->id, 'courseid' => $data->course->id))); 399 400 // We need to execute the return values cleaning process to simulate the web service server. 401 $enrolledusers = \external_api::clean_returnvalue(core_user_external::get_course_user_profiles_returns(), $enrolledusers); 402 403 foreach($enrolledusers as $enrolleduser) { 404 if ($enrolleduser['username'] == $data->user1->username) { 405 $this->assertEquals($data->user1->idnumber, $enrolleduser['idnumber']); 406 $this->assertEquals($data->user1->firstname, $enrolleduser['firstname']); 407 $this->assertEquals($data->user1->lastname, $enrolleduser['lastname']); 408 $this->assertEquals($data->user1->email, $enrolleduser['email']); 409 $this->assertEquals($data->user1->address, $enrolleduser['address']); 410 $this->assertEquals($data->user1->phone1, $enrolleduser['phone1']); 411 $this->assertEquals($data->user1->phone2, $enrolleduser['phone2']); 412 $this->assertEquals($data->user1->department, $enrolleduser['department']); 413 $this->assertEquals($data->user1->institution, $enrolleduser['institution']); 414 $this->assertEquals($data->user1->description, $enrolleduser['description']); 415 $this->assertEquals(FORMAT_HTML, $enrolleduser['descriptionformat']); 416 $this->assertEquals($data->user1->city, $enrolleduser['city']); 417 $this->assertEquals($data->user1->country, $enrolleduser['country']); 418 if (!empty($CFG->usetags)) { 419 $this->assertEquals(implode(', ', $data->user1->interests), $enrolleduser['interests']); 420 } 421 } 422 } 423 } 424 425 /** 426 * Test create_users 427 */ 428 public function test_create_users() { 429 global $DB; 430 431 $this->resetAfterTest(true); 432 433 $user1 = array( 434 'username' => 'usernametest1', 435 'password' => 'Moodle2012!', 436 'idnumber' => 'idnumbertest1', 437 'firstname' => 'First Name User Test 1', 438 'lastname' => 'Last Name User Test 1', 439 'middlename' => 'Middle Name User Test 1', 440 'lastnamephonetic' => '最後のお名前のテスト一号', 441 'firstnamephonetic' => 'お名前のテスト一号', 442 'alternatename' => 'Alternate Name User Test 1', 443 'email' => 'usertest1@example.com', 444 'description' => 'This is a description for user 1', 445 'city' => 'Perth', 446 'country' => 'AU', 447 'preferences' => [[ 448 'type' => 'htmleditor', 449 'value' => 'atto' 450 ], [ 451 'type' => 'invalidpreference', 452 'value' => 'abcd' 453 ] 454 ], 455 'department' => 'College of Science', 456 'institution' => 'National Institute of Physics', 457 'phone1' => '01 2345 6789', 458 'maildisplay' => 1, 459 'interests' => 'badminton, basketball, cooking, ' 460 ); 461 462 // User with an authentication method done externally. 463 $user2 = array( 464 'username' => 'usernametest2', 465 'firstname' => 'First Name User Test 2', 466 'lastname' => 'Last Name User Test 2', 467 'email' => 'usertest2@example.com', 468 'auth' => 'oauth2' 469 ); 470 471 $context = \context_system::instance(); 472 $roleid = $this->assignUserCapability('moodle/user:create', $context->id); 473 $this->assignUserCapability('moodle/user:editprofile', $context->id, $roleid); 474 475 // Call the external function. 476 $createdusers = core_user_external::create_users(array($user1, $user2)); 477 478 // We need to execute the return values cleaning process to simulate the web service server. 479 $createdusers = \external_api::clean_returnvalue(core_user_external::create_users_returns(), $createdusers); 480 481 // Check we retrieve the good total number of created users + no error on capability. 482 $this->assertCount(2, $createdusers); 483 484 foreach($createdusers as $createduser) { 485 $dbuser = $DB->get_record('user', array('id' => $createduser['id'])); 486 487 if ($createduser['username'] === $user1['username']) { 488 $usertotest = $user1; 489 $this->assertEquals('atto', get_user_preferences('htmleditor', null, $dbuser)); 490 $this->assertEquals(null, get_user_preferences('invalidpreference', null, $dbuser)); 491 // Confirm user interests have been saved. 492 $interests = \core_tag_tag::get_item_tags_array('core', 'user', $createduser['id'], 493 \core_tag_tag::BOTH_STANDARD_AND_NOT, 0, false); 494 // There should be 3 user interests. 495 $this->assertCount(3, $interests); 496 497 } else if ($createduser['username'] === $user2['username']) { 498 $usertotest = $user2; 499 } 500 501 foreach ($dbuser as $property => $value) { 502 if ($property === 'password') { 503 if ($usertotest === $user2) { 504 // External auth mechanisms don't store password in the user table. 505 $this->assertEquals(AUTH_PASSWORD_NOT_CACHED, $value); 506 } else { 507 // Skip hashed passwords. 508 continue; 509 } 510 } 511 // Confirm that the values match. 512 if (isset($usertotest[$property])) { 513 $this->assertEquals($usertotest[$property], $value); 514 } 515 } 516 } 517 518 // Call without required capability 519 $this->unassignUserCapability('moodle/user:create', $context->id, $roleid); 520 $this->expectException('required_capability_exception'); 521 core_user_external::create_users(array($user1)); 522 } 523 524 /** 525 * Test create_users with password and createpassword parameter not set. 526 */ 527 public function test_create_users_empty_password() { 528 $this->resetAfterTest(); 529 $this->setAdminUser(); 530 531 $user = [ 532 'username' => 'usernametest1', 533 'firstname' => 'First Name User Test 1', 534 'lastname' => 'Last Name User Test 1', 535 'email' => 'usertest1@example.com', 536 ]; 537 538 // This should throw an exception because either password or createpassword param must be passed for auth_manual. 539 $this->expectException(\invalid_parameter_exception::class); 540 core_user_external::create_users([$user]); 541 } 542 543 /** 544 * Data provider for \core_user_externallib_testcase::test_create_users_with_same_emails(). 545 */ 546 public function create_users_provider_with_same_emails() { 547 return [ 548 'Same emails allowed, same case' => [ 549 1, false 550 ], 551 'Same emails allowed, different case' => [ 552 1, true 553 ], 554 'Same emails disallowed, same case' => [ 555 0, false 556 ], 557 'Same emails disallowed, different case' => [ 558 0, true 559 ], 560 ]; 561 } 562 563 /** 564 * Test for \core_user_external::create_users() when user using the same email addresses are being created. 565 * 566 * @dataProvider create_users_provider_with_same_emails 567 * @param int $sameemailallowed The value to set for $CFG->allowaccountssameemail. 568 * @param boolean $differentcase Whether to user a different case for the other user. 569 */ 570 public function test_create_users_with_same_emails($sameemailallowed, $differentcase) { 571 global $DB; 572 573 $this->resetAfterTest(); 574 $this->setAdminUser(); 575 576 // Allow multiple users with the same email address. 577 set_config('allowaccountssameemail', $sameemailallowed); 578 $users = [ 579 [ 580 'username' => 's1', 581 'firstname' => 'Johnny', 582 'lastname' => 'Bravo', 583 'email' => 's1@example.com', 584 'password' => 'Passw0rd!' 585 ], 586 [ 587 'username' => 's2', 588 'firstname' => 'John', 589 'lastname' => 'Doe', 590 'email' => $differentcase ? 'S1@EXAMPLE.COM' : 's1@example.com', 591 'password' => 'Passw0rd!' 592 ], 593 ]; 594 595 if (!$sameemailallowed) { 596 // This should throw an exception when $CFG->allowaccountssameemail is empty. 597 $this->expectException(\invalid_parameter_exception::class); 598 } 599 600 // Create our users. 601 core_user_external::create_users($users); 602 603 // Confirm that the users have been created. 604 list($insql, $params) = $DB->get_in_or_equal(['s1', 's2']); 605 $this->assertEquals(2, $DB->count_records_select('user', 'username ' . $insql, $params)); 606 } 607 608 /** 609 * Test create_users with invalid parameters 610 * 611 * @dataProvider data_create_users_invalid_parameter 612 * @param array $data User data to attempt to register. 613 * @param string $expectmessage Expected exception message. 614 */ 615 public function test_create_users_invalid_parameter(array $data, $expectmessage) { 616 global $USER, $CFG, $DB; 617 618 $this->resetAfterTest(true); 619 $this->assignUserCapability('moodle/user:create', SYSCONTEXTID); 620 621 $this->expectException('invalid_parameter_exception'); 622 $this->expectExceptionMessage($expectmessage); 623 624 core_user_external::create_users(array($data)); 625 } 626 627 /** 628 * Data provider for {@see self::test_create_users_invalid_parameter()}. 629 * 630 * @return array 631 */ 632 public function data_create_users_invalid_parameter() { 633 return [ 634 'blank_username' => [ 635 'data' => [ 636 'username' => '', 637 'firstname' => 'Foo', 638 'lastname' => 'Bar', 639 'email' => 'foobar@example.com', 640 'createpassword' => 1, 641 ], 642 'expectmessage' => 'The field username cannot be blank', 643 ], 644 'blank_firtname' => [ 645 'data' => [ 646 'username' => 'foobar', 647 'firstname' => "\t \n", 648 'lastname' => 'Bar', 649 'email' => 'foobar@example.com', 650 'createpassword' => 1, 651 ], 652 'expectmessage' => 'The field firstname cannot be blank', 653 ], 654 'blank_lastname' => [ 655 'data' => [ 656 'username' => 'foobar', 657 'firstname' => '0', 658 'lastname' => ' ', 659 'email' => 'foobar@example.com', 660 'createpassword' => 1, 661 ], 662 'expectmessage' => 'The field lastname cannot be blank', 663 ], 664 'invalid_email' => [ 665 'data' => [ 666 'username' => 'foobar', 667 'firstname' => 'Foo', 668 'lastname' => 'Bar', 669 'email' => '@foobar', 670 'createpassword' => 1, 671 ], 672 'expectmessage' => 'Email address is invalid', 673 ], 674 'missing_password' => [ 675 'data' => [ 676 'username' => 'foobar', 677 'firstname' => 'Foo', 678 'lastname' => 'Bar', 679 'email' => 'foobar@example.com', 680 ], 681 'expectmessage' => 'Invalid password: you must provide a password, or set createpassword', 682 ], 683 ]; 684 } 685 686 /** 687 * Test delete_users 688 */ 689 public function test_delete_users() { 690 global $USER, $CFG, $DB; 691 692 $this->resetAfterTest(true); 693 694 $user1 = self::getDataGenerator()->create_user(); 695 $user2 = self::getDataGenerator()->create_user(); 696 697 // Check the users were correctly created. 698 $this->assertEquals(2, $DB->count_records_select('user', 'deleted = 0 AND (id = :userid1 OR id = :userid2)', 699 array('userid1' => $user1->id, 'userid2' => $user2->id))); 700 701 $context = \context_system::instance(); 702 $roleid = $this->assignUserCapability('moodle/user:delete', $context->id); 703 704 // Call the external function. 705 core_user_external::delete_users(array($user1->id, $user2->id)); 706 707 // Check we retrieve no users + no error on capability. 708 $this->assertEquals(0, $DB->count_records_select('user', 'deleted = 0 AND (id = :userid1 OR id = :userid2)', 709 array('userid1' => $user1->id, 'userid2' => $user2->id))); 710 711 // Call without required capability. 712 $this->unassignUserCapability('moodle/user:delete', $context->id, $roleid); 713 $this->expectException('required_capability_exception'); 714 core_user_external::delete_users(array($user1->id, $user2->id)); 715 } 716 717 /** 718 * Test update_users 719 */ 720 public function test_update_users() { 721 global $USER, $CFG, $DB; 722 723 $this->resetAfterTest(true); 724 725 $wsuser = self::getDataGenerator()->create_user(); 726 self::setUser($wsuser); 727 728 $context = \context_user::instance($USER->id); 729 $contextid = $context->id; 730 $filename = "reddot.png"; 731 $filecontent = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38" 732 . "GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; 733 734 // Call the files api to create a file. 735 $draftfile = core_files_external::upload($contextid, 'user', 'draft', 0, '/', 736 $filename, $filecontent, null, null); 737 $draftfile = \external_api::clean_returnvalue(core_files_external::upload_returns(), $draftfile); 738 739 $draftid = $draftfile['itemid']; 740 741 $user1 = self::getDataGenerator()->create_user(); 742 743 $user1 = array( 744 'id' => $user1->id, 745 'username' => 'usernametest1', 746 'password' => 'Moodle2012!', 747 'idnumber' => 'idnumbertest1', 748 'firstname' => 'First Name User Test 1', 749 'lastname' => 'Last Name User Test 1', 750 'middlename' => 'Middle Name User Test 1', 751 'lastnamephonetic' => '最後のお名前のテスト一号', 752 'firstnamephonetic' => 'お名前のテスト一号', 753 'alternatename' => 'Alternate Name User Test 1', 754 'email' => 'usertest1@example.com', 755 'description' => 'This is a description for user 1', 756 'city' => 'Perth', 757 'userpicture' => $draftid, 758 'country' => 'AU', 759 'preferences' => [[ 760 'type' => 'htmleditor', 761 'value' => 'atto' 762 ], [ 763 'type' => 'invialidpreference', 764 'value' => 'abcd' 765 ] 766 ], 767 'department' => 'College of Science', 768 'institution' => 'National Institute of Physics', 769 'phone1' => '01 2345 6789', 770 'maildisplay' => 1, 771 'interests' => 'badminton, basketball, cooking, ' 772 ); 773 774 $context = \context_system::instance(); 775 $roleid = $this->assignUserCapability('moodle/user:update', $context->id); 776 $this->assignUserCapability('moodle/user:editprofile', $context->id, $roleid); 777 778 // Check we can't update deleted users, guest users, site admin. 779 $user2 = $user3 = $user4 = $user1; 780 $user2['id'] = $CFG->siteguest; 781 782 $siteadmins = explode(',', $CFG->siteadmins); 783 $user3['id'] = array_shift($siteadmins); 784 785 $userdeleted = self::getDataGenerator()->create_user(); 786 $user4['id'] = $userdeleted->id; 787 user_delete_user($userdeleted); 788 789 // Call the external function. 790 core_user_external::update_users(array($user1, $user2, $user3, $user4)); 791 792 $dbuser2 = $DB->get_record('user', array('id' => $user2['id'])); 793 $this->assertNotEquals($dbuser2->username, $user2['username']); 794 $dbuser3 = $DB->get_record('user', array('id' => $user3['id'])); 795 $this->assertNotEquals($dbuser3->username, $user3['username']); 796 $dbuser4 = $DB->get_record('user', array('id' => $user4['id'])); 797 $this->assertNotEquals($dbuser4->username, $user4['username']); 798 799 $dbuser = $DB->get_record('user', array('id' => $user1['id'])); 800 $this->assertEquals($dbuser->username, $user1['username']); 801 $this->assertEquals($dbuser->idnumber, $user1['idnumber']); 802 $this->assertEquals($dbuser->firstname, $user1['firstname']); 803 $this->assertEquals($dbuser->lastname, $user1['lastname']); 804 $this->assertEquals($dbuser->email, $user1['email']); 805 $this->assertEquals($dbuser->description, $user1['description']); 806 $this->assertEquals($dbuser->city, $user1['city']); 807 $this->assertEquals($dbuser->country, $user1['country']); 808 $this->assertNotEquals(0, $dbuser->picture, 'Picture must be set to the new icon itemid for this user'); 809 $this->assertEquals($dbuser->department, $user1['department']); 810 $this->assertEquals($dbuser->institution, $user1['institution']); 811 $this->assertEquals($dbuser->phone1, $user1['phone1']); 812 $this->assertEquals($dbuser->maildisplay, $user1['maildisplay']); 813 $this->assertEquals('atto', get_user_preferences('htmleditor', null, $dbuser)); 814 $this->assertEquals(null, get_user_preferences('invalidpreference', null, $dbuser)); 815 816 // Confirm user interests have been saved. 817 $interests = \core_tag_tag::get_item_tags_array('core', 'user', $user1['id'], \core_tag_tag::BOTH_STANDARD_AND_NOT, 0, false); 818 // There should be 3 user interests. 819 $this->assertCount(3, $interests); 820 821 // Confirm no picture change when parameter is not supplied. 822 unset($user1['userpicture']); 823 core_user_external::update_users(array($user1)); 824 $dbusernopic = $DB->get_record('user', array('id' => $user1['id'])); 825 $this->assertEquals($dbuser->picture, $dbusernopic->picture, 'Picture not change without the parameter.'); 826 827 // Confirm delete of picture deletes the picture from the user record. 828 $user1['userpicture'] = 0; 829 core_user_external::update_users(array($user1)); 830 $dbuserdelpic = $DB->get_record('user', array('id' => $user1['id'])); 831 $this->assertEquals(0, $dbuserdelpic->picture, 'Picture must be deleted when sent as 0.'); 832 833 834 // Call without required capability. 835 $this->unassignUserCapability('moodle/user:update', $context->id, $roleid); 836 $this->expectException('required_capability_exception'); 837 core_user_external::update_users(array($user1)); 838 } 839 840 /** 841 * Data provider for testing \core_user_external::update_users() for users with same emails 842 * 843 * @return array 844 */ 845 public function users_with_same_emails() { 846 return [ 847 'Same emails not allowed: Update name using exactly the same email' => [ 848 0, 'John', 's1@example.com', 'Johnny', 's1@example.com', false, true 849 ], 850 'Same emails not allowed: Update using someone else\'s email' => [ 851 0, 'John', 's1@example.com', 'Johnny', 's2@example.com', true, false 852 ], 853 'Same emails allowed: Update using someone else\'s email' => [ 854 1, 'John', 's1@example.com', 'Johnny', 's2@example.com', true, true 855 ], 856 'Same emails not allowed: Update using same email but with different case' => [ 857 0, 'John', 's1@example.com', 'Johnny', 'S1@EXAMPLE.COM', false, true 858 ], 859 'Same emails not allowed: Update using another user\'s email similar to user but with different case' => [ 860 0, 'John', 's1@example.com', 'Johnny', 'S1@EXAMPLE.COM', true, false 861 ], 862 'Same emails allowed: Update using another user\'s email similar to user but with different case' => [ 863 1, 'John', 's1@example.com', 'Johnny', 'S1@EXAMPLE.COM', true, true 864 ], 865 ]; 866 } 867 868 /** 869 * Test update_users using similar emails with varying cases. 870 * 871 * @dataProvider users_with_same_emails 872 * @param boolean $allowsameemail The value to set for $CFG->allowaccountssameemail. 873 * @param string $currentname The user's current name. 874 * @param string $currentemail The user's current email. 875 * @param string $newname The user's new name. 876 * @param string $newemail The user's new email. 877 * @param boolean $withanotheruser Whether to create another user that has the same email as the target user's new email. 878 * @param boolean $successexpected Whether we expect that the target user's email/name will be updated. 879 */ 880 public function test_update_users_emails_with_different_cases($allowsameemail, $currentname, $currentemail, 881 $newname, $newemail, $withanotheruser, $successexpected) { 882 global $DB; 883 884 $this->resetAfterTest(); 885 $this->setAdminUser(); 886 887 // Set the value for $CFG->allowaccountssameemail. 888 set_config('allowaccountssameemail', $allowsameemail); 889 890 $generator = self::getDataGenerator(); 891 892 // Create the user that we wish to update. 893 $usertoupdate = $generator->create_user(['email' => $currentemail, 'firstname' => $currentname]); 894 895 if ($withanotheruser) { 896 // Create another user that has the same email as the new email that we'd like to update for our target user. 897 $generator->create_user(['email' => $newemail]); 898 } 899 900 // Build the user update parameters. 901 $updateparams = [ 902 'id' => $usertoupdate->id, 903 'email' => $newemail, 904 'firstname' => $newname 905 ]; 906 // Let's try to update the user's information. 907 core_user_external::update_users([$updateparams]); 908 909 // Fetch the updated user record. 910 $userrecord = $DB->get_record('user', ['id' => $usertoupdate->id], 'id, email, firstname'); 911 912 // If we expect the update to succeed, then the email/name would have been changed. 913 if ($successexpected) { 914 $expectedemail = $newemail; 915 $expectedname = $newname; 916 } else { 917 $expectedemail = $currentemail; 918 $expectedname = $currentname; 919 } 920 // Confirm that our expectations are met. 921 $this->assertEquals($expectedemail, $userrecord->email); 922 $this->assertEquals($expectedname, $userrecord->firstname); 923 } 924 925 /** 926 * Test add_user_private_files 927 */ 928 public function test_add_user_private_files() { 929 global $USER, $CFG, $DB; 930 931 $this->resetAfterTest(true); 932 933 $context = \context_system::instance(); 934 $roleid = $this->assignUserCapability('moodle/user:manageownfiles', $context->id); 935 936 $context = \context_user::instance($USER->id); 937 $contextid = $context->id; 938 $component = "user"; 939 $filearea = "draft"; 940 $itemid = 0; 941 $filepath = "/"; 942 $filename = "Simple.txt"; 943 $filecontent = base64_encode("Let us create a nice simple file"); 944 $contextlevel = null; 945 $instanceid = null; 946 $browser = get_file_browser(); 947 948 // Call the files api to create a file. 949 $draftfile = core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath, 950 $filename, $filecontent, $contextlevel, $instanceid); 951 $draftfile = \external_api::clean_returnvalue(core_files_external::upload_returns(), $draftfile); 952 953 $draftid = $draftfile['itemid']; 954 // Make sure the file was created. 955 $file = $browser->get_file_info($context, $component, $filearea, $draftid, $filepath, $filename); 956 $this->assertNotEmpty($file); 957 958 // Make sure the file does not exist in the user private files. 959 $file = $browser->get_file_info($context, $component, 'private', 0, $filepath, $filename); 960 $this->assertEmpty($file); 961 962 // Call the external function. 963 core_user_external::add_user_private_files($draftid); 964 965 // Make sure the file was added to the user private files. 966 $file = $browser->get_file_info($context, $component, 'private', 0, $filepath, $filename); 967 $this->assertNotEmpty($file); 968 } 969 970 /** 971 * Test add user device 972 */ 973 public function test_add_user_device() { 974 global $USER, $CFG, $DB; 975 976 $this->resetAfterTest(true); 977 978 $device = array( 979 'appid' => 'com.moodle.moodlemobile', 980 'name' => 'occam', 981 'model' => 'Nexus 4', 982 'platform' => 'Android', 983 'version' => '4.2.2', 984 'pushid' => 'apushdkasdfj4835', 985 'uuid' => 'asdnfl348qlksfaasef859' 986 ); 987 988 // Call the external function. 989 core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'], 990 $device['version'], $device['pushid'], $device['uuid']); 991 992 $created = $DB->get_record('user_devices', array('pushid' => $device['pushid'])); 993 $created = (array) $created; 994 995 $this->assertEquals($device, array_intersect_key((array)$created, $device)); 996 997 // Test reuse the same pushid value. 998 $warnings = core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'], 999 $device['version'], $device['pushid'], $device['uuid']); 1000 // We need to execute the return values cleaning process to simulate the web service server. 1001 $warnings = \external_api::clean_returnvalue(core_user_external::add_user_device_returns(), $warnings); 1002 $this->assertCount(1, $warnings); 1003 1004 // Test update an existing device. 1005 $device['pushid'] = 'different than before'; 1006 $warnings = core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'], 1007 $device['version'], $device['pushid'], $device['uuid']); 1008 $warnings = \external_api::clean_returnvalue(core_user_external::add_user_device_returns(), $warnings); 1009 1010 $this->assertEquals(1, $DB->count_records('user_devices')); 1011 $updated = $DB->get_record('user_devices', array('pushid' => $device['pushid'])); 1012 $this->assertEquals($device, array_intersect_key((array)$updated, $device)); 1013 1014 // Test creating a new device just changing the uuid. 1015 $device['uuid'] = 'newuidforthesameuser'; 1016 $device['pushid'] = 'new different than before'; 1017 $warnings = core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'], 1018 $device['version'], $device['pushid'], $device['uuid']); 1019 $warnings = \external_api::clean_returnvalue(core_user_external::add_user_device_returns(), $warnings); 1020 $this->assertEquals(2, $DB->count_records('user_devices')); 1021 } 1022 1023 /** 1024 * Test remove user device 1025 */ 1026 public function test_remove_user_device() { 1027 global $USER, $CFG, $DB; 1028 1029 $this->resetAfterTest(true); 1030 1031 $device = array( 1032 'appid' => 'com.moodle.moodlemobile', 1033 'name' => 'occam', 1034 'model' => 'Nexus 4', 1035 'platform' => 'Android', 1036 'version' => '4.2.2', 1037 'pushid' => 'apushdkasdfj4835', 1038 'uuid' => 'ABCDE3723ksdfhasfaasef859' 1039 ); 1040 1041 // A device with the same properties except the appid and pushid. 1042 $device2 = $device; 1043 $device2['pushid'] = "0987654321"; 1044 $device2['appid'] = "other.app.com"; 1045 1046 $this->setAdminUser(); 1047 // Create a user device using the external API function. 1048 core_user_external::add_user_device($device['appid'], $device['name'], $device['model'], $device['platform'], 1049 $device['version'], $device['pushid'], $device['uuid']); 1050 1051 // Create the same device but for a different app. 1052 core_user_external::add_user_device($device2['appid'], $device2['name'], $device2['model'], $device2['platform'], 1053 $device2['version'], $device2['pushid'], $device2['uuid']); 1054 1055 // Try to remove a device that does not exist. 1056 $result = core_user_external::remove_user_device('1234567890'); 1057 $result = \external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result); 1058 $this->assertFalse($result['removed']); 1059 $this->assertCount(1, $result['warnings']); 1060 1061 // Try to remove a device that does not exist for an existing app. 1062 $result = core_user_external::remove_user_device('1234567890', $device['appid']); 1063 $result = \external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result); 1064 $this->assertFalse($result['removed']); 1065 $this->assertCount(1, $result['warnings']); 1066 1067 // Remove an existing device for an existing app. This will remove one of the two devices. 1068 $result = core_user_external::remove_user_device($device['uuid'], $device['appid']); 1069 $result = \external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result); 1070 $this->assertTrue($result['removed']); 1071 1072 // Remove all the devices. This must remove the remaining device. 1073 $result = core_user_external::remove_user_device($device['uuid']); 1074 $result = \external_api::clean_returnvalue(core_user_external::remove_user_device_returns(), $result); 1075 $this->assertTrue($result['removed']); 1076 } 1077 1078 /** 1079 * Test get_user_preferences 1080 */ 1081 public function test_get_user_preferences() { 1082 $this->resetAfterTest(true); 1083 1084 $user = self::getDataGenerator()->create_user(); 1085 set_user_preference('calendar_maxevents', 1, $user); 1086 set_user_preference('some_random_text', 'text', $user); 1087 1088 $this->setUser($user); 1089 1090 $result = core_user_external::get_user_preferences(); 1091 $result = \external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result); 1092 $this->assertCount(0, $result['warnings']); 1093 // Expect 3, _lastloaded is always returned. 1094 $this->assertCount(3, $result['preferences']); 1095 1096 foreach ($result['preferences'] as $pref) { 1097 if ($pref['name'] === '_lastloaded') { 1098 continue; 1099 } 1100 // Check we receive the expected preferences. 1101 $this->assertEquals(get_user_preferences($pref['name']), $pref['value']); 1102 } 1103 1104 // Retrieve just one preference. 1105 $result = core_user_external::get_user_preferences('some_random_text'); 1106 $result = \external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result); 1107 $this->assertCount(0, $result['warnings']); 1108 $this->assertCount(1, $result['preferences']); 1109 $this->assertEquals('text', $result['preferences'][0]['value']); 1110 1111 // Retrieve non-existent preference. 1112 $result = core_user_external::get_user_preferences('non_existent'); 1113 $result = \external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result); 1114 $this->assertCount(0, $result['warnings']); 1115 $this->assertCount(1, $result['preferences']); 1116 $this->assertEquals(null, $result['preferences'][0]['value']); 1117 1118 // Check that as admin we can retrieve all the preferences for any user. 1119 $this->setAdminUser(); 1120 $result = core_user_external::get_user_preferences('', $user->id); 1121 $result = \external_api::clean_returnvalue(core_user_external::get_user_preferences_returns(), $result); 1122 $this->assertCount(0, $result['warnings']); 1123 $this->assertCount(3, $result['preferences']); 1124 1125 foreach ($result['preferences'] as $pref) { 1126 if ($pref['name'] === '_lastloaded') { 1127 continue; 1128 } 1129 // Check we receive the expected preferences. 1130 $this->assertEquals(get_user_preferences($pref['name'], null, $user), $pref['value']); 1131 } 1132 1133 // Check that as a non admin user we cannot retrieve other users preferences. 1134 $anotheruser = self::getDataGenerator()->create_user(); 1135 $this->setUser($anotheruser); 1136 1137 $this->expectException('required_capability_exception'); 1138 $result = core_user_external::get_user_preferences('', $user->id); 1139 } 1140 1141 /** 1142 * Test update_picture 1143 */ 1144 public function test_update_picture() { 1145 global $DB, $USER; 1146 1147 $this->resetAfterTest(true); 1148 1149 $user = self::getDataGenerator()->create_user(); 1150 self::setUser($user); 1151 1152 $context = \context_user::instance($USER->id); 1153 $contextid = $context->id; 1154 $filename = "reddot.png"; 1155 $filecontent = "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38" 1156 . "GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="; 1157 1158 // Call the files api to create a file. 1159 $draftfile = core_files_external::upload($contextid, 'user', 'draft', 0, '/', $filename, $filecontent, null, null); 1160 $draftid = $draftfile['itemid']; 1161 1162 // Change user profile image. 1163 $result = core_user_external::update_picture($draftid); 1164 $result = \external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result); 1165 $picture = $DB->get_field('user', 'picture', array('id' => $user->id)); 1166 // The new revision is in the url for the user. 1167 $this->assertStringContainsString($picture, $result['profileimageurl']); 1168 // Check expected URL for serving the image. 1169 $this->assertStringContainsString("/$contextid/user/icon", $result['profileimageurl']); 1170 1171 // Delete image. 1172 $result = core_user_external::update_picture(0, true); 1173 $result = \external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result); 1174 $picture = $DB->get_field('user', 'picture', array('id' => $user->id)); 1175 // No picture. 1176 $this->assertEquals(0, $picture); 1177 1178 // Add again the user profile image (as admin). 1179 $this->setAdminUser(); 1180 1181 $context = \context_user::instance($USER->id); 1182 $admincontextid = $context->id; 1183 $draftfile = core_files_external::upload($admincontextid, 'user', 'draft', 0, '/', $filename, $filecontent, null, null); 1184 $draftid = $draftfile['itemid']; 1185 1186 $result = core_user_external::update_picture($draftid, false, $user->id); 1187 $result = \external_api::clean_returnvalue(core_user_external::update_picture_returns(), $result); 1188 // The new revision is in the url for the user. 1189 $picture = $DB->get_field('user', 'picture', array('id' => $user->id)); 1190 $this->assertStringContainsString($picture, $result['profileimageurl']); 1191 $this->assertStringContainsString("/$contextid/user/icon", $result['profileimageurl']); 1192 } 1193 1194 /** 1195 * Test update_picture disabled 1196 */ 1197 public function test_update_picture_disabled() { 1198 global $CFG; 1199 $this->resetAfterTest(true); 1200 $CFG->disableuserimages = true; 1201 1202 $this->setAdminUser(); 1203 $this->expectException('moodle_exception'); 1204 core_user_external::update_picture(0); 1205 } 1206 1207 /** 1208 * Test set_user_preferences 1209 */ 1210 public function test_set_user_preferences_save() { 1211 global $DB; 1212 $this->resetAfterTest(true); 1213 1214 $user1 = self::getDataGenerator()->create_user(); 1215 $user2 = self::getDataGenerator()->create_user(); 1216 1217 // Save users preferences. 1218 $this->setAdminUser(); 1219 $preferences = array( 1220 array( 1221 'name' => 'htmleditor', 1222 'value' => 'atto', 1223 'userid' => $user1->id, 1224 ), 1225 array( 1226 'name' => 'htmleditor', 1227 'value' => 'tinymce', 1228 'userid' => $user2->id, 1229 ) 1230 ); 1231 1232 $result = core_user_external::set_user_preferences($preferences); 1233 $result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result); 1234 $this->assertCount(0, $result['warnings']); 1235 $this->assertCount(2, $result['saved']); 1236 1237 // Get preference from DB to avoid cache. 1238 $this->assertEquals('atto', $DB->get_field('user_preferences', 'value', 1239 array('userid' => $user1->id, 'name' => 'htmleditor'))); 1240 $this->assertEquals('tinymce', $DB->get_field('user_preferences', 'value', 1241 array('userid' => $user2->id, 'name' => 'htmleditor'))); 1242 } 1243 1244 /** 1245 * Test set_user_preferences 1246 */ 1247 public function test_set_user_preferences_save_invalid_pref() { 1248 global $DB; 1249 $this->resetAfterTest(true); 1250 1251 $user1 = self::getDataGenerator()->create_user(); 1252 1253 // Save users preferences. 1254 $this->setAdminUser(); 1255 $preferences = array( 1256 array( 1257 'name' => 'some_random_pref', 1258 'value' => 'abc', 1259 'userid' => $user1->id, 1260 ), 1261 ); 1262 1263 $result = core_user_external::set_user_preferences($preferences); 1264 $result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result); 1265 $this->assertCount(1, $result['warnings']); 1266 $this->assertCount(0, $result['saved']); 1267 $this->assertEquals('nopermission', $result['warnings'][0]['warningcode']); 1268 1269 // Nothing was written to DB. 1270 $this->assertEmpty($DB->count_records('user_preferences', array('name' => 'some_random_pref'))); 1271 } 1272 1273 /** 1274 * Test set_user_preferences for an invalid user 1275 */ 1276 public function test_set_user_preferences_invalid_user() { 1277 $this->resetAfterTest(true); 1278 1279 $this->setAdminUser(); 1280 $preferences = array( 1281 array( 1282 'name' => 'calendar_maxevents', 1283 'value' => 4, 1284 'userid' => -2 1285 ) 1286 ); 1287 1288 $result = core_user_external::set_user_preferences($preferences); 1289 $result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result); 1290 $this->assertCount(1, $result['warnings']); 1291 $this->assertCount(0, $result['saved']); 1292 $this->assertEquals('invaliduser', $result['warnings'][0]['warningcode']); 1293 $this->assertEquals(-2, $result['warnings'][0]['itemid']); 1294 } 1295 1296 /** 1297 * Test set_user_preferences using an invalid preference 1298 */ 1299 public function test_set_user_preferences_invalid_preference() { 1300 global $USER, $DB; 1301 1302 $this->resetAfterTest(true); 1303 // Create a very long value. 1304 $this->setAdminUser(); 1305 $preferences = array( 1306 array( 1307 'name' => 'calendar_maxevents', 1308 'value' => str_repeat('a', 1334), 1309 'userid' => $USER->id 1310 ) 1311 ); 1312 1313 $result = core_user_external::set_user_preferences($preferences); 1314 $result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result); 1315 $this->assertCount(0, $result['warnings']); 1316 $this->assertCount(1, $result['saved']); 1317 // Cleaned valud of the preference was saved. 1318 $this->assertEquals(1, $DB->get_field('user_preferences', 'value', 1319 array('userid' => $USER->id, 'name' => 'calendar_maxevents'))); 1320 } 1321 1322 /** 1323 * Test set_user_preferences for other user not being admin 1324 */ 1325 public function test_set_user_preferences_capability() { 1326 $this->resetAfterTest(true); 1327 1328 $user1 = self::getDataGenerator()->create_user(); 1329 $user2 = self::getDataGenerator()->create_user(); 1330 1331 $this->setUser($user1); 1332 $preferences = array( 1333 array( 1334 'name' => 'calendar_maxevents', 1335 'value' => 4, 1336 'userid' => $user2->id 1337 ) 1338 ); 1339 1340 $result = core_user_external::set_user_preferences($preferences); 1341 1342 $this->assertCount(1, $result['warnings']); 1343 $this->assertCount(0, $result['saved']); 1344 $this->assertEquals('nopermission', $result['warnings'][0]['warningcode']); 1345 $this->assertEquals($user2->id, $result['warnings'][0]['itemid']); 1346 } 1347 1348 /** 1349 * Test update_user_preferences unsetting an existing preference. 1350 */ 1351 public function test_update_user_preferences_unset() { 1352 global $DB; 1353 $this->resetAfterTest(true); 1354 1355 $user = self::getDataGenerator()->create_user(); 1356 1357 // Save users preferences. 1358 $this->setAdminUser(); 1359 $preferences = array( 1360 array( 1361 'name' => 'htmleditor', 1362 'value' => 'atto', 1363 'userid' => $user->id, 1364 ) 1365 ); 1366 1367 $result = core_user_external::set_user_preferences($preferences); 1368 $result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result); 1369 $this->assertCount(0, $result['warnings']); 1370 $this->assertCount(1, $result['saved']); 1371 1372 // Get preference from DB to avoid cache. 1373 $this->assertEquals('atto', $DB->get_field('user_preferences', 'value', 1374 array('userid' => $user->id, 'name' => 'htmleditor'))); 1375 1376 // Now, unset. 1377 $result = core_user_external::update_user_preferences($user->id, null, array(array('type' => 'htmleditor'))); 1378 1379 $this->assertEquals(0, $DB->count_records('user_preferences', array('userid' => $user->id, 'name' => 'htmleditor'))); 1380 } 1381 1382 /** 1383 * Test agree_site_policy 1384 */ 1385 public function test_agree_site_policy() { 1386 global $CFG, $DB, $USER; 1387 $this->resetAfterTest(true); 1388 1389 $user = self::getDataGenerator()->create_user(); 1390 $this->setUser($user); 1391 1392 // Site policy not set. 1393 $result = core_user_external::agree_site_policy(); 1394 $result = \external_api::clean_returnvalue(core_user_external::agree_site_policy_returns(), $result); 1395 $this->assertFalse($result['status']); 1396 $this->assertCount(1, $result['warnings']); 1397 $this->assertEquals('nositepolicy', $result['warnings'][0]['warningcode']); 1398 1399 // Set a policy issue. 1400 $CFG->sitepolicy = 'https://moodle.org'; 1401 $this->assertEquals(0, $USER->policyagreed); 1402 1403 $result = core_user_external::agree_site_policy(); 1404 $result = \external_api::clean_returnvalue(core_user_external::agree_site_policy_returns(), $result); 1405 $this->assertTrue($result['status']); 1406 $this->assertCount(0, $result['warnings']); 1407 $this->assertEquals(1, $USER->policyagreed); 1408 $this->assertEquals(1, $DB->get_field('user', 'policyagreed', array('id' => $USER->id))); 1409 1410 // Try again, we should get a warning. 1411 $result = core_user_external::agree_site_policy(); 1412 $result = \external_api::clean_returnvalue(core_user_external::agree_site_policy_returns(), $result); 1413 $this->assertFalse($result['status']); 1414 $this->assertCount(1, $result['warnings']); 1415 $this->assertEquals('alreadyagreed', $result['warnings'][0]['warningcode']); 1416 1417 // Set something to make require_login throws an exception. 1418 $otheruser = self::getDataGenerator()->create_user(); 1419 $this->setUser($otheruser); 1420 1421 $DB->set_field('user', 'lastname', '', array('id' => $USER->id)); 1422 $USER->lastname = ''; 1423 try { 1424 $result = core_user_external::agree_site_policy(); 1425 $this->fail('Expecting \'usernotfullysetup\' moodle_exception to be thrown'); 1426 } catch (\moodle_exception $e) { 1427 $this->assertEquals('usernotfullysetup', $e->errorcode); 1428 } catch (\Exception $e) { 1429 $this->fail('Expecting \'usernotfullysetup\' moodle_exception to be thrown.'); 1430 } 1431 } 1432 1433 /** 1434 * Test get_private_files_info 1435 */ 1436 public function test_get_private_files_info() { 1437 1438 $this->resetAfterTest(true); 1439 $user = self::getDataGenerator()->create_user(); 1440 $this->setUser($user); 1441 $usercontext = \context_user::instance($user->id); 1442 1443 $filerecord = array( 1444 'contextid' => $usercontext->id, 1445 'component' => 'user', 1446 'filearea' => 'private', 1447 'itemid' => 0, 1448 'filepath' => '/', 1449 'filename' => 'thefile', 1450 ); 1451 1452 $fs = get_file_storage(); 1453 $file = $fs->create_file_from_string($filerecord, 'abc'); 1454 1455 // Get my private files information. 1456 $result = core_user_external::get_private_files_info(); 1457 $result = \external_api::clean_returnvalue(core_user_external::get_private_files_info_returns(), $result); 1458 $this->assertEquals(1, $result['filecount']); 1459 $this->assertEquals($file->get_filesize(), $result['filesize']); 1460 $this->assertEquals(0, $result['foldercount']); 1461 $this->assertEquals($file->get_filesize(), $result['filesizewithoutreferences']); 1462 1463 // As admin, get user information. 1464 $this->setAdminUser(); 1465 $result = core_user_external::get_private_files_info($user->id); 1466 $result = \external_api::clean_returnvalue(core_user_external::get_private_files_info_returns(), $result); 1467 $this->assertEquals(1, $result['filecount']); 1468 $this->assertEquals($file->get_filesize(), $result['filesize']); 1469 $this->assertEquals(0, $result['foldercount']); 1470 $this->assertEquals($file->get_filesize(), $result['filesizewithoutreferences']); 1471 } 1472 1473 /** 1474 * Test get_private_files_info missing permissions. 1475 */ 1476 public function test_get_private_files_info_missing_permissions() { 1477 1478 $this->resetAfterTest(true); 1479 $user1 = self::getDataGenerator()->create_user(); 1480 $user2 = self::getDataGenerator()->create_user(); 1481 $this->setUser($user1); 1482 1483 $this->expectException('required_capability_exception'); 1484 // Try to retrieve other user private files info. 1485 core_user_external::get_private_files_info($user2->id); 1486 } 1487 1488 /** 1489 * Test the functionality of the {@see \core_user\external\search_identity} class. 1490 */ 1491 public function test_external_search_identity() { 1492 global $CFG; 1493 1494 $this->resetAfterTest(true); 1495 $this->setAdminUser(); 1496 1497 $user1 = self::getDataGenerator()->create_user([ 1498 'firstname' => 'Firstone', 1499 'lastname' => 'Lastone', 1500 'username' => 'usernameone', 1501 'idnumber' => 'idnumberone', 1502 'email' => 'userone@example.com', 1503 'phone1' => 'tel1', 1504 'phone2' => 'tel2', 1505 'department' => 'Department Foo', 1506 'institution' => 'Institution Foo', 1507 'city' => 'City One', 1508 'country' => 'AU', 1509 ]); 1510 1511 $user2 = self::getDataGenerator()->create_user([ 1512 'firstname' => 'Firsttwo', 1513 'lastname' => 'Lasttwo', 1514 'username' => 'usernametwo', 1515 'idnumber' => 'idnumbertwo', 1516 'email' => 'usertwo@example.com', 1517 'phone1' => 'tel1', 1518 'phone2' => 'tel2', 1519 'department' => 'Department Foo', 1520 'institution' => 'Institution Foo', 1521 'city' => 'City One', 1522 'country' => 'AU', 1523 ]); 1524 1525 $user3 = self::getDataGenerator()->create_user([ 1526 'firstname' => 'Firstthree', 1527 'lastname' => 'Lastthree', 1528 'username' => 'usernamethree', 1529 'idnumber' => 'idnumberthree', 1530 'email' => 'userthree@example.com', 1531 'phone1' => 'tel1', 1532 'phone2' => 'tel2', 1533 'department' => 'Department Foo', 1534 'institution' => 'Institution Foo', 1535 'city' => 'City One', 1536 'country' => 'AU', 1537 ]); 1538 1539 $CFG->showuseridentity = 'email,idnumber,city'; 1540 $CFG->maxusersperpage = 3; 1541 1542 $result = \core_user\external\search_identity::execute('Lastt'); 1543 $result = \external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result); 1544 1545 $this->assertEquals(2, count($result['list'])); 1546 $this->assertEquals(3, $result['maxusersperpage']); 1547 $this->assertEquals(false, $result['overflow']); 1548 1549 foreach ($result['list'] as $user) { 1550 $this->assertEquals(3, count($user['extrafields'])); 1551 $this->assertEquals('email', $user['extrafields'][0]['name']); 1552 $this->assertEquals('idnumber', $user['extrafields'][1]['name']); 1553 $this->assertEquals('city', $user['extrafields'][2]['name']); 1554 } 1555 1556 $CFG->showuseridentity = 'username'; 1557 $CFG->maxusersperpage = 2; 1558 1559 $result = \core_user\external\search_identity::execute('Firstt'); 1560 $result = \external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result); 1561 1562 $this->assertEquals(2, count($result['list'])); 1563 $this->assertEquals(2, $result['maxusersperpage']); 1564 $this->assertEquals(false, $result['overflow']); 1565 1566 foreach ($result['list'] as $user) { 1567 $this->assertEquals(1, count($user['extrafields'])); 1568 $this->assertEquals('username', $user['extrafields'][0]['name']); 1569 } 1570 1571 $CFG->showuseridentity = 'email'; 1572 $CFG->maxusersperpage = 2; 1573 1574 $result = \core_user\external\search_identity::execute('City One'); 1575 $result = \external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result); 1576 1577 $this->assertEquals(0, count($result['list'])); 1578 $this->assertEquals(2, $result['maxusersperpage']); 1579 $this->assertEquals(false, $result['overflow']); 1580 1581 $CFG->showuseridentity = 'city'; 1582 $CFG->maxusersperpage = 2; 1583 1584 foreach ($result['list'] as $user) { 1585 $this->assertEquals(1, count($user['extrafields'])); 1586 $this->assertEquals('username', $user['extrafields'][0]['name']); 1587 } 1588 1589 $result = \core_user\external\search_identity::execute('City One'); 1590 $result = \external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result); 1591 1592 $this->assertEquals(2, count($result['list'])); 1593 $this->assertEquals(2, $result['maxusersperpage']); 1594 $this->assertEquals(true, $result['overflow']); 1595 } 1596 1597 /** 1598 * Test functionality of the {@see \core_user\external\search_identity} class with alternativefullnameformat defined. 1599 */ 1600 public function test_external_search_identity_with_alternativefullnameformat() { 1601 global $CFG; 1602 1603 $this->resetAfterTest(true); 1604 $this->setAdminUser(); 1605 1606 $user1 = self::getDataGenerator()->create_user([ 1607 'lastname' => '小柳', 1608 'lastnamephonetic' => 'Koyanagi', 1609 'firstname' => '秋', 1610 'firstnamephonetic' => 'Aki', 1611 'email' => 'koyanagiaki@example.com', 1612 'country' => 'JP', 1613 ]); 1614 1615 $CFG->showuseridentity = 'email'; 1616 $CFG->maxusersperpage = 3; 1617 $CFG->alternativefullnameformat = 1618 '<ruby>lastname firstname <rp>(</rp><rt>lastnamephonetic firstnamephonetic</rt><rp>)</rp></ruby>'; 1619 1620 $result = \core_user\external\search_identity::execute('Ak'); 1621 $result = \external_api::clean_returnvalue(\core_user\external\search_identity::execute_returns(), $result); 1622 1623 $this->assertEquals(1, count($result['list'])); 1624 $this->assertEquals(3, $result['maxusersperpage']); 1625 $this->assertEquals(false, $result['overflow']); 1626 1627 foreach ($result['list'] as $user) { 1628 $this->assertEquals(1, count($user['extrafields'])); 1629 $this->assertEquals('email', $user['extrafields'][0]['name']); 1630 } 1631 } 1632 1633 /** 1634 * Test verifying that update_user_preferences prevents changes to the default homepage for other users. 1635 */ 1636 public function test_update_user_preferences_homepage_permission_callback() { 1637 global $DB; 1638 $this->resetAfterTest(); 1639 1640 $user = self::getDataGenerator()->create_user(); 1641 $this->setUser($user); 1642 $adminuser = get_admin(); 1643 1644 // Allow user selection of the default homepage via preferences. 1645 set_config('defaulthomepage', HOMEPAGE_USER); 1646 1647 // Try to save another user's home page preference which uses the permissioncallback. 1648 $preferences = [ 1649 [ 1650 'name' => 'user_home_page_preference', 1651 'value' => '3', 1652 'userid' => $adminuser->id, 1653 ] 1654 ]; 1655 $result = core_user_external::set_user_preferences($preferences); 1656 $result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result); 1657 $this->assertCount(1, $result['warnings']); 1658 $this->assertCount(0, $result['saved']); 1659 1660 // Verify no change to the preference, checking from DB to avoid cache. 1661 $this->assertEquals(null, $DB->get_field('user_preferences', 'value', 1662 ['userid' => $adminuser->id, 'name' => 'user_home_page_preference'])); 1663 } 1664 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body