Merge branch 'MDL-65547-master' of git://github.com/jleyva/moodle
This commit is contained in:
@@ -31,6 +31,8 @@ use moodle_url;
|
||||
use moodle_exception;
|
||||
use lang_string;
|
||||
use curl;
|
||||
use core_qrcode;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* API exposed by tool_mobile, to be used mostly by external functions and the plugin settings.
|
||||
@@ -51,6 +53,14 @@ class api {
|
||||
const LOGIN_KEY_TTL = 60;
|
||||
/** @var string URL of the Moodle Apps Portal */
|
||||
const MOODLE_APPS_PORTAL_URL = 'https://apps.moodle.com';
|
||||
/** @var int seconds a QR login key will expire. */
|
||||
const LOGIN_QR_KEY_TTL = 600;
|
||||
/** @var int QR code disabled value */
|
||||
const QR_CODE_DISABLED = 0;
|
||||
/** @var int QR code type URL value */
|
||||
const QR_CODE_URL = 1;
|
||||
/** @var int QR code type login value */
|
||||
const QR_CODE_LOGIN = 2;
|
||||
|
||||
/**
|
||||
* Returns a list of Moodle plugins supporting the mobile app.
|
||||
@@ -336,6 +346,7 @@ class api {
|
||||
|
||||
/**
|
||||
* Creates an auto-login key for the current user, this key is restricted by time and ip address.
|
||||
* This key is used for automatically login the user in the site when the Moodle app opens the site in a mobile browser.
|
||||
*
|
||||
* @return string the key
|
||||
* @since Moodle 3.2
|
||||
@@ -351,6 +362,24 @@ class api {
|
||||
return create_user_key('tool_mobile', $USER->id, null, $iprestriction, $validuntil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a QR login key for the current user, this key is restricted by time and ip address.
|
||||
* This key is used for automatically login the user in the site when the user scans a QR code in the Moodle app.
|
||||
*
|
||||
* @return string the key
|
||||
* @since Moodle 3.9
|
||||
*/
|
||||
public static function get_qrlogin_key() {
|
||||
global $USER;
|
||||
// Delete previous keys.
|
||||
delete_user_key('tool_mobile', $USER->id);
|
||||
|
||||
// Create a new key.
|
||||
$iprestriction = getremoteaddr(null);
|
||||
$validuntil = time() + self::LOGIN_QR_KEY_TTL;
|
||||
return create_user_key('tool_mobile', $USER->id, null, $iprestriction, $validuntil);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of the Mobile app features.
|
||||
*
|
||||
@@ -601,4 +630,31 @@ class api {
|
||||
|
||||
return $warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a QR code with the site URL or for automatic login from the mobile app.
|
||||
*
|
||||
* @param stdClass $mobilesettings tool_mobile settings
|
||||
* @return string base64 data image contents, null if qr disabled
|
||||
*/
|
||||
public static function generate_login_qrcode(stdClass $mobilesettings) {
|
||||
global $CFG, $USER;
|
||||
|
||||
if ($mobilesettings->qrcodetype == static::QR_CODE_DISABLED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$urlscheme = !empty($mobilesettings->forcedurlscheme) ? $mobilesettings->forcedurlscheme : 'moodlemobile';
|
||||
$data = $urlscheme . '://' . $CFG->wwwroot;
|
||||
|
||||
if ($mobilesettings->qrcodetype == static::QR_CODE_LOGIN) {
|
||||
$qrloginkey = static::get_qrlogin_key();
|
||||
$data .= '?qrlogin=' . $qrloginkey . '&userid=' . $USER->id;
|
||||
}
|
||||
|
||||
$qrcode = new core_qrcode($data);
|
||||
$imagedata = 'data:image/png;base64,' . base64_encode($qrcode->getBarcodePngData(5, 5));
|
||||
|
||||
return $imagedata;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ use context_system;
|
||||
use moodle_exception;
|
||||
use moodle_url;
|
||||
use core_text;
|
||||
use core_user;
|
||||
use coding_exception;
|
||||
|
||||
/**
|
||||
@@ -593,4 +594,102 @@ class external extends external_api {
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of get_tokens_for_qr_login() parameters.
|
||||
*
|
||||
* @return external_function_parameters
|
||||
* @since Moodle 3.9
|
||||
*/
|
||||
public static function get_tokens_for_qr_login_parameters() {
|
||||
return new external_function_parameters (
|
||||
[
|
||||
'qrloginkey' => new external_value(PARAM_ALPHANUMEXT, 'The user key for validating the request.'),
|
||||
'userid' => new external_value(PARAM_INT, 'The user the key belongs to.'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a WebService token (and private token) for QR login
|
||||
*
|
||||
* @param string $qrloginkey the user key generated and embedded into the QR code for validating the request
|
||||
* @param int $userid the user the key belongs to
|
||||
* @return array with the tokens and warnings
|
||||
* @since Moodle 3.9
|
||||
*/
|
||||
public static function get_tokens_for_qr_login($qrloginkey, $userid) {
|
||||
global $PAGE, $DB;
|
||||
|
||||
$params = self::validate_parameters(self::get_tokens_for_qr_login_parameters(),
|
||||
['qrloginkey' => $qrloginkey, 'userid' => $userid]);
|
||||
|
||||
$context = context_system::instance();
|
||||
// We need this to make work the format text functions.
|
||||
$PAGE->set_context($context);
|
||||
|
||||
$qrcodetype = get_config('tool_mobile', 'qrcodetype');
|
||||
if ($qrcodetype != api::QR_CODE_LOGIN) {
|
||||
throw new moodle_exception('qrcodedisabled', 'tool_mobile');
|
||||
}
|
||||
|
||||
// Only requests from the Moodle mobile or desktop app. This enhances security to avoid any type of XSS attack.
|
||||
// This code goes intentionally here and not inside the check_autologin_prerequisites() function because it
|
||||
// is used by other PHP scripts that can be opened in any browser.
|
||||
if (!\core_useragent::is_moodle_app()) {
|
||||
throw new moodle_exception('apprequired', 'tool_mobile');
|
||||
}
|
||||
api::check_autologin_prerequisites($params['userid']); // Checks https, avoid site admins using this...
|
||||
|
||||
// Validate and delete the key.
|
||||
$key = validate_user_key($params['qrloginkey'], 'tool_mobile', null);
|
||||
delete_user_key('tool_mobile', $params['userid']);
|
||||
|
||||
// Double check key belong to user.
|
||||
if ($key->userid != $params['userid']) {
|
||||
throw new moodle_exception('invalidkey');
|
||||
}
|
||||
|
||||
// Key validated, check user.
|
||||
$user = core_user::get_user($key->userid, '*', MUST_EXIST);
|
||||
core_user::require_active_user($user, true, true);
|
||||
|
||||
// Generate WS tokens.
|
||||
\core\session\manager::set_user($user);
|
||||
|
||||
// Check if the service exists and is enabled.
|
||||
$service = $DB->get_record('external_services', ['shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE, 'enabled' => 1]);
|
||||
if (empty($service)) {
|
||||
// will throw exception if no token found
|
||||
throw new moodle_exception('servicenotavailable', 'webservice');
|
||||
}
|
||||
|
||||
// Get an existing token or create a new one.
|
||||
$token = external_generate_token_for_current_user($service);
|
||||
$privatetoken = $token->privatetoken; // Save it here, the next function removes it.
|
||||
external_log_token_request($token);
|
||||
|
||||
$result = [
|
||||
'token' => $token->token,
|
||||
'privatetoken' => $privatetoken ?: '',
|
||||
'warnings' => [],
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of get_tokens_for_qr_login() result value.
|
||||
*
|
||||
* @return external_description
|
||||
* @since Moodle 3.9
|
||||
*/
|
||||
public static function get_tokens_for_qr_login_returns() {
|
||||
return new external_single_structure(
|
||||
[
|
||||
'token' => new external_value(PARAM_ALPHANUM, 'A valid WebService token for the official mobile app service.'),
|
||||
'privatetoken' => new external_value(PARAM_ALPHANUM, 'Private token used for auto-login processes.'),
|
||||
'warnings' => new external_warnings(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,5 +78,14 @@ $functions = array(
|
||||
'type' => 'write',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
|
||||
),
|
||||
);
|
||||
|
||||
'tool_mobile_get_tokens_for_qr_login' => array(
|
||||
'classname' => 'tool_mobile\external',
|
||||
'methodname' => 'get_tokens_for_qr_login',
|
||||
'description' => 'Returns a WebService token (and private token) for QR login.',
|
||||
'type' => 'read',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE),
|
||||
'ajax' => true,
|
||||
'loginrequired' => false,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -96,6 +96,15 @@ $string['oauth2identityproviders'] = 'OAuth 2 identity providers';
|
||||
$string['offlineuse'] = 'Offline use';
|
||||
$string['pluginname'] = 'Moodle app tools';
|
||||
$string['pluginnotenabledorconfigured'] = 'Plugin not enabled or configured.';
|
||||
$string['qrcodedisabled'] = 'Access via QR code disabled';
|
||||
$string['qrcodeformobileappaccess'] = 'QR code for mobile app access';
|
||||
$string['qrcodeformobileapploginabout'] = 'Scan the QR code with your mobile app and you will be automatically logged in. The QR code will expire in {$a} minutes.';
|
||||
$string['qrcodeformobileappurlabout'] = 'Scan the QR code with your mobile app to fill in the site URL in your app.';
|
||||
$string['qrsiteadminsnotallowed'] = 'For security reasons login via QR code is not allowed for site administrators or if you are logged in as another user.';
|
||||
$string['qrcodetype'] = 'QR code access';
|
||||
$string['qrcodetype_desc'] = 'A QR code can be provided for mobile app users to scan and either have the site URL filled in or be automatically logged in without having to enter their credentials.';
|
||||
$string['qrcodetypeurl'] = 'QR code with site URL';
|
||||
$string['qrcodetypelogin'] = 'QR code with automatic login';
|
||||
$string['readingthisemailgettheapp'] = 'Reading this in an email? <a href="{$a}">Download the mobile app and receive notifications on your mobile device</a>.';
|
||||
$string['remoteaddons'] = 'Remote add-ons';
|
||||
$string['selfsignedoruntrustedcertificatewarning'] = 'It seems that the HTTPS certificate is self-signed or not trusted. The mobile app will only work with trusted sites.';
|
||||
@@ -108,3 +117,4 @@ $string['getmoodleonyourmobile'] = 'Get the mobile app';
|
||||
$string['privacy:metadata:preference:tool_mobile_autologin_request_last'] = 'The date of the last auto-login key request. Between each request 6 minutes are required.';
|
||||
$string['privacy:metadata:core_userkey'] = 'User\'s keys used to create auto-login key for the current user.';
|
||||
$string['responsivemainmenuitems'] = 'Responsive menu items';
|
||||
$string['viewqrcode'] = 'View QR code';
|
||||
|
||||
+51
-11
@@ -126,24 +126,64 @@ function tool_mobile_myprofile_navigation(\core_user\output\myprofile\tree $tree
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$url = tool_mobile_create_app_download_url()) {
|
||||
return;
|
||||
$newnodes = [];
|
||||
$mobilesettings = get_config('tool_mobile');
|
||||
|
||||
// Check if we should display a QR code.
|
||||
if (!empty($mobilesettings->qrcodetype)) {
|
||||
$mobileqr = null;
|
||||
$qrcodeforappstr = get_string('qrcodeformobileappaccess', 'tool_mobile');
|
||||
|
||||
if ($mobilesettings->qrcodetype == tool_mobile\api::QR_CODE_LOGIN && is_https()) {
|
||||
|
||||
if (is_siteadmin() || \core\session\manager::is_loggedinas()) {
|
||||
$mobileqr = get_string('qrsiteadminsnotallowed', 'tool_mobile');
|
||||
} else {
|
||||
$qrcodeimg = tool_mobile\api::generate_login_qrcode($mobilesettings);
|
||||
|
||||
$minutes = tool_mobile\api::LOGIN_QR_KEY_TTL / MINSECS;
|
||||
$mobileqr = html_writer::tag('p', get_string('qrcodeformobileapploginabout', 'tool_mobile', $minutes));
|
||||
$mobileqr .= html_writer::link('#qrcode', get_string('viewqrcode', 'tool_mobile'),
|
||||
['class' => 'btn btn-primary mt-2', 'data-toggle' => 'collapse',
|
||||
'role' => 'button', 'aria-expanded' => 'false']);
|
||||
$mobileqr .= html_writer::div(html_writer::img($qrcodeimg, $qrcodeforappstr), 'collapse mt-4', ['id' => 'qrcode']);
|
||||
}
|
||||
|
||||
} else if ($mobilesettings->qrcodetype == tool_mobile\api::QR_CODE_URL) {
|
||||
$qrcodeimg = tool_mobile\api::generate_login_qrcode($mobilesettings);
|
||||
|
||||
$mobileqr = get_string('qrcodeformobileappurlabout', 'tool_mobile');
|
||||
$mobileqr .= html_writer::div(html_writer::img($qrcodeimg, $qrcodeforappstr));
|
||||
}
|
||||
|
||||
if ($mobileqr) {
|
||||
$newnodes[] = new core_user\output\myprofile\node('mobile', 'mobileappqr', $qrcodeforappstr, null, null, $mobileqr);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user is using the app, encouraging him to use it otherwise.
|
||||
$userhastoken = tool_mobile_user_has_token($user->id);
|
||||
|
||||
$mobilecategory = new core_user\output\myprofile\category('mobile', get_string('mobileapp', 'tool_mobile'),
|
||||
'loginactivity');
|
||||
$tree->add_category($mobilecategory);
|
||||
$mobilestrconnected = null;
|
||||
|
||||
if ($userhastoken) {
|
||||
$mobilestr = get_string('mobileappconnected', 'tool_mobile');
|
||||
} else {
|
||||
$mobilestr = get_string('mobileappenabled', 'tool_mobile', $url->out());
|
||||
$mobilestrconnected = get_string('mobileappconnected', 'tool_mobile');
|
||||
} else if ($url = tool_mobile_create_app_download_url()) {
|
||||
$mobilestrconnected = get_string('mobileappenabled', 'tool_mobile', $url->out());
|
||||
}
|
||||
|
||||
$node = new core_user\output\myprofile\node('mobile', 'mobileappnode', $mobilestr, null);
|
||||
$tree->add_node($node);
|
||||
if ($mobilestrconnected) {
|
||||
$newnodes[] = new core_user\output\myprofile\node('mobile', 'mobileappnode', $mobilestrconnected, null);
|
||||
}
|
||||
|
||||
// Add nodes, if any.
|
||||
if (!empty($newnodes)) {
|
||||
$mobilecat = new core_user\output\myprofile\category('mobile', get_string('mobileapp', 'tool_mobile'), 'loginactivity');
|
||||
$tree->add_category($mobilecat);
|
||||
|
||||
foreach ($newnodes as $node) {
|
||||
$tree->add_node($node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,9 @@ if ($hassiteconfig) {
|
||||
|
||||
// Type of login.
|
||||
$temp = new admin_settingpage('mobileauthentication', new lang_string('mobileauthentication', 'tool_mobile'));
|
||||
|
||||
$temp->add(new admin_setting_heading('tool_mobile/moodleappsportalfeaturesauth', '', $featuresnotice));
|
||||
|
||||
$options = array(
|
||||
tool_mobile\api::LOGIN_VIA_APP => new lang_string('loginintheapp', 'tool_mobile'),
|
||||
tool_mobile\api::LOGIN_VIA_BROWSER => new lang_string('logininthebrowser', 'tool_mobile'),
|
||||
@@ -67,6 +70,15 @@ if ($hassiteconfig) {
|
||||
new lang_string('typeoflogin', 'tool_mobile'),
|
||||
new lang_string('typeoflogin_desc', 'tool_mobile'), 1, $options));
|
||||
|
||||
$options = [
|
||||
tool_mobile\api::QR_CODE_DISABLED => new lang_string('qrcodedisabled', 'tool_mobile'),
|
||||
tool_mobile\api::QR_CODE_URL => new lang_string('qrcodetypeurl', 'tool_mobile'),
|
||||
tool_mobile\api::QR_CODE_LOGIN => new lang_string('qrcodetypelogin', 'tool_mobile'),
|
||||
];
|
||||
$temp->add(new admin_setting_configselect('tool_mobile/qrcodetype',
|
||||
new lang_string('qrcodetype', 'tool_mobile'),
|
||||
new lang_string('qrcodetype_desc', 'tool_mobile'), tool_mobile\api::QR_CODE_LOGIN, $options));
|
||||
|
||||
$temp->add(new admin_setting_configtext('tool_mobile/forcedurlscheme',
|
||||
new lang_string('forcedurlscheme_key', 'tool_mobile'),
|
||||
new lang_string('forcedurlscheme', 'tool_mobile'), 'moodlemobile', PARAM_NOTAGS));
|
||||
|
||||
@@ -600,4 +600,129 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
|
||||
$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() {
|
||||
global $DB, $CFG, $USER;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
$qrloginkey = api::get_qrlogin_key();
|
||||
|
||||
// Generate new tokens, the ones we expect to receive.
|
||||
$service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
|
||||
$token = external_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 missing QR code enabled.
|
||||
*/
|
||||
public function test_get_tokens_for_qr_login_missing_enableqr() {
|
||||
global $CFG, $USER;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
set_config('qrcodetype', tool_mobile\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() {
|
||||
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() {
|
||||
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() {
|
||||
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() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
$plugin->version = 2019111800; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2019111801; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2019111200; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_mobile'; // Full name of the plugin (used for diagnostics).
|
||||
$plugin->dependencies = array(
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Class for generating QR codes. Wrapper class that extends TCPDF.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2020 Moodle Pty Ltd.
|
||||
* @author Juan Leyva <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/tcpdf/tcpdf_barcodes_2d.php');
|
||||
|
||||
/**
|
||||
* Class for generating QR codes. Wrapper class that extends TCPDF.
|
||||
*
|
||||
* @copyright 2020 Moodle Pty Ltd.
|
||||
*/
|
||||
class core_qrcode extends TCPDF2DBarcode {
|
||||
|
||||
/**
|
||||
* Overrided constructor to force QR codes.
|
||||
*
|
||||
* @param string $data the data to generate the code
|
||||
*/
|
||||
public function __construct($data) {
|
||||
|
||||
parent::__construct($data, 'QRCODE');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Test QR code functionality.
|
||||
*
|
||||
* @package core
|
||||
* @copyright Moodle Pty Ltd
|
||||
* @author <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A set of tests for some of the QR code functionality within Moodle.
|
||||
*
|
||||
* @package core
|
||||
* @copyright Moodle Pty Ltd
|
||||
* @author <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_qrcode_testcase extends basic_testcase {
|
||||
|
||||
/**
|
||||
* Basic test to generate a QR code and check that the library is not broken.
|
||||
*/
|
||||
public function test_generate_basic_qr() {
|
||||
// The QR code generator library apply masks by random order, this is why everytime a QR code is generated the resultant
|
||||
// binary file can be different. This is why tests are limited.
|
||||
|
||||
$text = 'abc';
|
||||
$color = 'black';
|
||||
$qrcode = new core_qrcode($text, $color);
|
||||
$svgdata = $qrcode->getBarcodeSVGcode(1, 1);
|
||||
|
||||
// Just check the SVG was generated.
|
||||
$this->assertContains('<desc>' . $text . '</desc>', $svgdata);
|
||||
$this->assertContains('fill="' . $color . '"', $svgdata);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user