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