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