Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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->assertStringContainsString($CFG->wwwroot, $identityproviders[0]['url']); 162 163 $this->assertEquals('CAS', $identityproviders[1]['name']); 164 $this->assertEmpty($identityproviders[1]['iconurl']); 165 $this->assertStringContainsString($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->assertStringContainsString($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_filetypeexclusionlist', 'value' => ''), 217 array('name' => 'tool_mobile_custommenuitems', 'value' => ''), 218 array('name' => 'tool_mobile_apppolicy', 'value' => ''), 219 array('name' => 'calendartype', 'value' => $CFG->calendartype), 220 array('name' => 'calendar_site_timeformat', 'value' => $CFG->calendar_site_timeformat), 221 array('name' => 'calendar_startwday', 'value' => $CFG->calendar_startwday), 222 array('name' => 'calendar_adminseesall', 'value' => $CFG->calendar_adminseesall), 223 array('name' => 'calendar_lookahead', 'value' => $CFG->calendar_lookahead), 224 array('name' => 'calendar_maxevents', 'value' => $CFG->calendar_maxevents), 225 ); 226 $colornumbers = range(1, 10); 227 foreach ($colornumbers as $number) { 228 $expected[] = [ 229 'name' => 'core_admin_coursecolor' . $number, 230 'value' => get_config('core_admin', 'coursecolor' . $number) 231 ]; 232 } 233 $expected[] = ['name' => 'supportname', 'value' => $CFG->supportname]; 234 $expected[] = ['name' => 'supportemail', 'value' => $CFG->supportemail]; 235 $expected[] = ['name' => 'supportpage', 'value' => $CFG->supportpage]; 236 237 $expected[] = ['name' => 'coursegraceperiodafter', 'value' => $CFG->coursegraceperiodafter]; 238 $expected[] = ['name' => 'coursegraceperiodbefore', 'value' => $CFG->coursegraceperiodbefore]; 239 240 $this->assertCount(0, $result['warnings']); 241 $this->assertEquals($expected, $result['settings']); 242 243 // Change a value and retrieve filtering by section. 244 set_config('commentsperpage', 1); 245 $expected[10]['value'] = 1; 246 // Remove not expected elements. 247 array_splice($expected, 11); 248 249 $result = external::get_config('frontpagesettings'); 250 $result = external_api::clean_returnvalue(external::get_config_returns(), $result); 251 $this->assertCount(0, $result['warnings']); 252 $this->assertEquals($expected, $result['settings']); 253 } 254 255 /* 256 * Test get_autologin_key. 257 */ 258 public function test_get_autologin_key() { 259 global $DB, $CFG, $USER; 260 261 $this->resetAfterTest(true); 262 263 $user = $this->getDataGenerator()->create_user(); 264 $this->setUser($user); 265 $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 266 267 $token = external_generate_token_for_current_user($service); 268 269 // Check we got the private token. 270 $this->assertTrue(isset($token->privatetoken)); 271 272 // Enable requeriments. 273 $_GET['wstoken'] = $token->token; // Mock parameters. 274 275 // Fake the app. 276 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 277 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 278 279 // Even if we force the password change for the current user we should be able to retrieve the key. 280 set_user_preference('auth_forcepasswordchange', 1, $user->id); 281 282 $this->setCurrentTimeStart(); 283 $result = external::get_autologin_key($token->privatetoken); 284 $result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result); 285 // Validate the key. 286 $this->assertEquals(32, core_text::strlen($result['key'])); 287 $key = $DB->get_record('user_private_key', array('value' => $result['key'])); 288 $this->assertEquals($USER->id, $key->userid); 289 $this->assertTimeCurrent($key->validuntil - api::LOGIN_KEY_TTL); 290 291 // Now, try with an invalid private token. 292 set_user_preference('tool_mobile_autologin_request_last', time() - HOURSECS, $USER); 293 294 $this->expectException('moodle_exception'); 295 $this->expectExceptionMessage(get_string('invalidprivatetoken', 'tool_mobile')); 296 $result = external::get_autologin_key(random_string('64')); 297 } 298 299 /** 300 * Test get_autologin_key missing ws. 301 */ 302 public function test_get_autologin_key_missing_ws() { 303 global $CFG; 304 $this->resetAfterTest(true); 305 306 // Fake the app. 307 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 308 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 309 310 // Need to disable webservices to verify that's checked. 311 $CFG->enablewebservices = 0; 312 $CFG->enablemobilewebservice = 0; 313 314 $this->setAdminUser(); 315 $this->expectException('moodle_exception'); 316 $this->expectExceptionMessage(get_string('enablewsdescription', 'webservice')); 317 $result = external::get_autologin_key(''); 318 } 319 320 /** 321 * Test get_autologin_key missing https. 322 */ 323 public function test_get_autologin_key_missing_https() { 324 global $CFG; 325 326 // Fake the app. 327 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 328 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 329 330 // Need to simulate a non HTTPS site here. 331 $CFG->wwwroot = str_replace('https:', 'http:', $CFG->wwwroot); 332 333 $this->resetAfterTest(true); 334 $this->setAdminUser(); 335 336 $this->expectException('moodle_exception'); 337 $this->expectExceptionMessage(get_string('httpsrequired', 'tool_mobile')); 338 $result = external::get_autologin_key(''); 339 } 340 341 /** 342 * Test get_autologin_key missing admin. 343 */ 344 public function test_get_autologin_key_missing_admin() { 345 global $CFG; 346 347 $this->resetAfterTest(true); 348 $this->setAdminUser(); 349 350 // Fake the app. 351 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 352 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 353 354 $this->expectException('moodle_exception'); 355 $this->expectExceptionMessage(get_string('autologinnotallowedtoadmins', 'tool_mobile')); 356 $result = external::get_autologin_key(''); 357 } 358 359 /** 360 * Test get_autologin_key locked. 361 */ 362 public function test_get_autologin_key_missing_locked() { 363 global $CFG, $DB, $USER; 364 365 $this->resetAfterTest(true); 366 $user = $this->getDataGenerator()->create_user(); 367 $this->setUser($user); 368 369 $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 370 371 $token = external_generate_token_for_current_user($service); 372 $_GET['wstoken'] = $token->token; // Mock parameters. 373 374 // Fake the app. 375 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 376 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 377 378 $result = external::get_autologin_key($token->privatetoken); 379 $result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result); 380 381 // Mock last time request. 382 $mocktime = time() - 7 * MINSECS; 383 set_user_preference('tool_mobile_autologin_request_last', $mocktime, $USER); 384 $result = external::get_autologin_key($token->privatetoken); 385 $result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result); 386 387 // We just requested one token, we must wait. 388 $this->expectException('moodle_exception'); 389 $this->expectExceptionMessage(get_string('autologinkeygenerationlockout', 'tool_mobile')); 390 $result = external::get_autologin_key($token->privatetoken); 391 } 392 393 /** 394 * Test get_autologin_key missing app_request. 395 */ 396 public function test_get_autologin_key_missing_app_request() { 397 global $CFG; 398 399 $this->resetAfterTest(true); 400 $this->setAdminUser(); 401 402 $this->expectException('moodle_exception'); 403 $this->expectExceptionMessage(get_string('apprequired', 'tool_mobile')); 404 $result = external::get_autologin_key(''); 405 } 406 407 /** 408 * Test get_content. 409 */ 410 public function test_get_content() { 411 412 $paramval = 16; 413 $result = external::get_content('tool_mobile', 'test_view', array(array('name' => 'param1', 'value' => $paramval))); 414 $result = external_api::clean_returnvalue(external::get_content_returns(), $result); 415 $this->assertCount(1, $result['templates']); 416 $this->assertCount(1, $result['otherdata']); 417 $this->assertCount(2, $result['restrict']['users']); 418 $this->assertCount(2, $result['restrict']['courses']); 419 $this->assertEquals('alert();', $result['javascript']); 420 $this->assertEquals('main', $result['templates'][0]['id']); 421 $this->assertEquals('The HTML code', $result['templates'][0]['html']); 422 $this->assertEquals('otherdata1', $result['otherdata'][0]['name']); 423 $this->assertEquals($paramval, $result['otherdata'][0]['value']); 424 $this->assertEquals(array(1, 2), $result['restrict']['users']); 425 $this->assertEquals(array(3, 4), $result['restrict']['courses']); 426 $this->assertEmpty($result['files']); 427 $this->assertFalse($result['disabled']); 428 } 429 430 /** 431 * Test get_content disabled. 432 */ 433 public function test_get_content_disabled() { 434 435 $paramval = 16; 436 $result = external::get_content('tool_mobile', 'test_view_disabled', 437 array(array('name' => 'param1', 'value' => $paramval))); 438 $result = external_api::clean_returnvalue(external::get_content_returns(), $result); 439 $this->assertTrue($result['disabled']); 440 } 441 442 /** 443 * Test get_content non existent function in valid component. 444 */ 445 public function test_get_content_non_existent_function() { 446 447 $this->expectException('coding_exception'); 448 $result = external::get_content('tool_mobile', 'test_blahblah'); 449 } 450 451 /** 452 * Test get_content incorrect component. 453 */ 454 public function test_get_content_invalid_component() { 455 456 $this->expectException('moodle_exception'); 457 $result = external::get_content('tool_mobile\hack', 'test_view'); 458 } 459 460 /** 461 * Test get_content non existent component. 462 */ 463 public function test_get_content_non_existent_component() { 464 465 $this->expectException('moodle_exception'); 466 $result = external::get_content('tool_blahblahblah', 'test_view'); 467 } 468 469 public function test_call_external_functions() { 470 global $SESSION; 471 472 $this->resetAfterTest(true); 473 474 $category = self::getDataGenerator()->create_category(array('name' => 'Category 1')); 475 $course = self::getDataGenerator()->create_course([ 476 'category' => $category->id, 477 'shortname' => 'c1', 478 'summary' => '<span lang="en" class="multilang">Course summary</span>' 479 . '<span lang="eo" class="multilang">Kurso resumo</span>' 480 . '@@PLUGINFILE@@/filename.txt' 481 . '<!-- Comment stripped when formatting text -->', 482 'summaryformat' => FORMAT_MOODLE 483 ]); 484 $user1 = self::getDataGenerator()->create_user(['username' => 'user1', 'lastaccess' => time()]); 485 $user2 = self::getDataGenerator()->create_user(['username' => 'user2', 'lastaccess' => time()]); 486 487 self::setUser($user1); 488 489 // Setup WS token. 490 $webservicemanager = new \webservice; 491 $service = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); 492 $token = external_generate_token_for_current_user($service); 493 $_POST['wstoken'] = $token->token; 494 495 // Workaround for external_api::call_external_function requiring sesskey. 496 $_POST['sesskey'] = sesskey(); 497 498 // Call some functions. 499 500 $requests = [ 501 [ 502 'function' => 'core_course_get_courses_by_field', 503 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]) 504 ], 505 [ 506 'function' => 'core_user_get_users_by_field', 507 'arguments' => json_encode(['field' => 'id', 'values' => [$user1->id]]) 508 ], 509 [ 510 'function' => 'core_user_get_user_preferences', 511 'arguments' => json_encode(['name' => 'some_setting', 'userid' => $user2->id]) 512 ], 513 [ 514 'function' => 'core_course_get_courses_by_field', 515 'arguments' => json_encode(['field' => 'shortname', 'value' => $course->shortname]) 516 ], 517 ]; 518 $result = external::call_external_functions($requests); 519 520 // We need to execute the return values cleaning process to simulate the web service server. 521 $result = external_api::clean_returnvalue(external::call_external_functions_returns(), $result); 522 523 // Only 3 responses, the 4th request is not executed because the 3rd throws an exception. 524 $this->assertCount(3, $result['responses']); 525 526 $this->assertFalse($result['responses'][0]['error']); 527 $coursedata = external_api::clean_returnvalue( 528 core_course_external::get_courses_by_field_returns(), 529 core_course_external::get_courses_by_field('id', $course->id)); 530 $this->assertEquals(json_encode($coursedata), $result['responses'][0]['data']); 531 532 $this->assertFalse($result['responses'][1]['error']); 533 $userdata = external_api::clean_returnvalue( 534 core_user_external::get_users_by_field_returns(), 535 core_user_external::get_users_by_field('id', [$user1->id])); 536 $this->assertEquals(json_encode($userdata), $result['responses'][1]['data']); 537 538 $this->assertTrue($result['responses'][2]['error']); 539 $exception = json_decode($result['responses'][2]['exception'], true); 540 $this->assertEquals('nopermissions', $exception['errorcode']); 541 542 // Call a function not included in the external service. 543 544 $_POST['wstoken'] = $token->token; 545 $functions = $webservicemanager->get_not_associated_external_functions($service->id); 546 $requests = [['function' => current($functions)->name]]; 547 $result = external::call_external_functions($requests); 548 549 $this->assertTrue($result['responses'][0]['error']); 550 $exception = json_decode($result['responses'][0]['exception'], true); 551 $this->assertEquals('accessexception', $exception['errorcode']); 552 $this->assertEquals('webservice', $exception['module']); 553 554 // Call a function with different external settings. 555 556 filter_set_global_state('multilang', TEXTFILTER_ON); 557 $_POST['wstoken'] = $token->token; 558 $SESSION->lang = 'eo'; // Change default language, so we can test changing it to "en". 559 $requests = [ 560 [ 561 'function' => 'core_course_get_courses_by_field', 562 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 563 ], 564 [ 565 'function' => 'core_course_get_courses_by_field', 566 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 567 'settingraw' => '1' 568 ], 569 [ 570 'function' => 'core_course_get_courses_by_field', 571 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 572 'settingraw' => '1', 573 'settingfileurl' => '0' 574 ], 575 [ 576 'function' => 'core_course_get_courses_by_field', 577 'arguments' => json_encode(['field' => 'id', 'value' => $course->id]), 578 'settingfilter' => '1', 579 'settinglang' => 'en' 580 ], 581 ]; 582 $result = external::call_external_functions($requests); 583 584 $this->assertCount(4, $result['responses']); 585 586 $context = \context_course::instance($course->id); 587 $pluginfile = 'webservice/pluginfile.php'; 588 589 $this->assertFalse($result['responses'][0]['error']); 590 $data = json_decode($result['responses'][0]['data']); 591 $expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null); 592 $expected = format_text($expected, $course->summaryformat, ['para' => false, 'filter' => false]); 593 $this->assertEquals($expected, $data->courses[0]->summary); 594 595 $this->assertFalse($result['responses'][1]['error']); 596 $data = json_decode($result['responses'][1]['data']); 597 $expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null); 598 $this->assertEquals($expected, $data->courses[0]->summary); 599 600 $this->assertFalse($result['responses'][2]['error']); 601 $data = json_decode($result['responses'][2]['data']); 602 $this->assertEquals($course->summary, $data->courses[0]->summary); 603 604 $this->assertFalse($result['responses'][3]['error']); 605 $data = json_decode($result['responses'][3]['data']); 606 $expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null); 607 $SESSION->lang = 'en'; // We expect filtered text in english. 608 $expected = format_text($expected, $course->summaryformat, ['para' => false, 'filter' => true]); 609 $this->assertEquals($expected, $data->courses[0]->summary); 610 } 611 612 /* 613 * Test get_tokens_for_qr_login. 614 */ 615 public function test_get_tokens_for_qr_login() { 616 global $DB, $CFG, $USER; 617 618 $this->resetAfterTest(true); 619 620 $user = $this->getDataGenerator()->create_user(); 621 $this->setUser($user); 622 623 $qrloginkey = api::get_qrlogin_key(); 624 625 // Generate new tokens, the ones we expect to receive. 626 $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); 627 $token = external_generate_token_for_current_user($service); 628 629 // Fake the app. 630 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 631 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 632 633 $result = external::get_tokens_for_qr_login($qrloginkey, $USER->id); 634 $result = external_api::clean_returnvalue(external::get_tokens_for_qr_login_returns(), $result); 635 636 $this->assertEmpty($result['warnings']); 637 $this->assertEquals($token->token, $result['token']); 638 $this->assertEquals($token->privatetoken, $result['privatetoken']); 639 640 // Now, try with an invalid key. 641 $this->expectException('moodle_exception'); 642 $this->expectExceptionMessage(get_string('invalidkey', 'error')); 643 $result = external::get_tokens_for_qr_login(random_string('64'), $user->id); 644 } 645 646 /** 647 * Test get_tokens_for_qr_login missing QR code enabled. 648 */ 649 public function test_get_tokens_for_qr_login_missing_enableqr() { 650 global $CFG, $USER; 651 $this->resetAfterTest(true); 652 $this->setAdminUser(); 653 654 set_config('qrcodetype', tool_mobile\api::QR_CODE_DISABLED, 'tool_mobile'); 655 656 $this->expectExceptionMessage(get_string('qrcodedisabled', 'tool_mobile')); 657 $result = external::get_tokens_for_qr_login('', $USER->id); 658 } 659 660 /** 661 * Test get_tokens_for_qr_login missing ws. 662 */ 663 public function test_get_tokens_for_qr_login_missing_ws() { 664 global $CFG; 665 $this->resetAfterTest(true); 666 667 $user = $this->getDataGenerator()->create_user(); 668 $this->setUser($user); 669 670 // Fake the app. 671 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 672 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 673 674 // Need to disable webservices to verify that's checked. 675 $CFG->enablewebservices = 0; 676 $CFG->enablemobilewebservice = 0; 677 678 $this->setAdminUser(); 679 $this->expectException('moodle_exception'); 680 $this->expectExceptionMessage(get_string('enablewsdescription', 'webservice')); 681 $result = external::get_tokens_for_qr_login('', $user->id); 682 } 683 684 /** 685 * Test get_tokens_for_qr_login missing https. 686 */ 687 public function test_get_tokens_for_qr_login_missing_https() { 688 global $CFG, $USER; 689 690 // Fake the app. 691 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 692 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 693 694 // Need to simulate a non HTTPS site here. 695 $CFG->wwwroot = str_replace('https:', 'http:', $CFG->wwwroot); 696 697 $this->resetAfterTest(true); 698 $this->setAdminUser(); 699 700 $this->expectException('moodle_exception'); 701 $this->expectExceptionMessage(get_string('httpsrequired', 'tool_mobile')); 702 $result = external::get_tokens_for_qr_login('', $USER->id); 703 } 704 705 /** 706 * Test get_tokens_for_qr_login missing admin. 707 */ 708 public function test_get_tokens_for_qr_login_missing_admin() { 709 global $CFG, $USER; 710 711 $this->resetAfterTest(true); 712 $this->setAdminUser(); 713 714 // Fake the app. 715 core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' . 716 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile'); 717 718 $this->expectException('moodle_exception'); 719 $this->expectExceptionMessage(get_string('autologinnotallowedtoadmins', 'tool_mobile')); 720 $result = external::get_tokens_for_qr_login('', $USER->id); 721 } 722 723 /** 724 * Test get_tokens_for_qr_login missing app_request. 725 */ 726 public function test_get_tokens_for_qr_login_missing_app_request() { 727 global $CFG, $USER; 728 729 $this->resetAfterTest(true); 730 $this->setAdminUser(); 731 732 $this->expectException('moodle_exception'); 733 $this->expectExceptionMessage(get_string('apprequired', 'tool_mobile')); 734 $result = external::get_tokens_for_qr_login('', $USER->id); 735 } 736 737 /** 738 * Test validate subscription key. 739 */ 740 public function test_validate_subscription_key_valid() { 741 $this->resetAfterTest(true); 742 743 $sitesubscriptionkey = ['validuntil' => time() + MINSECS, 'key' => complex_random_string(32)]; 744 set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile'); 745 746 $result = external::validate_subscription_key($sitesubscriptionkey['key']); 747 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 748 $this->assertEmpty($result['warnings']); 749 $this->assertTrue($result['validated']); 750 } 751 752 /** 753 * Test validate subscription key invalid first and then a valid one. 754 */ 755 public function test_validate_subscription_key_invalid_key_first() { 756 $this->resetAfterTest(true); 757 758 $sitesubscriptionkey = ['validuntil' => time() + MINSECS, 'key' => complex_random_string(32)]; 759 set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile'); 760 761 $result = external::validate_subscription_key('fakekey'); 762 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 763 $this->assertEmpty($result['warnings']); 764 $this->assertFalse($result['validated']); 765 766 // The valid one has been invalidated because the previous attempt. 767 $result = external::validate_subscription_key($sitesubscriptionkey['key']); 768 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 769 $this->assertEmpty($result['warnings']); 770 $this->assertFalse($result['validated']); 771 } 772 773 /** 774 * Test validate subscription key invalid. 775 */ 776 public function test_validate_subscription_key_invalid_key() { 777 $this->resetAfterTest(true); 778 779 $result = external::validate_subscription_key('fakekey'); 780 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 781 $this->assertEmpty($result['warnings']); 782 $this->assertFalse($result['validated']); 783 } 784 785 /** 786 * Test validate subscription key invalid. 787 */ 788 public function test_validate_subscription_key_outdated() { 789 $this->resetAfterTest(true); 790 791 $sitesubscriptionkey = ['validuntil' => time() - MINSECS, 'key' => complex_random_string(32)]; 792 set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile'); 793 794 $result = external::validate_subscription_key($sitesubscriptionkey['key']); 795 $result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result); 796 $this->assertEmpty($result['warnings']); 797 $this->assertFalse($result['validated']); 798 } 799 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body