first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+159
View File
@@ -0,0 +1,159 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_mobile;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Moodle Mobile admin tool api tests.
*
* @package tool_mobile
* @copyright 2016 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.1
*/
class api_test extends \externallib_advanced_testcase {
/**
* Test get_autologin_key.
*/
public function test_get_autologin_key(): void {
global $USER, $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
// Set server timezone for test.
$this->setTimezone('UTC');
// SEt user to GMT+5.
$USER->timezone = 5;
$timenow = $this->setCurrentTimeStart();
$key = api::get_autologin_key();
$key = $DB->get_record('user_private_key', array('value' => $key), '*', MUST_EXIST);
$this->assertTimeCurrent($key->validuntil - api::LOGIN_KEY_TTL);
$this->assertEquals('0.0.0.0', $key->iprestriction);
}
/**
* Test get_potential_config_issues.
*/
public function test_get_potential_config_issues(): void {
global $CFG;
$this->resetAfterTest(true);
$this->setAdminUser();
// Set non-SSL wwwroot, to avoid spurious certificate checking.
$CFG->wwwroot = 'http://www.example.com';
$CFG->debugdisplay = 1;
set_config('debugauthdb', 1, 'auth_db');
set_config('debugdb', 1, 'enrol_database');
// Get potential issues, obtain their keys for comparison.
$issues = api::get_potential_config_issues();
$issuekeys = array_column($issues, 0);
$this->assertEqualsCanonicalizing([
'nohttpsformobilewarning',
'adodbdebugwarning',
'displayerrorswarning',
], $issuekeys);
}
/**
* Test pre_processor_message_send callback.
*/
public function test_pre_processor_message_send_callback(): void {
global $DB, $CFG;
$this->preventResetByRollback();
$this->resetAfterTest();
// Enable mobile services and required configuration.
$CFG->enablewebservices = 1;
$CFG->enablemobilewebservice = 1;
$mobileappdownloadpage = 'htt://mobileappdownloadpage';
set_config('setuplink', $mobileappdownloadpage, 'tool_mobile');
$user1 = $this->getDataGenerator()->create_user(array('maildisplay' => 1));
$user2 = $this->getDataGenerator()->create_user();
set_config('allowedemaildomains', 'example.com');
$DB->set_field_select('message_processors', 'enabled', 0, "name <> 'email'");
set_user_preference('message_provider_moodle_instantmessage_enabled', 'email', $user2);
// Extra content for all types of messages.
$message = new \core\message\message();
$message->courseid = 1;
$message->component = 'moodle';
$message->name = 'instantmessage';
$message->userfrom = $user1;
$message->userto = $user2;
$message->subject = 'message subject 1';
$message->fullmessage = 'message body';
$message->fullmessageformat = FORMAT_MARKDOWN;
$message->fullmessagehtml = '<p>message body</p>';
$message->smallmessage = 'small message';
$message->notification = '0';
$content = array('*' => array('header' => ' test ', 'footer' => ' test '));
$message->set_additional_content('email', $content);
$sink = $this->redirectEmails();
$messageid = message_send($message);
$emails = $sink->get_messages();
$this->assertCount(1, $emails);
$email = reset($emails);
// Check we got the promotion text.
$this->assertStringContainsString($mobileappdownloadpage, quoted_printable_decode($email->body));
$sink->clear();
// Disable mobile so we don't get mobile promotions.
$CFG->enablemobilewebservice = 0;
$messageid = message_send($message);
$emails = $sink->get_messages();
$this->assertCount(1, $emails);
$email = reset($emails);
// Check we don't get the promotion text.
$this->assertStringNotContainsString($mobileappdownloadpage, quoted_printable_decode($email->body));
$sink->clear();
// Enable mobile again and set current user mobile token so we don't get mobile promotions.
$CFG->enablemobilewebservice = 1;
$user3 = $this->getDataGenerator()->create_user();
$this->setUser($user3);
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
$token = \core_external\util::generate_token_for_current_user($service);
$message->userto = $user3;
$messageid = message_send($message);
$emails = $sink->get_messages();
$this->assertCount(1, $emails);
$email = reset($emails);
// Check we don't get the promotion text.
$this->assertStringNotContainsString($mobileappdownloadpage, quoted_printable_decode($email->body));
$sink->clear();
$sink->close();
}
}
@@ -0,0 +1,929 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_mobile;
use externallib_advanced_testcase;
use core_external\external_api;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/admin/tool/mobile/tests/fixtures/output/mobile.php');
require_once($CFG->dirroot . '/webservice/lib.php');
/**
* Moodle Mobile admin tool external functions tests.
*
* @package tool_mobile
* @copyright 2016 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since Moodle 3.1
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Test get_plugins_supporting_mobile.
* This is a very basic test because currently there aren't plugins supporting Mobile in core.
*/
public function test_get_plugins_supporting_mobile(): void {
$result = external::get_plugins_supporting_mobile();
$result = external_api::clean_returnvalue(external::get_plugins_supporting_mobile_returns(), $result);
$this->assertCount(0, $result['warnings']);
$this->assertArrayHasKey('plugins', $result);
$this->assertTrue(is_array($result['plugins']));
}
public function test_get_public_config(): void {
global $CFG, $SITE, $OUTPUT;
$this->resetAfterTest(true);
$result = external::get_public_config();
$result = external_api::clean_returnvalue(external::get_public_config_returns(), $result);
// Test default values.
$context = \context_system::instance();
[$authinstructions] = \core_external\util::format_text(
$CFG->auth_instructions,
FORMAT_MOODLE,
$context->id
);
[$maintenancemessage] = \core_external\util::format_text(
$CFG->maintenance_message,
FORMAT_MOODLE,
$context->id
);
$expected = array(
'wwwroot' => $CFG->wwwroot,
'httpswwwroot' => $CFG->wwwroot,
'sitename' => \core_external\util::format_string($SITE->fullname, $context->id, true),
'guestlogin' => $CFG->guestloginbutton,
'rememberusername' => $CFG->rememberusername,
'authloginviaemail' => $CFG->authloginviaemail,
'registerauth' => $CFG->registerauth,
'forgottenpasswordurl' => $CFG->forgottenpasswordurl,
'authinstructions' => $authinstructions,
'authnoneenabled' => (int) is_enabled_auth('none'),
'enablewebservices' => $CFG->enablewebservices,
'enablemobilewebservice' => $CFG->enablemobilewebservice,
'maintenanceenabled' => $CFG->maintenance_enabled,
'maintenancemessage' => $maintenancemessage,
'typeoflogin' => api::LOGIN_VIA_APP,
'mobilecssurl' => '',
'tool_mobile_disabledfeatures' => '',
'launchurl' => "$CFG->wwwroot/$CFG->admin/tool/mobile/launch.php",
'country' => $CFG->country,
'agedigitalconsentverification' => \core_auth\digital_consent::is_age_digital_consent_verification_enabled(),
'autolang' => $CFG->autolang,
'lang' => $CFG->lang,
'langmenu' => $CFG->langmenu,
'langlist' => $CFG->langlist,
'locale' => $CFG->locale,
'tool_mobile_minimumversion' => '',
'tool_mobile_iosappid' => get_config('tool_mobile', 'iosappid'),
'tool_mobile_androidappid' => get_config('tool_mobile', 'androidappid'),
'tool_mobile_setuplink' => get_config('tool_mobile', 'setuplink'),
'tool_mobile_qrcodetype' => get_config('tool_mobile', 'qrcodetype'),
'supportpage' => $CFG->supportpage,
'supportavailability' => $CFG->supportavailability,
'warnings' => array()
);
$this->assertEquals($expected, $result);
$this->setAdminUser();
// Change some values.
set_config('registerauth', 'email');
$authinstructions = 'Something with <b>html tags</b>';
set_config('auth_instructions', $authinstructions);
set_config('typeoflogin', api::LOGIN_VIA_BROWSER, 'tool_mobile');
set_config('logo', 'mock.png', 'core_admin');
set_config('logocompact', 'mock.png', 'core_admin');
set_config('forgottenpasswordurl', 'mailto:fake@email.zy'); // Test old hack.
set_config('agedigitalconsentverification', 1);
set_config('autolang', 1);
set_config('lang', 'a_b'); // Set invalid lang.
set_config('disabledfeatures', 'myoverview', 'tool_mobile');
set_config('minimumversion', '3.8.0', 'tool_mobile');
set_config('supportemail', 'test@test.com');
set_config('supportavailability', CONTACT_SUPPORT_ANYONE);
// Enable couple of issuers.
$issuer = \core\oauth2\api::create_standard_issuer('google');
$irecord = $issuer->to_record();
$irecord->clientid = 'mock';
$irecord->clientsecret = 'mock';
\core\oauth2\api::update_issuer($irecord);
set_config('hostname', 'localhost', 'auth_cas');
set_config('auth_logo', 'http://invalidurl.com//invalid/', 'auth_cas');
set_config('auth_name', 'CAS', 'auth_cas');
set_config('auth', 'oauth2,cas');
list($authinstructions, $notusedformat) = \core_external\util::format_text($authinstructions, FORMAT_MOODLE, $context->id);
$expected['registerauth'] = 'email';
$expected['authinstructions'] = $authinstructions;
$expected['typeoflogin'] = api::LOGIN_VIA_BROWSER;
$expected['forgottenpasswordurl'] = ''; // Expect empty when it's not an URL.
$expected['agedigitalconsentverification'] = true;
$expected['supportname'] = $CFG->supportname;
$expected['supportemail'] = $CFG->supportemail;
$expected['supportavailability'] = $CFG->supportavailability;
$expected['autolang'] = '1';
$expected['lang'] = ''; // Expect empty because it was set to an invalid lang.
$expected['tool_mobile_disabledfeatures'] = 'myoverview';
$expected['tool_mobile_minimumversion'] = '3.8.0';
if ($logourl = $OUTPUT->get_logo_url()) {
$expected['logourl'] = $logourl->out(false);
}
if ($compactlogourl = $OUTPUT->get_compact_logo_url()) {
$expected['compactlogourl'] = $compactlogourl->out(false);
}
$result = external::get_public_config();
$result = external_api::clean_returnvalue(external::get_public_config_returns(), $result);
// First check providers.
$identityproviders = $result['identityproviders'];
unset($result['identityproviders']);
$this->assertEquals('Google', $identityproviders[0]['name']);
$this->assertEquals($irecord->image, $identityproviders[0]['iconurl']);
$this->assertStringContainsString($CFG->wwwroot, $identityproviders[0]['url']);
$this->assertEquals('CAS', $identityproviders[1]['name']);
$this->assertEmpty($identityproviders[1]['iconurl']);
$this->assertStringContainsString($CFG->wwwroot, $identityproviders[1]['url']);
$this->assertEquals($expected, $result);
// Change providers img.
$newurl = 'validimage.png';
set_config('auth_logo', $newurl, 'auth_cas');
$result = external::get_public_config();
$result = external_api::clean_returnvalue(external::get_public_config_returns(), $result);
$this->assertStringContainsString($newurl, $result['identityproviders'][1]['iconurl']);
}
/**
* Test get_config
*
* @covers \tool_mobile\external::get_config
*/
public function test_get_config(): void {
global $CFG, $SITE;
require_once($CFG->dirroot . '/course/format/lib.php');
$this->resetAfterTest(true);
$mysitepolicy = 'http://mysite.is/policy/';
set_config('sitepolicy', $mysitepolicy);
set_config('supportemail', 'test@test.com');
$result = external::get_config();
$result = external_api::clean_returnvalue(external::get_config_returns(), $result);
// SITE summary is null in phpunit which gets transformed to an empty string by format_text.
[$sitesummary, $summaryformat] = \core_external\util::format_text(
$SITE->summary,
$SITE->summaryformat,
\context_system::instance()->id
);
// Test default values.
$context = \context_system::instance();
$expected = array(
array('name' => 'fullname', 'value' => $SITE->fullname),
array('name' => 'shortname', 'value' => $SITE->shortname),
array('name' => 'summary', 'value' => $sitesummary),
array('name' => 'summaryformat', 'value' => $summaryformat),
array('name' => 'frontpage', 'value' => $CFG->frontpage),
array('name' => 'frontpageloggedin', 'value' => $CFG->frontpageloggedin),
array('name' => 'maxcategorydepth', 'value' => $CFG->maxcategorydepth),
array('name' => 'frontpagecourselimit', 'value' => $CFG->frontpagecourselimit),
array('name' => 'numsections', 'value' => course_get_format($SITE)->get_last_section_number()),
array('name' => 'newsitems', 'value' => $SITE->newsitems),
array('name' => 'commentsperpage', 'value' => $CFG->commentsperpage),
array('name' => 'sitepolicy', 'value' => $mysitepolicy),
array('name' => 'sitepolicyhandler', 'value' => ''),
array('name' => 'disableuserimages', 'value' => $CFG->disableuserimages),
array('name' => 'mygradesurl', 'value' => user_mygrades_url()->out(false)),
array('name' => 'tool_mobile_forcelogout', 'value' => 0),
array('name' => 'tool_mobile_customlangstrings', 'value' => ''),
array('name' => 'tool_mobile_disabledfeatures', 'value' => ''),
array('name' => 'tool_mobile_filetypeexclusionlist', 'value' => ''),
array('name' => 'tool_mobile_custommenuitems', 'value' => ''),
array('name' => 'tool_mobile_apppolicy', 'value' => ''),
array('name' => 'tool_mobile_autologinmintimebetweenreq', 'value' => 6 * MINSECS),
array('name' => 'tool_mobile_autologout', 'value' => get_config('tool_mobile', 'autologout')),
array('name' => 'tool_mobile_autologouttime', 'value' => get_config('tool_mobile', 'autologouttime')),
array('name' => 'calendartype', 'value' => $CFG->calendartype),
array('name' => 'calendar_site_timeformat', 'value' => $CFG->calendar_site_timeformat),
array('name' => 'calendar_startwday', 'value' => $CFG->calendar_startwday),
array('name' => 'calendar_adminseesall', 'value' => $CFG->calendar_adminseesall),
array('name' => 'calendar_lookahead', 'value' => $CFG->calendar_lookahead),
array('name' => 'calendar_maxevents', 'value' => $CFG->calendar_maxevents),
);
$colornumbers = range(1, 10);
foreach ($colornumbers as $number) {
$expected[] = [
'name' => 'core_admin_coursecolor' . $number,
'value' => get_config('core_admin', 'coursecolor' . $number)
];
}
$expected[] = ['name' => 'supportavailability', 'value' => $CFG->supportavailability];
$expected[] = ['name' => 'supportname', 'value' => $CFG->supportname];
$expected[] = ['name' => 'supportemail', 'value' => $CFG->supportemail];
$expected[] = ['name' => 'supportpage', 'value' => $CFG->supportpage];
$expected[] = ['name' => 'coursegraceperiodafter', 'value' => $CFG->coursegraceperiodafter];
$expected[] = ['name' => 'coursegraceperiodbefore', 'value' => $CFG->coursegraceperiodbefore];
$expected[] = ['name' => 'enabledashboard', 'value' => $CFG->enabledashboard];
$expected[] = ['name' => 'customusermenuitems', 'value' => $CFG->customusermenuitems];
$expected[] = ['name' => 'timezone', 'value' => $CFG->timezone];
$expected[] = ['name' => 'forcetimezone', 'value' => $CFG->forcetimezone];
$expected[] = ['name' => 'searchengine', 'value' => $CFG->searchengine];
$expected[] = ['name' => 'searchenablecategories', 'value' => $CFG->searchenablecategories];
$expected[] = ['name' => 'searchdefaultcategory', 'value' => $CFG->searchdefaultcategory];
$expected[] = ['name' => 'searchhideallcategory', 'value' => $CFG->searchhideallcategory];
$expected[] = ['name' => 'searchmaxtopresults', 'value' => $CFG->searchmaxtopresults];
$expected[] = ['name' => 'searchbannerenable', 'value' => $CFG->searchbannerenable];
$expected[] = ['name' => 'searchbanner', 'value' => $CFG->searchbanner];
$expected[] = ['name' => 'tool_dataprivacy_contactdataprotectionofficer', 'value' => get_config('tool_dataprivacy', 'contactdataprotectionofficer')];
$expected[] = ['name' => 'tool_dataprivacy_showdataretentionsummary', 'value' => get_config('tool_dataprivacy', 'showdataretentionsummary')];
$expected[] = ['name' => 'useblogassociations', 'value' => $CFG->useblogassociations];
$expected[] = ['name' => 'bloglevel', 'value' => $CFG->bloglevel];
$expected[] = ['name' => 'blogusecomments', 'value' => $CFG->blogusecomments];
$this->assertCount(0, $result['warnings']);
$this->assertEquals($expected, $result['settings']);
// H5P custom CSS.
set_config('h5pcustomcss', '.debug { color: #fab; }', 'core_h5p');
\core_h5p\local\library\autoloader::register();
\core_h5p\file_storage::generate_custom_styles();
$result = external::get_config();
$result = external_api::clean_returnvalue(external::get_config_returns(), $result);
$customcss = \core_h5p\file_storage::get_custom_styles();
$expected[] = ['name' => 'h5pcustomcssurl', 'value' => $customcss['cssurl']->out() . '?ver=' . $customcss['cssversion']];
$this->assertCount(0, $result['warnings']);
$this->assertEquals($expected, $result['settings']);
// Change a value and retrieve filtering by section.
set_config('commentsperpage', 1);
$expected[10]['value'] = 1;
// Remove not expected elements.
array_splice($expected, 11);
$result = external::get_config('frontpagesettings');
$result = external_api::clean_returnvalue(external::get_config_returns(), $result);
$this->assertCount(0, $result['warnings']);
$this->assertEquals($expected, $result['settings']);
}
/*
* Test get_autologin_key.
*/
public function test_get_autologin_key(): void {
global $DB, $CFG, $USER;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
$token = \core_external\util::generate_token_for_current_user($service);
// Check we got the private token.
$this->assertTrue(isset($token->privatetoken));
// Enable requeriments.
$_GET['wstoken'] = $token->token; // Mock parameters.
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
// Even if we force the password change for the current user we should be able to retrieve the key.
set_user_preference('auth_forcepasswordchange', 1, $user->id);
$this->setCurrentTimeStart();
$result = external::get_autologin_key($token->privatetoken);
$result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result);
// Validate the key.
$this->assertEquals(32, \core_text::strlen($result['key']));
$key = $DB->get_record('user_private_key', array('value' => $result['key']));
$this->assertEquals($USER->id, $key->userid);
$this->assertTimeCurrent($key->validuntil - api::LOGIN_KEY_TTL);
// Now, try with an invalid private token.
set_user_preference('tool_mobile_autologin_request_last', time() - HOURSECS, $USER);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('invalidprivatetoken', 'tool_mobile'));
$result = external::get_autologin_key(random_string('64'));
}
/**
* Test get_autologin_key missing ws.
*/
public function test_get_autologin_key_missing_ws(): void {
global $CFG;
$this->resetAfterTest(true);
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
// Need to disable webservices to verify that's checked.
$CFG->enablewebservices = 0;
$CFG->enablemobilewebservice = 0;
$this->setAdminUser();
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('enablewsdescription', 'webservice'));
$result = external::get_autologin_key('');
}
/**
* Test get_autologin_key missing https.
*/
public function test_get_autologin_key_missing_https(): void {
global $CFG;
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
// Need to simulate a non HTTPS site here.
$CFG->wwwroot = str_replace('https:', 'http:', $CFG->wwwroot);
$this->resetAfterTest(true);
$this->setAdminUser();
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('httpsrequired', 'tool_mobile'));
$result = external::get_autologin_key('');
}
/**
* Test get_autologin_key missing admin.
*/
public function test_get_autologin_key_missing_admin(): void {
global $CFG;
$this->resetAfterTest(true);
$this->setAdminUser();
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('autologinnotallowedtoadmins', 'tool_mobile'));
$result = external::get_autologin_key('');
}
/**
* Test get_autologin_key locked.
*/
public function test_get_autologin_key_missing_locked(): void {
global $CFG, $DB, $USER;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
$token = \core_external\util::generate_token_for_current_user($service);
$_GET['wstoken'] = $token->token; // Mock parameters.
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
$result = external::get_autologin_key($token->privatetoken);
$result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result);
// Mock last time request.
$mocktime = time() - 7 * MINSECS;
set_user_preference('tool_mobile_autologin_request_last', $mocktime, $USER);
$result = external::get_autologin_key($token->privatetoken);
$result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result);
// Change min time between requests to 3 minutes.
set_config('autologinmintimebetweenreq', 3 * MINSECS, 'tool_mobile');
// Mock a previous request, 4 minutes ago.
$mocktime = time() - (4 * MINSECS);
set_user_preference('tool_mobile_autologin_request_last', $mocktime, $USER);
$result = external::get_autologin_key($token->privatetoken);
$result = external_api::clean_returnvalue(external::get_autologin_key_returns(), $result);
// We just requested one token, we must wait.
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('autologinkeygenerationlockout', 'tool_mobile', 3));
$result = external::get_autologin_key($token->privatetoken);
}
/**
* Test get_autologin_key missing app_request.
*/
public function test_get_autologin_key_missing_app_request(): void {
global $CFG;
$this->resetAfterTest(true);
$this->setAdminUser();
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('apprequired', 'tool_mobile'));
$result = external::get_autologin_key('');
}
/**
* Test get_content.
*/
public function test_get_content(): void {
$paramval = 16;
$result = external::get_content('tool_mobile', 'test_view', array(array('name' => 'param1', 'value' => $paramval)));
$result = external_api::clean_returnvalue(external::get_content_returns(), $result);
$this->assertCount(1, $result['templates']);
$this->assertCount(1, $result['otherdata']);
$this->assertCount(2, $result['restrict']['users']);
$this->assertCount(2, $result['restrict']['courses']);
$this->assertEquals('alert();', $result['javascript']);
$this->assertEquals('main', $result['templates'][0]['id']);
$this->assertEquals('The HTML code', $result['templates'][0]['html']);
$this->assertEquals('otherdata1', $result['otherdata'][0]['name']);
$this->assertEquals($paramval, $result['otherdata'][0]['value']);
$this->assertEquals(array(1, 2), $result['restrict']['users']);
$this->assertEquals(array(3, 4), $result['restrict']['courses']);
$this->assertEmpty($result['files']);
$this->assertFalse($result['disabled']);
}
/**
* Test get_content disabled.
*/
public function test_get_content_disabled(): void {
$paramval = 16;
$result = external::get_content('tool_mobile', 'test_view_disabled',
array(array('name' => 'param1', 'value' => $paramval)));
$result = external_api::clean_returnvalue(external::get_content_returns(), $result);
$this->assertTrue($result['disabled']);
}
/**
* Test get_content non existent function in valid component.
*/
public function test_get_content_non_existent_function(): void {
$this->expectException('coding_exception');
$result = external::get_content('tool_mobile', 'test_blahblah');
}
/**
* Test get_content incorrect component.
*/
public function test_get_content_invalid_component(): void {
$this->expectException('moodle_exception');
$result = external::get_content('tool_mobile\hack', 'test_view');
}
/**
* Test get_content non existent component.
*/
public function test_get_content_non_existent_component(): void {
$this->expectException('moodle_exception');
$result = external::get_content('tool_blahblahblah', 'test_view');
}
public function test_call_external_functions(): void {
global $SESSION;
$this->resetAfterTest(true);
$category = self::getDataGenerator()->create_category(array('name' => 'Category 1'));
$course = self::getDataGenerator()->create_course([
'category' => $category->id,
'shortname' => 'c1',
'summary' => '<span lang="en" class="multilang">Course summary</span>'
. '<span lang="eo" class="multilang">Kurso resumo</span>'
. '@@PLUGINFILE@@/filename.txt'
. '<!-- Comment stripped when formatting text -->',
'summaryformat' => FORMAT_MOODLE
]);
$user1 = self::getDataGenerator()->create_user(['username' => 'user1', 'lastaccess' => time()]);
$user2 = self::getDataGenerator()->create_user(['username' => 'user2', 'lastaccess' => time()]);
self::setUser($user1);
// Setup WS token.
$webservicemanager = new \webservice;
$service = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
$token = \core_external\util::generate_token_for_current_user($service);
$_POST['wstoken'] = $token->token;
// Workaround for external_api::call_external_function requiring sesskey.
$_POST['sesskey'] = sesskey();
// Call some functions.
$requests = [
[
'function' => 'core_course_get_courses_by_field',
'arguments' => json_encode(['field' => 'id', 'value' => $course->id])
],
[
'function' => 'core_user_get_users_by_field',
'arguments' => json_encode(['field' => 'id', 'values' => [$user1->id]])
],
[
'function' => 'core_user_get_user_preferences',
'arguments' => json_encode(['name' => 'some_setting', 'userid' => $user2->id])
],
[
'function' => 'core_course_get_courses_by_field',
'arguments' => json_encode(['field' => 'shortname', 'value' => $course->shortname])
],
];
$result = external::call_external_functions($requests);
// We need to execute the return values cleaning process to simulate the web service server.
$result = external_api::clean_returnvalue(external::call_external_functions_returns(), $result);
// Only 3 responses, the 4th request is not executed because the 3rd throws an exception.
$this->assertCount(3, $result['responses']);
$this->assertFalse($result['responses'][0]['error']);
$coursedata = external_api::clean_returnvalue(
\core_course_external::get_courses_by_field_returns(),
\core_course_external::get_courses_by_field('id', $course->id));
$this->assertEquals(json_encode($coursedata), $result['responses'][0]['data']);
$this->assertFalse($result['responses'][1]['error']);
$userdata = external_api::clean_returnvalue(
\core_user_external::get_users_by_field_returns(),
\core_user_external::get_users_by_field('id', [$user1->id]));
$this->assertEquals(json_encode($userdata), $result['responses'][1]['data']);
$this->assertTrue($result['responses'][2]['error']);
$exception = json_decode($result['responses'][2]['exception'], true);
$this->assertEquals('nopermissions', $exception['errorcode']);
// Call a function not included in the external service.
$_POST['wstoken'] = $token->token;
$functions = $webservicemanager->get_not_associated_external_functions($service->id);
$requests = [['function' => current($functions)->name]];
$result = external::call_external_functions($requests);
$this->assertTrue($result['responses'][0]['error']);
$exception = json_decode($result['responses'][0]['exception'], true);
$this->assertEquals('accessexception', $exception['errorcode']);
$this->assertEquals('webservice', $exception['module']);
// Call a function with different external settings.
filter_set_global_state('multilang', TEXTFILTER_ON);
$_POST['wstoken'] = $token->token;
$SESSION->lang = 'eo'; // Change default language, so we can test changing it to "en".
$requests = [
[
'function' => 'core_course_get_courses_by_field',
'arguments' => json_encode(['field' => 'id', 'value' => $course->id]),
],
[
'function' => 'core_course_get_courses_by_field',
'arguments' => json_encode(['field' => 'id', 'value' => $course->id]),
'settingraw' => '1'
],
[
'function' => 'core_course_get_courses_by_field',
'arguments' => json_encode(['field' => 'id', 'value' => $course->id]),
'settingraw' => '1',
'settingfileurl' => '0'
],
[
'function' => 'core_course_get_courses_by_field',
'arguments' => json_encode(['field' => 'id', 'value' => $course->id]),
'settingfilter' => '1',
'settinglang' => 'en'
],
];
$result = external::call_external_functions($requests);
$this->assertCount(4, $result['responses']);
$context = \context_course::instance($course->id);
$pluginfile = 'webservice/pluginfile.php';
$this->assertFalse($result['responses'][0]['error']);
$data = json_decode($result['responses'][0]['data']);
$expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null);
$expected = format_text($expected, $course->summaryformat, ['para' => false, 'filter' => false]);
$this->assertEquals($expected, $data->courses[0]->summary);
$this->assertFalse($result['responses'][1]['error']);
$data = json_decode($result['responses'][1]['data']);
$expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null);
$this->assertEquals($expected, $data->courses[0]->summary);
$this->assertFalse($result['responses'][2]['error']);
$data = json_decode($result['responses'][2]['data']);
$this->assertEquals($course->summary, $data->courses[0]->summary);
$this->assertFalse($result['responses'][3]['error']);
$data = json_decode($result['responses'][3]['data']);
$expected = file_rewrite_pluginfile_urls($course->summary, $pluginfile, $context->id, 'course', 'summary', null);
$SESSION->lang = 'en'; // We expect filtered text in english.
$expected = format_text($expected, $course->summaryformat, ['para' => false, 'filter' => true]);
$this->assertEquals($expected, $data->courses[0]->summary);
}
/*
* Test get_tokens_for_qr_login.
*/
public function test_get_tokens_for_qr_login(): void {
global $DB, $CFG, $USER;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$mobilesettings = get_config('tool_mobile');
$mobilesettings->qrsameipcheck = 1;
$qrloginkey = api::get_qrlogin_key($mobilesettings);
// Generate new tokens, the ones we expect to receive.
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
$token = \core_external\util::generate_token_for_current_user($service);
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
$result = external::get_tokens_for_qr_login($qrloginkey, $USER->id);
$result = external_api::clean_returnvalue(external::get_tokens_for_qr_login_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertEquals($token->token, $result['token']);
$this->assertEquals($token->privatetoken, $result['privatetoken']);
// Now, try with an invalid key.
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('invalidkey', 'error'));
$result = external::get_tokens_for_qr_login(random_string('64'), $user->id);
}
/*
* Test get_tokens_for_qr_login ignore ip check.
*/
public function test_get_tokens_for_qr_login_ignore_ip_check(): void {
global $DB, $CFG, $USER;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$mobilesettings = get_config('tool_mobile');
$mobilesettings->qrsameipcheck = 0;
$qrloginkey = api::get_qrlogin_key($mobilesettings);
$key = $DB->get_record('user_private_key', ['value' => $qrloginkey]);
$this->assertNull($key->iprestriction);
// Generate new tokens, the ones we expect to receive.
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
$token = \core_external\util::generate_token_for_current_user($service);
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
$result = external::get_tokens_for_qr_login($qrloginkey, $USER->id);
$result = external_api::clean_returnvalue(external::get_tokens_for_qr_login_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertEquals($token->token, $result['token']);
$this->assertEquals($token->privatetoken, $result['privatetoken']);
// Now, try with an invalid key.
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('invalidkey', 'error'));
$result = external::get_tokens_for_qr_login(random_string('64'), $user->id);
}
/*
* Test get_tokens_for_qr_login ip check fails.
*/
public function test_get_tokens_for_qr_login_ip_check_mismatch(): void {
global $DB, $CFG, $USER;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$mobilesettings = get_config('tool_mobile');
$mobilesettings->qrsameipcheck = 1;
$qrloginkey = api::get_qrlogin_key($mobilesettings);
// Alter expected ip.
$DB->set_field('user_private_key', 'iprestriction', '6.6.6.6', ['value' => $qrloginkey]);
// Generate new tokens, the ones we expect to receive.
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
$token = \core_external\util::generate_token_for_current_user($service);
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('ipmismatch', 'error'));
$result = external::get_tokens_for_qr_login($qrloginkey, $USER->id);
}
/**
* Test get_tokens_for_qr_login missing QR code enabled.
*/
public function test_get_tokens_for_qr_login_missing_enableqr(): void {
global $CFG, $USER;
$this->resetAfterTest(true);
$this->setAdminUser();
set_config('qrcodetype', api::QR_CODE_DISABLED, 'tool_mobile');
$this->expectExceptionMessage(get_string('qrcodedisabled', 'tool_mobile'));
$result = external::get_tokens_for_qr_login('', $USER->id);
}
/**
* Test get_tokens_for_qr_login missing ws.
*/
public function test_get_tokens_for_qr_login_missing_ws(): void {
global $CFG;
$this->resetAfterTest(true);
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
// Need to disable webservices to verify that's checked.
$CFG->enablewebservices = 0;
$CFG->enablemobilewebservice = 0;
$this->setAdminUser();
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('enablewsdescription', 'webservice'));
$result = external::get_tokens_for_qr_login('', $user->id);
}
/**
* Test get_tokens_for_qr_login missing https.
*/
public function test_get_tokens_for_qr_login_missing_https(): void {
global $CFG, $USER;
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
// Need to simulate a non HTTPS site here.
$CFG->wwwroot = str_replace('https:', 'http:', $CFG->wwwroot);
$this->resetAfterTest(true);
$this->setAdminUser();
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('httpsrequired', 'tool_mobile'));
$result = external::get_tokens_for_qr_login('', $USER->id);
}
/**
* Test get_tokens_for_qr_login missing admin.
*/
public function test_get_tokens_for_qr_login_missing_admin(): void {
global $CFG, $USER;
$this->resetAfterTest(true);
$this->setAdminUser();
// Fake the app.
\core_useragent::instance(true, 'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) ' .
'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile');
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('autologinnotallowedtoadmins', 'tool_mobile'));
$result = external::get_tokens_for_qr_login('', $USER->id);
}
/**
* Test get_tokens_for_qr_login missing app_request.
*/
public function test_get_tokens_for_qr_login_missing_app_request(): void {
global $CFG, $USER;
$this->resetAfterTest(true);
$this->setAdminUser();
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('apprequired', 'tool_mobile'));
$result = external::get_tokens_for_qr_login('', $USER->id);
}
/**
* Test validate subscription key.
*/
public function test_validate_subscription_key_valid(): void {
$this->resetAfterTest(true);
$sitesubscriptionkey = ['validuntil' => time() + MINSECS, 'key' => complex_random_string(32)];
set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile');
$result = external::validate_subscription_key($sitesubscriptionkey['key']);
$result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertTrue($result['validated']);
}
/**
* Test validate subscription key invalid first and then a valid one.
*/
public function test_validate_subscription_key_invalid_key_first(): void {
$this->resetAfterTest(true);
$sitesubscriptionkey = ['validuntil' => time() + MINSECS, 'key' => complex_random_string(32)];
set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile');
$result = external::validate_subscription_key('fakekey');
$result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertFalse($result['validated']);
// The valid one has been invalidated because the previous attempt.
$result = external::validate_subscription_key($sitesubscriptionkey['key']);
$result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertFalse($result['validated']);
}
/**
* Test validate subscription key invalid.
*/
public function test_validate_subscription_key_invalid_key(): void {
$this->resetAfterTest(true);
$result = external::validate_subscription_key('fakekey');
$result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertFalse($result['validated']);
}
/**
* Test validate subscription key invalid.
*/
public function test_validate_subscription_key_outdated(): void {
$this->resetAfterTest(true);
$sitesubscriptionkey = ['validuntil' => time() - MINSECS, 'key' => complex_random_string(32)];
set_config('sitesubscriptionkey', json_encode($sitesubscriptionkey), 'tool_mobile');
$result = external::validate_subscription_key($sitesubscriptionkey['key']);
$result = external_api::clean_returnvalue(external::validate_subscription_key_returns(), $result);
$this->assertEmpty($result['warnings']);
$this->assertFalse($result['validated']);
}
}
+82
View File
@@ -0,0 +1,82 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Mock class for get_content.
*
* @package tool_mobile
* @copyright 2018 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_mobile\output;
defined('MOODLE_INTERNAL') || die;
/**
* Mock class for get_content.
*
* @package tool_mobile
* @copyright 2018 Juan Leyva
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mobile {
/**
* Returns a test view.
* @param array $args Arguments from tool_mobile_get_content WS
* @return array HTML, javascript and otherdata
*/
public static function test_view($args) {
$args = (object) $args;
return array(
'templates' => array(
array(
'id' => 'main',
'html' => 'The HTML code',
),
),
'javascript' => 'alert();',
'otherdata' => array('otherdata1' => $args->param1),
'restrict' => array('users' => array(1, 2), 'courses' => array(3, 4)),
'files' => array()
);
}
/**
* Returns a test view disabled.
* @param array $args Arguments from tool_mobile_get_content WS
* @return array HTML, javascript and otherdata
*/
public static function test_view_disabled($args) {
$args = (object) $args;
return array(
'templates' => array(
array(
'id' => 'main',
'html' => 'The HTML code',
),
),
'javascript' => 'alert();',
'otherdata' => array('otherdata1' => $args->param1),
'restrict' => array('users' => array(1, 2), 'courses' => array(3, 4)),
'files' => array(),
'disabled' => true,
);
}
}
@@ -0,0 +1,212 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Base class for unit tests for tool_mobile.
*
* @package tool_mobile
* @category test
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_mobile\privacy;
defined('MOODLE_INTERNAL') || die();
use core_privacy\local\request\writer;
use core_privacy\local\request\transform;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\approved_userlist;
use tool_mobile\privacy\provider;
/**
* Unit tests for the tool_mobile implementation of the privacy API.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider_test extends \core_privacy\tests\provider_testcase {
/**
* Basic setup for these tests.
*/
public function setUp(): void {
$this->resetAfterTest(true);
}
/**
* Test to check export_user_preferences.
* returns user preferences data.
*/
public function test_export_user_preferences(): void {
$user = $this->getDataGenerator()->create_user();
$expectedtime = time();
set_user_preference('tool_mobile_autologin_request_last', time(), $user);
provider::export_user_preferences($user->id);
$writer = writer::with_context(\context_system::instance());
$prefs = $writer->get_user_preferences('tool_mobile');
$time = transform::datetime($expectedtime);
$this->assertEquals($time, $prefs->tool_mobile_autologin_request_last->value);
$this->assertEquals(get_string('privacy:metadata:preference:tool_mobile_autologin_request_last', 'tool_mobile'),
$prefs->tool_mobile_autologin_request_last->description);
}
/**
* Test getting the context for the user ID related to this plugin.
*/
public function test_get_contexts_for_userid(): void {
// Create user and Mobile user keys.
$user = $this->getDataGenerator()->create_user();
$context = \context_user::instance($user->id);
$key = get_user_key('tool_mobile', $user->id);
$contextlist = provider::get_contexts_for_userid($user->id);
$this->assertEquals($context->id, $contextlist->current()->id);
}
/**
* Test getting the users for a context related to this plugin.
*/
public function test_get_users_in_context(): void {
$component = 'tool_mobile';
// Create users and Mobile user keys.
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$context1 = \context_user::instance($user1->id);
$context2 = \context_user::instance($user2->id);
$key1 = get_user_key('tool_mobile', $user1->id);
$key2 = get_user_key('tool_mobile/qrlogin', $user1->id);
$key3 = get_user_key('tool_mobile', $user2->id);
// Ensure only user1 is found in context1.
$userlist = new \core_privacy\local\request\userlist($context1, $component);
provider::get_users_in_context($userlist);
$userids = $userlist->get_userids();
$userid = reset($userids);
$this->assertCount(1, $userids);
$this->assertEquals($user1->id, $userid);
}
/**
* Test that data is exported correctly for this plugin.
*/
public function test_export_user_data(): void {
global $DB;
// Create user and Mobile user keys.
$user = $this->getDataGenerator()->create_user();
$context = \context_user::instance($user->id);
$keyvalue = get_user_key('tool_mobile', $user->id);
$key = $DB->get_record('user_private_key', ['value' => $keyvalue]);
// Validate exported data.
$this->setUser($user);
/** @var \core_privacy\tests\request\content_writer $writer */
$writer = writer::with_context($context);
$this->assertFalse($writer->has_any_data());
$this->export_context_data_for_user($user->id, $context, 'tool_mobile');
$userkeydata = $writer->get_related_data([], 'userkeys');
$this->assertCount(1, $userkeydata->keys);
$this->assertEquals($key->script, reset($userkeydata->keys)->script);
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context(): void {
global $DB;
// Create user and Mobile user keys.
$user = $this->getDataGenerator()->create_user();
$context = \context_user::instance($user->id);
$keyvalue = get_user_key('tool_mobile', $user->id);
$key = $DB->get_record('user_private_key', ['value' => $keyvalue]);
// Before deletion, we should have 1 user_private_key.
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(1, $count);
// Delete data.
provider::delete_data_for_all_users_in_context($context);
// After deletion, the user_private_key entries should have been deleted.
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(0, $count);
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user(): void {
global $DB;
// Create user and Mobile user keys.
$user = $this->getDataGenerator()->create_user();
$context = \context_user::instance($user->id);
$keyvalue = get_user_key('tool_mobile', $user->id);
$key = $DB->get_record('user_private_key', ['value' => $keyvalue]);
// Before deletion, we should have 1 user_private_key.
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(1, $count);
// Delete data.
$contextlist = provider::get_contexts_for_userid($user->id);
$approvedcontextlist = new approved_contextlist($user, 'tool_mobile', $contextlist->get_contextids());
provider::delete_data_for_user($approvedcontextlist);
// After deletion, the user_private_key entries should have been deleted.
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(0, $count);
}
/**
* Test for provider::test_delete_data_for_users().
*/
public function test_delete_data_for_users(): void {
global $DB;
$component = 'tool_mobile';
// Create users and Mobile user keys.
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$context1 = \context_user::instance($user1->id);
$context2 = \context_user::instance($user2->id);
$keyvalue1 = get_user_key('tool_mobile', $user1->id);
$keyvalue2 = get_user_key('tool_mobile/qrlogin', $user1->id);
$keyvalue3 = get_user_key('tool_mobile', $user2->id);
$key1 = $DB->get_record('user_private_key', ['value' => $keyvalue1]);
// Before deletion, we should have 2 user_private_keys for tool_mobile and one for tool_mobile/qrlogin.
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(2, $count);
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile/qrlogin']);
$this->assertEquals(1, $count);
// Ensure deleting wrong user in the user context does nothing.
$approveduserids = [$user2->id];
$approvedlist = new approved_userlist($context1, $component, $approveduserids);
provider::delete_data_for_users($approvedlist);
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(2, $count);
// Delete for user1 in context1.
$approveduserids = [$user1->id];
$approvedlist = new approved_userlist($context1, $component, $approveduserids);
provider::delete_data_for_users($approvedlist);
// Ensure only user1's data is deleted, user2's remains.
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']);
$this->assertEquals(1, $count);
$count = $DB->count_records('user_private_key', ['script' => 'tool_mobile/qrlogin']);
$this->assertEquals(0, $count);
$params = ['script' => $component];
$userid = $DB->get_field_select('user_private_key', 'userid', 'script = :script', $params);
$this->assertEquals($user2->id, $userid);
}
}