See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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 * Moodle Mobile admin tool external functions tests. 19 * 20 * @package tool_mobile 21 * @category external 22 * @copyright 2016 Juan Leyva 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 * @since Moodle 3.1 25 */ 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 31 require_once($CFG->dirroot . '/webservice/tests/helpers.php'); 32 require_once($CFG->dirroot . '/admin/tool/mobile/tests/fixtures/output/mobile.php'); 33 require_once($CFG->dirroot . '/webservice/lib.php'); 34 35 use tool_mobile\external; 36 use tool_mobile\api; 37 38 /** 39 * Moodle Mobile admin tool external functions tests. 40 * 41 * @package tool_mobile 42 * @copyright 2016 Juan Leyva 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 * @since Moodle 3.1 45 */ 46 class tool_mobile_external_testcase extends externallib_advanced_testcase { 47 48 /** 49 * Test get_plugins_supporting_mobile. 50 * This is a very basic test because currently there aren't plugins supporting Mobile in core. 51 */ 52 public function test_get_plugins_supporting_mobile() { 53 $result = external::get_plugins_supporting_mobile(); 54 $result = external_api::clean_returnvalue(external::get_plugins_supporting_mobile_returns(), $result); 55 $this->assertCount(0, $result['warnings']); 56 $this->assertArrayHasKey('plugins', $result); 57 $this->assertTrue(is_array($result['plugins'])); 58 } 59 60 public function test_get_public_config() { 61 global $CFG, $SITE, $OUTPUT; 62 63 $this->resetAfterTest(true); 64 $result = external::get_public_config(); 65 $result = external_api::clean_returnvalue(external::get_public_config_returns(), $result); 66 67 // Test default values. 68 $context = context_system::instance(); 69 list($authinstructions, $notusedformat) = external_format_text($CFG->auth_instructions, FORMAT_MOODLE, $context->id); 70 list($maintenancemessage, $notusedformat) = external_format_text($CFG->maintenance_message, FORMAT_MOODLE, $context->id); 71 72 $expected = array( 73 'wwwroot' => $CFG->wwwroot, 74 'httpswwwroot' => $CFG->wwwroot, 75 'sitename' => external_format_string($SITE->fullname, $context->id, true), 76 'guestlogin' => $CFG->guestloginbutton, 77 'rememberusername' => $CFG->rememberusername, 78 'authloginviaemail' => $CFG->authloginviaemail, 79 'registerauth' => $CFG->registerauth, 80 'forgottenpasswordurl' => $CFG->forgottenpasswordurl, 81 'authinstructions' => $authinstructions, 82 'authnoneenabled' => (int) is_enabled_auth('none'), 83 'enablewebservices' => $CFG->enablewebservices, 84 'enablemobilewebservice' => $CFG->enablemobilewebservice, 85 'maintenanceenabled' => $CFG->maintenance_enabled, 86 'maintenancemessage' => $maintenancemessage, 87 'typeoflogin' => api::LOGIN_VIA_APP, 88 'mobilecssurl' => '', 89 'tool_mobile_disabledfeatures' => '', 90 'launchurl' => "$CFG->wwwroot/$CFG->admin/tool/mobile/launch.php", 91 'country' => $CFG->country, 92 'agedigitalconsentverification' => \core_auth\digital_consent::is_age_digital_consent_verification_enabled(), 93 'autolang' => $CFG->autolang, 94 'lang' => $CFG->lang, 95 'langmenu' => $CFG->langmenu, 96 'langlist' => $CFG->langlist, 97 'locale' => $CFG->locale, 98 'tool_mobile_minimumversion' => '', 99 'tool_mobile_iosappid' => get_config('tool_mobile', 'iosappid'), 100 'tool_mobile_androidappid' => get_config('tool_mobile', 'androidappid'), 101 'tool_mobile_setuplink' => get_config('tool_mobile', 'setuplink'), 102 'warnings' => array() 103 ); 104 $this->assertEquals($expected, $result); 105 106 $this->setAdminUser(); 107 // Change some values. 108 set_config('registerauth', 'email'); 109 $authinstructions = 'Something with <b>html tags</b>'; 110 set_config('auth_instructions', $authinstructions); 111 set_config('typeoflogin', api::LOGIN_VIA_BROWSER, 'tool_mobile'); 112 set_config('logo', 'mock.png', 'core_admin'); 113 set_config('logocompact', 'mock.png', 'core_admin'); 114 set_config('forgottenpasswordurl', 'mailto:fake@email.zy'); // Test old hack. 115 set_config('agedigitalconsentverification', 1); 116 set_config('autolang', 1); 117 set_config('lang', 'a_b'); // Set invalid lang. 118 set_config('disabledfeatures', 'myoverview', 'tool_mobile'); 119 set_config('minimumversion', '3.8.0', 'tool_mobile'); 120 121 // Enable couple of issuers. 122 $issuer = \core\oauth2\api::create_standard_issuer('google'); 123 $irecord = $issuer->to_record(); 124 $irecord->clientid = 'mock'; 125 $irecord->clientsecret = 'mock'; 126 core\oauth2\api::update_issuer($irecord); 127 128 set_config('hostname', 'localhost', 'auth_cas'); 129 set_config('auth_logo', 'http://invalidurl.com//invalid/', 'auth_cas'); 130 set_config('auth_name', 'CAS', 'auth_cas'); 131 set_config('auth', 'oauth2,cas'); 132 133 list($authinstructions, $notusedformat) = external_format_text($authinstructions, FORMAT_MOODLE, $context->id); 134 $expected['registerauth'] = 'email'; 135 $expected['authinstructions'] = $authinstructions; 136 $expected['typeoflogin'] = api::LOGIN_VIA_BROWSER; 137 $expected['forgottenpasswordurl'] = ''; // Expect empty when it's not an URL. 138 $expected['agedigitalconsentverification'] = true; 139 $expected['supportname'] = $CFG->supportname; 140 $expected['supportemail'] = $CFG->supportemail; 141 $expected['autolang'] = '1'; 142 $expected['lang'] = ''; // Expect empty because it was set to an invalid lang. 143 $expected['tool_mobile_disabledfeatures'] = 'myoverview'; 144 $expected['tool_mobile_minimumversion'] = '3.8.0'; 145 146 if ($logourl = $OUTPUT->get_logo_url()) { 147 $expected['logourl'] = $logourl->out(false); 148 } 149 if ($compactlogourl = $OUTPUT->get_compact_logo_url()) { 150 $expected['compactlogourl'] = $compactlogourl->out(false); 151 } 152 153 $result = external::get_public_config(); 154 $result = external_api::clean_returnvalue(external::get_public_config_returns(), $result); 155 // First check providers. 156 $identityproviders = $result['identityproviders']; 157 unset($result['identityproviders']); 158 159 $this->assertEquals('Google', $identityproviders[0]['name']); 160 $this->assertEquals($irecord->image, $identityproviders[0]['iconurl']); 161 $this->assertContains($CFG->wwwroot, $identityproviders[0]['url']); 162 163 $this->assertEquals('CAS', $identityproviders[1]['name']); 164 $this->assertEmpty($identityproviders[1]['iconurl']); 165 $this->assertContains($CFG->wwwroot, $identityproviders[1]['url']); 166 167 $this->assertEquals($expected, $result); 168 169 // Change providers img. 170 $newurl = 'validimage.png'; 171 set_config('auth_logo', $newurl, 'auth_cas'); 172 $result = external::get_public_config(); 173 $result = external_api::clean_returnvalue(external::get_public_config_returns(), $result); 174 $this->assertContains($newurl, $result['identityproviders'][1]['iconurl']); 175 } 176 177 /** 178 * Test get_config 179 */ 180 public function test_get_config() { 181 global $CFG, $SITE; 182 require_once($CFG->dirroot . '/course/format/lib.php'); 183 184 $this->resetAfterTest(true); 185 186 $mysitepolicy = 'http://mysite.is/policy/'; 187 set_config('sitepolicy', $mysitepolicy); 188 189 $result = external::get_config(); 190 $result = external_api::clean_returnvalue(external::get_config_returns(), $result); 191 192 // SITE summary is null in phpunit which gets transformed to an empty string by format_text. 193 list($sitesummary, $unused) = external_format_text($SITE->summary, $SITE->summaryformat, context_system::instance()->id); 194 195 // Test default values. 196 $context = context_system::instance(); 197 $expected = array( 198 array('name' => 'fullname', 'value' => $SITE->fullname), 199 array('name' => 'shortname', 'value' => $SITE->shortname), 200 array('name' => 'summary', 'value' => $sitesummary), 201 array('name' => 'summaryformat', 'value' => FORMAT_HTML), 202 array('name' => 'frontpage', 'value' => $CFG->frontpage), 203 array('name' => 'frontpageloggedin', 'value' => $CFG->frontpageloggedin), 204 array('name' => 'maxcategorydepth', 'value' => $CFG->maxcategorydepth), 205 array('name' => 'frontpagecourselimit', 'value' => $CFG->frontpagecourselimit), 206 array('name' => 'numsections', 'value' => course_get_format($SITE)->get_last_section_number()), 207 array('name' => 'newsitems', 'value' => $SITE->newsitems), 208 array('name' => 'commentsperpage', 'value' => $CFG->commentsperpage), 209 array('name' => 'sitepolicy', 'value' => $mysitepolicy), 210 array('name' => 'sitepolicyhandler', 'value' => ''), 211 array('name' => 'disableuserimages', 'value' => $CFG->disableuserimages), 212 array('name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false)), 213 array('name' => 'tool_mobile_forcelogout', 'value' => 0), 214 array('name' => 'tool_mobile_customlangstrings', 'value' => ''), 215 array('name' => 'tool_mobile_disabledfeatures', 'value' => ''), 216 array('name' => 'tool_mobile_custommenuitems', 'value' => ''), 217 array('name' => 'tool_mobile_apppolicy', 'value' => ''), 218 array('name' => 'calendartype', 'value' => $CFG->calendartype), 219 array('name' => 'calendar_site_timeformat', 'value' => $CFG->calendar_site_timeformat), 220 array('name' => 'calendar_startwday', 'value' => $CFG->calendar_startwday), 221 array('name' => 'calendar_adminseesall', 'value' => $CFG->calendar_adminseesall), 222 array('name' => 'calendar_lookahead', 'value' => $CFG->calendar_lookahead), 223 array('name' => 'calendar_maxevents', 'value' => $CFG->calendar_maxevents), 224 ); 225 $colornumbers = range(1, 10); 226 foreach ($colornumbers as $number) { 227 $expected[] = [ 228 'name' => 'core_admin_coursecolor' . $number, 229 'value' => get_config('core_admin', 'coursecolor' . $number) 230 ]; 231 } 232 $expected[] = ['name' => 'supportname', 'value' => $CFG->supportname]; 233 $expected[] = ['name' => 'supportemail', 'value' => $CFG->supportemail]; 234 $expected[] = ['name' => 'supportpage', 'value' => $CFG->supportpage]; 235 236 $this->assertCount(0, $result['warnings']); 237 $this->assertEquals($expected, $result['settings']); 238 239 // Change a value and retrieve filtering by section. 240 set_config('commentsperpage', 1); 241 $expected[10]['value'] = 1; 242 // Remove not expected elements. 243 array_splice($expected, 11); 244 245 $result = external::get_config('frontpagesettings'); 246 $result = external_api::clean_returnvalue(external::get_config_returns(), $result); 247 $this->assertCount(0, $result['warnings']); 248 $this->assertEquals($expected, $result['settings']); 249 } 250 251 /* 252 * Test get_autologin_key. 253 */ 254 public function test_get_autologin_key() { 255 global $DB, $CFG, $USER; 256 257 $this->resetAfterTest(true); 258 259 $user = $this->getDataGenerator()->create_user(); 260 $this->setUser($user); 261 $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 262 263 $token = external_generate_token_for_current_user($service); 264 265 // Check we got the private token. 266 $this->assertTrue(isset($token->privatetoken)); 267 268 // Enable requeriments. 269 $_GET['wstoken'] = $token->token; // Mock parameters. 270 271 // Fake the app. 272 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 273 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 274 275 // Even if we force the password change for the current user we should be able to retrieve the key. 276 set_user_preference('auth_forcepasswordchange', 1, $user->id); 277 278 $this->setCurrentTimeStart(); 279 $result = external::get_autologin_key($token->privatetoken); 280 $result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result); 281 // Validate the key. 282 $this->assertEquals(32, core_text::strlen($result['key'])); 283 $key = $DB->get_record('user_private_key', array('value' => $result['key'])); 284 $this->assertEquals($USER->id, $key->userid); 285 $this->assertTimeCurrent($key->validuntil - api::LOGIN_KEY_TTL); 286 287 // Now, try with an invalid private token. 288 set_user_preference('tool_mobile_autologin_request_last', time() - HOURSECS, $USER); 289 290 $this->expectException('moodle_exception'); 291 $this->expectExceptionMessage(get_string('invalidprivatetoken', 'tool_mobile')); 292 $result = external::get_autologin_key(random_string('64')); 293 } 294 295 /** 296 * Test get_autologin_key missing ws. 297 */ 298 public function test_get_autologin_key_missing_ws() { 299 global $CFG; 300 $this->resetAfterTest(true); 301 302 // Fake the app. 303 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 304 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 305 306 // Need to disable webservices to verify that's checked. 307 $CFG->enablewebservices = 0; 308 $CFG->enablemobilewebservice = 0; 309 310 $this->setAdminUser(); 311 $this->expectException('moodle_exception'); 312 $this->expectExceptionMessage(get_string('enablewsdescription', 'webservice')); 313 $result = external::get_autologin_key(''); 314 } 315 316 /** 317 * Test get_autologin_key missing https. 318 */ 319 public function test_get_autologin_key_missing_https() { 320 global $CFG; 321 322 // Fake the app. 323 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 324 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 325 326 // Need to simulate a non HTTPS site here. 327 $CFG->wwwroot = str_replace('https:', 'http:', $CFG->wwwroot); 328 329 $this->resetAfterTest(true); 330 $this->setAdminUser(); 331 332 $this->expectException('moodle_exception'); 333 $this->expectExceptionMessage(get_string('httpsrequired', 'tool_mobile')); 334 $result = external::get_autologin_key(''); 335 } 336 337 /** 338 * Test get_autologin_key missing admin. 339 */ 340 public function test_get_autologin_key_missing_admin() { 341 global $CFG; 342 343 $this->resetAfterTest(true); 344 $this->setAdminUser(); 345 346 // Fake the app. 347 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 348 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 349 350 $this->expectException('moodle_exception'); 351 $this->expectExceptionMessage(get_string('autologinnotallowedtoadmins', 'tool_mobile')); 352 $result = external::get_autologin_key(''); 353 } 354 355 /** 356 * Test get_autologin_key locked. 357 */ 358 public function test_get_autologin_key_missing_locked() { 359 global $CFG, $DB, $USER; 360 361 $this->resetAfterTest(true); 362 $user = $this->getDataGenerator()->create_user(); 363 $this->setUser($user); 364 365 $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 366 367 $token = external_generate_token_for_current_user($service); 368 $_GET['wstoken'] = $token->token; // Mock parameters. 369 370 // Fake the app. 371 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 372 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 373 374 $result = external::get_autologin_key($token->privatetoken); 375 $result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result); 376 377 // Mock last time request. 378 $mocktime = time() - 7 * MINSECS; 379 set_user_preference('tool_mobile_autologin_request_last', $mocktime, $USER); 380 $result = external::get_autologin_key($token->privatetoken); 381 $result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result); 382 383 // We just requested one token, we must wait. 384 $this->expectException('moodle_exception'); 385 $this->expectExceptionMessage(get_string('autologinkeygenerationlockout', 'tool_mobile')); 386 $result = external::get_autologin_key($token->privatetoken); 387 } 388 389 /** 390 * Test get_autologin_key missing app_request. 391 */ 392 public function test_get_autologin_key_missing_app_request() { 393 global $CFG; 394 395 $this->resetAfterTest(true); 396 $this->setAdminUser(); 397 398 $this->expectException('moodle_exception'); 399 $this->expectExceptionMessage(get_string('apprequired', 'tool_mobile')); 400 $result = external::get_autologin_key(''); 401 } 402 403 /** 404 * Test get_content. 405 */ 406 public function test_get_content() { 407 408 $paramval = 16; 409 $result = external::get_content('tool_mobile', 'test_view', array(array('name' => 'param1', 'value' => $paramval))); 410 $result = external_api::clean_returnvalue(external::get_content_returns(), $result); 411 $this->assertCount(1, $result['templates']); 412 $this->assertCount(1, $result['otherdata']); 413 $this->assertCount(2, $result['restrict']['users']); 414 $this->assertCount(2, $result['restrict']['courses']); 415 $this->assertEquals('alert();', $result['javascript']); 416 $this->assertEquals('main', $result['templates'][0]['id']); 417 $this->assertEquals('The HTML code', $result['templates'][0]['html']); 418 $this->assertEquals('otherdata1', $result['otherdata'][0]['name']); 419 $this->assertEquals($paramval, $result['otherdata'][0]['value']); 420 $this->assertEquals(array(1, 2), $result['restrict']['users']); 421 $this->assertEquals(array(3, 4), $result['restrict']['courses']); 422 $this->assertEmpty($result['files']); 423 $this->assertFalse($result['disabled']); 424 } 425 426 /** 427 * Test get_content disabled. 428 */ 429 public function test_get_content_disabled() { 430 431 $paramval = 16; 432 $result = external::get_content('tool_mobile', 'test_view_disabled', 433 array(array('name' => 'param1', 'value' => $paramval))); 434 $result = external_api::clean_returnvalue(external::get_content_returns(), $result); 435 $this->assertTrue($result['disabled']); 436 } 437 438 /** 439 * Test get_content non existent function in valid component. 440 */ 441 public function test_get_content_non_existent_function() { 442 443 $this->expectException('coding_exception'); 444 $result = external::get_content('tool_mobile', 'test_blahblah'); 445 } 446 447 /** 448 * Test get_content incorrect component. 449 */ 450 public function test_get_content_invalid_component() { 451 452 $this->expectException('moodle_exception'); 453 $result = external::get_content('tool_mobile\hack', 'test_view'); 454 } 455 456 /** 457 * Test get_content non existent component. 458 */ 459 public function test_get_content_non_existent_component() { 460 461 $this->expectException('moodle_exception'); 462 $result = external::get_content('tool_blahblahblah', 'test_view'); 463 } 464 465 public function test_call_external_functions() { 466 global $SESSION; 467 468 $this->resetAfterTest(true); 469 470 $category = self::getDataGenerator()->create_category(array('name' => 'Category 1')); 471 $course = self::getDataGenerator()->create_course([ 472 'category' => $category->id, 473 'shortname' => 'c1', 474 'summary' => '<span lang="en" class="multilang">Course summary</span>' 475 . '<span lang="eo" class="multilang">Kurso resumo</span>' 476 . '@@PLUGINFILE@@/filename.txt' 477 . '<!-- Comment stripped when formatting text -->', 478 'summaryformat' => FORMAT_MOODLE 479 ]); 480 $user1 = self::getDataGenerator()->create_user(['username' => 'user1', 'lastaccess' => time()]); 481 $user2 = self::getDataGenerator()->create_user(['username' => 'user2', 'lastaccess' => time()]); 482 483 self::setUser($user1); 484 485 // Setup WS token. 486 $webservicemanager = new \webservice; 487 $service = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 488 $token = external_generate_token_for_current_user($service); 489 $_POST['wstoken'] = $token->token; 490 491 // Workaround for external_api::call_external_function requiring sesskey. 492 $_POST['sesskey'] = sesskey(); 493 494 // Call some functions. 495 496 $requests = [ 497 [ 498 'function' => 'core_course_get_courses_by_field', 499 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]) 500 ], 501 [ 502 'function' => 'core_user_get_users_by_field', 503 'arguments' => json_encode(['field' => 'id', 'values' => [$user1->id]]) 504 ], 505 [ 506 'function' => 'core_user_get_user_preferences', 507 'arguments' => json_encode(['name' => 'some_setting', 'userid' => $user2->id]) 508 ], 509 [ 510 'function' => 'core_course_get_courses_by_field', 511 'arguments' => json_encode(['field' => 'shortname', 'value' => $course->shortname]) 512 ], 513 ]; 514 $result = external::call_external_functions($requests); 515 516 // We need to execute the return values cleaning process to simulate the web service server. 517 $result = external_api::clean_returnvalue(external::call_external_functions_returns(), $result); 518 519 // Only 3 responses, the 4th request is not executed because the 3rd throws an exception. 520 $this->assertCount(3, $result['responses']); 521 522 $this->assertFalse($result['responses'][0]['error']); 523 $coursedata = external_api::clean_returnvalue( 524 core_course_external::get_courses_by_field_returns(), 525 core_course_external::get_courses_by_field('id', $course->id)); 526 $this->assertEquals(json_encode($coursedata), $result['responses'][0]['data']); 527 528 $this->assertFalse($result['responses'][1]['error']); 529 $userdata = external_api::clean_returnvalue( 530 core_user_external::get_users_by_field_returns(), 531 core_user_external::get_users_by_field('id', [$user1->id])); 532 $this->assertEquals(json_encode($userdata), $result['responses'][1]['data']); 533 534 $this->assertTrue($result['responses'][2]['error']); 535 $exception = json_decode($result['responses'][2]['exception'], true); 536 $this->assertEquals('nopermissions', $exception['errorcode']); 537 538 // Call a function not included in the external service. 539 540 $_POST['wstoken'] = $token->token; 541 $functions = $webservicemanager->get_not_associated_external_functions($service->id); 542 $requests = [['function' => current($functions)->name]]; 543 $result = external::call_external_functions($requests); 544 545 $this->assertTrue($result['responses'][0]['error']); 546 $exception = json_decode($result['responses'][0]['exception'], true); 547 $this->assertEquals('accessexception', $exception['errorcode']); 548 $this->assertEquals('webservice', $exception['module']); 549 550 // Call a function with different external settings. 551 552 filter_set_global_state('multilang', TEXTFILTER_ON); 553 $_POST['wstoken'] = $token->token; 554 $SESSION->lang = 'eo'; // Change default language, so we can test changing it to "en". 555 $requests = [ 556 [ 557 'function' => 'core_course_get_courses_by_field', 558 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 559 ], 560 [ 561 'function' => 'core_course_get_courses_by_field', 562 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 563 'settingraw' => '1' 564 ], 565 [ 566 'function' => 'core_course_get_courses_by_field', 567 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 568 'settingraw' => '1', 569 'settingfileurl' => '0' 570 ], 571 [ 572 'function' => 'core_course_get_courses_by_field', 573 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 574 'settingfilter' => '1', 575 'settinglang' => 'en' 576 ], 577 ]; 578 $result = external::call_external_functions($requests); 579 580 $this->assertCount(4, $result['responses']); 581 582 $context = \context_course::instance($course->id); 583 $pluginfile = 'webservice/pluginfile.php'; 584 585 $this->assertFalse($result['responses'][0]['error']); 586 $data = json_decode($result['responses'][0]['data']); 587 $expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null); 588 $expected = format_text($expected, $course->summaryformat, ['para' => false, 'filter' => false]); 589 $this->assertEquals($expected, $data->courses[0]->summary); 590 591 $this->assertFalse($result['responses'][1]['error']); 592 $data = json_decode($result['responses'][1]['data']); 593 $expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null); 594 $this->assertEquals($expected, $data->courses[0]->summary); 595 596 $this->assertFalse($result['responses'][2]['error']); 597 $data = json_decode($result['responses'][2]['data']); 598 $this->assertEquals($course->summary, $data->courses[0]->summary); 599 600 $this->assertFalse($result['responses'][3]['error']); 601 $data = json_decode($result['responses'][3]['data']); 602 $expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null); 603 $SESSION->lang = 'en'; // We expect filtered text in english. 604 $expected = format_text($expected, $course->summaryformat, ['para' => false, 'filter' => true]); 605 $this->assertEquals($expected, $data->courses[0]->summary); 606 } 607 608 /* 609 * Test get_tokens_for_qr_login. 610 */ 611 public function test_get_tokens_for_qr_login() { 612 global $DB, $CFG, $USER; 613 614 $this->resetAfterTest(true); 615 616 $user = $this->getDataGenerator()->create_user(); 617 $this->setUser($user); 618 619 $qrloginkey = api::get_qrlogin_key(); 620 621 // Generate new tokens, the ones we expect to receive. 622 $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 623 $token = external_generate_token_for_current_user($service); 624 625 // Fake the app. 626 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 627 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 628 629 $result = external::get_tokens_for_qr_login($qrloginkey, $USER->id); 630 $result = external_api::clean_returnvalue(external::get_tokens_for_qr_login_returns(), $result); 631 632 $this->assertEmpty($result['warnings']); 633 $this->assertEquals($token->token, $result['token']); 634 $this->assertEquals($token->privatetoken, $result['privatetoken']); 635 636 // Now, try with an invalid key. 637 $this->expectException('moodle_exception'); 638 $this->expectExceptionMessage(get_string('invalidkey', 'error')); 639 $result = external::get_tokens_for_qr_login(random_string('64'), $user->id); 640 } 641 642 /** 643 * Test get_tokens_for_qr_login missing QR code enabled. 644 */ 645 public function test_get_tokens_for_qr_login_missing_enableqr() { 646 global $CFG, $USER; 647 $this->resetAfterTest(true); 648 $this->setAdminUser(); 649 650 set_config('qrcodetype', tool_mobile\api::QR_CODE_DISABLED, 'tool_mobile'); 651 652 $this->expectExceptionMessage(get_string('qrcodedisabled', 'tool_mobile')); 653 $result = external::get_tokens_for_qr_login('', $USER->id); 654 } 655 656 /** 657 * Test get_tokens_for_qr_login missing ws. 658 */ 659 public function test_get_tokens_for_qr_login_missing_ws() { 660 global $CFG; 661 $this->resetAfterTest(true); 662 663 $user = $this->getDataGenerator()->create_user(); 664 $this->setUser($user); 665 666 // Fake the app. 667 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 668 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 669 670 // Need to disable webservices to verify that's checked. 671 $CFG->enablewebservices = 0; 672 $CFG->enablemobilewebservice = 0; 673 674 $this->setAdminUser(); 675 $this->expectException('moodle_exception'); 676 $this->expectExceptionMessage(get_string('enablewsdescription', 'webservice')); 677 $result = external::get_tokens_for_qr_login('', $user->id); 678 } 679 680 /** 681 * Test get_tokens_for_qr_login missing https. 682 */ 683 public function test_get_tokens_for_qr_login_missing_https() { 684 global $CFG, $USER; 685 686 // Fake the app. 687 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 688 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 689 690 // Need to simulate a non HTTPS site here. 691 $CFG->wwwroot = str_replace('https:', 'http:', $CFG->wwwroot); 692 693 $this->resetAfterTest(true); 694 $this->setAdminUser(); 695 696 $this->expectException('moodle_exception'); 697 $this->expectExceptionMessage(get_string('httpsrequired', 'tool_mobile')); 698 $result = external::get_tokens_for_qr_login('', $USER->id); 699 } 700 701 /** 702 * Test get_tokens_for_qr_login missing admin. 703 */ 704 public function test_get_tokens_for_qr_login_missing_admin() { 705 global $CFG, $USER; 706 707 $this->resetAfterTest(true); 708 $this->setAdminUser(); 709 710 // Fake the app. 711 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 712 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 713 714 $this->expectException('moodle_exception'); 715 $this->expectExceptionMessage(get_string('autologinnotallowedtoadmins', 'tool_mobile')); 716 $result = external::get_tokens_for_qr_login('', $USER->id); 717 } 718 719 /** 720 * Test get_tokens_for_qr_login missing app_request. 721 */ 722 public function test_get_tokens_for_qr_login_missing_app_request() { 723 global $CFG, $USER; 724 725 $this->resetAfterTest(true); 726 $this->setAdminUser(); 727 728 $this->expectException('moodle_exception'); 729 $this->expectExceptionMessage(get_string('apprequired', 'tool_mobile')); 730 $result = external::get_tokens_for_qr_login('', $USER->id); 731 } 732 733 /** 734 * Test validate subscription key. 735 */ 736 public function test_validate_subscription_key_valid() { 737 $this->resetAfterTest(true); 738 739 $sitesubscriptionkey = ['validuntil' => time() + MINSECS, 'key' => complex_random_string(32)]; 740 set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile'); 741 742 $result = external::validate_subscription_key($sitesubscriptionkey['key']); 743 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 744 $this->assertEmpty($result['warnings']); 745 $this->assertTrue($result['validated']); 746 } 747 748 /** 749 * Test validate subscription key invalid first and then a valid one. 750 */ 751 public function test_validate_subscription_key_invalid_key_first() { 752 $this->resetAfterTest(true); 753 754 $sitesubscriptionkey = ['validuntil' => time() + MINSECS, 'key' => complex_random_string(32)]; 755 set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile'); 756 757 $result = external::validate_subscription_key('fakekey'); 758 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 759 $this->assertEmpty($result['warnings']); 760 $this->assertFalse($result['validated']); 761 762 // The valid one has been invalidated because the previous attempt. 763 $result = external::validate_subscription_key($sitesubscriptionkey['key']); 764 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 765 $this->assertEmpty($result['warnings']); 766 $this->assertFalse($result['validated']); 767 } 768 769 /** 770 * Test validate subscription key invalid. 771 */ 772 public function test_validate_subscription_key_invalid_key() { 773 $this->resetAfterTest(true); 774 775 $result = external::validate_subscription_key('fakekey'); 776 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 777 $this->assertEmpty($result['warnings']); 778 $this->assertFalse($result['validated']); 779 } 780 781 /** 782 * Test validate subscription key invalid. 783 */ 784 public function test_validate_subscription_key_outdated() { 785 $this->resetAfterTest(true); 786 787 $sitesubscriptionkey = ['validuntil' => time() - MINSECS, 'key' => complex_random_string(32)]; 788 set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile'); 789 790 $result = external::validate_subscription_key($sitesubscriptionkey['key']); 791 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 792 $this->assertEmpty($result['warnings']); 793 $this->assertFalse($result['validated']); 794 } 795 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body