Merge branch 'MDL-61423-master' of git://github.com/mihailges/moodle

This commit is contained in:
Andrew Nicols 2018-03-08 15:26:30 +08:00
commit 1e9016d8d8
25 changed files with 1189 additions and 1 deletions

View File

@ -123,6 +123,43 @@ if ($hassiteconfig) {
$temp->add($setting);
$ADMIN->add('authsettings', $temp);
$options = array(
0 => get_string('no'),
1 => get_string('yes')
);
$url = new moodle_url('/admin/settings.php?section=supportcontact');
$url = $url->out();
$setting = new admin_setting_configselect('agedigitalconsentverification',
new lang_string('agedigitalconsentverification', 'admin'),
new lang_string('agedigitalconsentverification_desc', 'admin', $url), 0, $options);
$setting->set_force_ltr(true);
$temp->add($setting);
$setting = new admin_setting_agedigitalconsentmap('agedigitalconsentmap',
new lang_string('ageofdigitalconsentmap', 'admin'),
new lang_string('ageofdigitalconsentmap_desc', 'admin'),
// See {@link https://gdpr-info.eu/art-8-gdpr/}.
implode(PHP_EOL, [
'*, 16',
'AT, 14',
'CZ, 13',
'DE, 14',
'DK, 13',
'ES, 13',
'FI, 15',
'GB, 13',
'HU, 14',
'IE, 13',
'LT, 16',
'LU, 16',
'NL, 16',
'PL, 13',
'SE, 13',
]),
PARAM_RAW
);
$temp->add($setting);
$temp = new admin_externalpage('authtestsettings', get_string('testsettings', 'core_auth'), new moodle_url("/auth/test_settings.php"), 'moodle/site:config', true);
$ADMIN->add('authsettings', $temp);

View File

@ -0,0 +1,106 @@
<?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/>.
/**
* Contains helper class for digital consent.
*
* @package core_auth
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_auth;
defined('MOODLE_INTERNAL') || die();
/**
* Helper class for digital consent.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class digital_consent {
/**
* Returns true if age and location verification is enabled in the site.
*
* @return bool
*/
public static function is_age_digital_consent_verification_enabled() {
global $CFG;
return !empty($CFG->agedigitalconsentverification);
}
/**
* Checks if a user is a digital minor.
*
* @param int $age
* @param string $country The country code (ISO 3166-2)
* @return bool
*/
public static function is_minor($age, $country) {
global $CFG;
$ageconsentmap = $CFG->agedigitalconsentmap;
$agedigitalconsentmap = self::parse_age_digital_consent_map($ageconsentmap);
return array_key_exists($country, $agedigitalconsentmap) ?
$age < $agedigitalconsentmap[$country] : $age < $agedigitalconsentmap['*'];
}
/**
* Parse the agedigitalconsentmap setting into an array.
*
* @param string $ageconsentmap The value of the agedigitalconsentmap setting
* @return array $ageconsentmapparsed
*/
public static function parse_age_digital_consent_map($ageconsentmap) {
$ageconsentmapparsed = array();
$countries = get_string_manager()->get_list_of_countries();
$isdefaultvaluepresent = false;
$lines = preg_split('/\r|\n/', $ageconsentmap, -1, PREG_SPLIT_NO_EMPTY);
foreach ($lines as $line) {
$arr = explode(",", $line);
// Handle if there is more or less than one comma separator.
if (count($arr) != 2) {
throw new \moodle_exception('agedigitalconsentmapinvalidcomma', 'error', '', $line);
}
$country = trim($arr[0]);
$age = trim($arr[1]);
// Check if default.
if ($country == "*") {
$isdefaultvaluepresent = true;
}
// Handle if the presented value for country is not valid.
if ($country !== "*" && !array_key_exists($country, $countries)) {
throw new \moodle_exception('agedigitalconsentmapinvalidcountry', 'error', '', $country);
}
// Handle if the presented value for age is not valid.
if (!is_numeric($age)) {
throw new \moodle_exception('agedigitalconsentmapinvalidage', 'error', '', $age);
}
$ageconsentmapparsed[$country] = $age;
}
// Handle if a default value does not exist.
if (!$isdefaultvaluepresent) {
throw new \moodle_exception('agedigitalconsentmapinvaliddefault');
}
return $ageconsentmapparsed;
}
}

View File

@ -215,4 +215,76 @@ class core_auth_external extends external_api {
)
);
}
/**
* Describes the parameters for the digital minor check.
*
* @return external_function_parameters
* @since Moodle 3.4
*/
public static function is_minor_parameters() {
return new external_function_parameters(
array(
'age' => new external_value(PARAM_INT, 'Age'),
'country' => new external_value(PARAM_ALPHA, 'Country of residence'),
)
);
}
/**
* Requests a check if a user is digital minor.
*
* @param int $age User age
* @param string $country Country of residence
* @return array status (true if the user is a minor, false otherwise)
* @since Moodle 3.4
* @throws moodle_exception
*/
public static function is_minor($age, $country) {
global $CFG, $PAGE;
require_once($CFG->dirroot . '/login/lib.php');
$params = self::validate_parameters(
self::is_minor_parameters(),
array(
'age' => $age,
'country' => $country,
)
);
if (!array_key_exists($params['country'], get_string_manager()->get_list_of_countries())) {
throw new invalid_parameter_exception('Invalid value for country parameter (value: '.
$params['country'] .')');
}
$context = context_system::instance();
$PAGE->set_context($context);
// Check if verification of age and location (minor check) is enabled.
if (!\core_auth\digital_consent::is_age_digital_consent_verification_enabled()) {
throw new moodle_exception('nopermissions', 'error', '',
get_string('agelocationverificationdisabled', 'error'));
}
$status = \core_auth\digital_consent::is_minor($params['age'], $params['country']);
return array(
'status' => $status
);
}
/**
* Describes the is_minor return value.
*
* @return external_single_structure
* @since Moodle 3.4
*/
public static function is_minor_returns() {
return new external_single_structure(
array(
'status' => new external_value(PARAM_BOOL, 'True if the user is considered to be a digital minor,
false if not')
)
);
}
}

View File

@ -0,0 +1,62 @@
<?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/>.
/**
* Age and location verification mform.
*
* @package core_auth
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_auth\form;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/formslib.php');
use moodleform;
/**
* Age and location verification mform class.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class verify_age_location_form extends moodleform {
/**
* Defines the form fields.
*/
public function definition() {
global $CFG;
$mform = $this->_form;
$mform->addElement('text', 'age', get_string('whatisyourage'), array('optional' => false));
$mform->setType('age', PARAM_RAW);
$mform->addRule('age', null, 'required', null, 'client');
$mform->addRule('age', null, 'numeric', null, 'client');
$countries = get_string_manager()->get_list_of_countries();
$defaultcountry[''] = get_string('selectacountry');
$countries = array_merge($defaultcountry, $countries);
$mform->addElement('select', 'country', get_string('wheredoyoulive'), $countries);
$mform->addRule('country', null, 'required', null, 'client');
$mform->setDefault('country', $CFG->country);
$this->add_action_buttons(true, get_string('proceed'));
}
}

View File

@ -0,0 +1,63 @@
<?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/>.
/**
* Digital minor renderable.
*
* @package core_auth
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_auth\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
/**
* Digital minor renderable class.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class digital_minor_page implements renderable, templatable {
/**
* Export the page data for the mustache template.
*
* @param renderer_base $output renderer to be used to render the page elements.
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $SITE, $CFG;
$sitename = format_string($SITE->fullname);
$supportname = $CFG->supportname;
$supportemail = $CFG->supportemail;
$context = [
'sitename' => $sitename,
'supportname' => $supportname,
'supportemail' => $supportemail,
'homelink' => new \moodle_url('/')
];
return $context;
}
}

View File

@ -0,0 +1,81 @@
<?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/>.
/**
* Age and location verification renderable.
*
* @package core_auth
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_auth\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
require_once($CFG->libdir.'/formslib.php');
/**
* Age and location verification renderable class.
*
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class verify_age_location_page implements renderable, templatable {
/** @var mform The form object */
protected $form;
/** @var string Error message */
protected $errormessage;
/**
* Constructor
*
* @param mform $form The form object
* @param string $errormessage The error message.
*/
public function __construct($form, $errormessage = null) {
$this->form = $form;
$this->errormessage = $errormessage;
}
/**
* Export the page data for the mustache template.
*
* @param renderer_base $output renderer to be used to render the page elements.
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $SITE;
$sitename = format_string($SITE->fullname);
$formhtml = $this->form->render();
$error = $this->errormessage;
$context = [
'sitename' => $sitename,
'formhtml' => $formhtml,
'error' => $error
];
return $context;
}
}

View File

@ -0,0 +1,68 @@
@core @verify_age_location
Feature: Test validation of 'Age of digital consent' setting.
In order to set the 'Age of digital consent' setting
As an admin
I need to provide valid data and valid format
Background:
Given I log in as "admin"
And I navigate to "Manage authentication" node in "Site administration > Plugins > Authentication"
Scenario: Admin provides valid value for 'Age of digital consent'.
Given I set the field "s__agedigitalconsentmap" to multiline:
"""
*, 16
AT, 14
BE, 14
"""
When I press "Save changes"
Then I should see "Changes saved"
And I should not see "Some settings were not changed due to an error."
And I should not see "The digital age of consent is not valid:"
Scenario: Admin provides invalid format for 'Age of digital consent'.
# Try to set a value with missing space separator
Given I set the field "s__agedigitalconsentmap" to multiline:
"""
*16
AT, 14
BE, 14
"""
When I press "Save changes"
Then I should not see "Changes saved"
And I should see "Some settings were not changed due to an error."
And I should see "The digital age of consent is not valid: \"*16\" has more or less than one comma separator."
# Try to set a value with missing default age of consent
When I set the field "s__agedigitalconsentmap" to multiline:
"""
AT, 14
BE, 14
"""
And I press "Save changes"
Then I should not see "Changes saved"
And I should see "Some settings were not changed due to an error."
And I should see "The digital age of consent is not valid: Default (*) value is missing."
Scenario: Admin provides invalid age of consent or country for 'Age of digital consent'.
# Try to set a value containing invalid age of consent
Given I set the field "s__agedigitalconsentmap" to multiline:
"""
*, 16
AT, age
BE, 14
"""
When I press "Save changes"
Then I should not see "Changes saved"
And I should see "Some settings were not changed due to an error."
And I should see "The digital age of consent is not valid: \"age\" is not a valid value for age."
# Try to set a value containing invalid country
When I set the field "s__agedigitalconsentmap" to multiline:
"""
*, 16
COUNTRY, 14
BE, 14
"""
And I press "Save changes"
Then I should not see "Changes saved"
And I should see "Some settings were not changed due to an error."
And I should see "The digital age of consent is not valid: \"COUNTRY\" is not a valid value for country."

View File

@ -0,0 +1,45 @@
@core @verify_age_location
Feature: Test the 'Digital age of consent verification' feature works.
In order to self-register on the site
As an user
I need be to be over the age of digital consent
Background:
Given the following config values are set as admin:
| registerauth | email |
| agedigitalconsentverification | 1 |
Scenario: User that is not considered a digital minor attempts to self-register on the site.
# Try to access the sign up page.
Given I am on homepage
When I click on "Log in" "link" in the ".logininfo" "css_element"
And I press "Create new account"
Then I should see "Age and location verification"
When I set the field "What is your age?" to "16"
And I set the field "In which country do you live?" to "DZ"
And I press "Proceed"
Then I should see "New account"
And I should see "Choose your username and password"
# Try to access the sign up page again.
When I press "Cancel"
And I press "Create new account"
Then I should see "New account"
And I should see "Choose your username and password"
Scenario: User that is considered a digital minor attempts to self-register on the site.
# Try to access the sign up page.
Given I am on homepage
When I click on "Log in" "link" in the ".logininfo" "css_element"
And I press "Create new account"
Then I should see "Age and location verification"
When I set the field "What is your age?" to "12"
And I set the field "In which country do you live?" to "AT"
And I press "Proceed"
Then I should see "You are considered to be a digital minor."
And I should see "To create an account on this site please have your parent/guardian contact the following person."
# Try to access the sign up page again.
When I click on "Back to the site home" "link"
And I click on "Log in" "link" in the ".logininfo" "css_element"
And I press "Create new account"
Then I should see "You are considered to be a digital minor."
And I should see "To create an account on this site please have your parent/guardian contact the following person."

View File

@ -0,0 +1,182 @@
<?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/>.
/**
* Unit tests for core_auth\digital_consent.
*
* @package core_auth
* @copyright 2018 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Digital consent helper testcase.
*
* @package core_auth
* @copyright 2018 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_auth_digital_consent_testcase extends advanced_testcase {
public function test_is_age_digital_consent_verification_enabled() {
global $CFG;
$this->resetAfterTest();
// Age of digital consent verification is enabled.
$CFG->agedigitalconsentverification = 0;
$isenabled = \core_auth\digital_consent::is_age_digital_consent_verification_enabled();
$this->assertFalse($isenabled);
}
public function test_is_minor() {
global $CFG;
$this->resetAfterTest();
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'AT, 14',
'CZ, 13',
'DE, 14',
'DK, 13',
]);
$CFG->agedigitalconsentmap = $agedigitalconsentmap;
$usercountry1 = 'DK';
$usercountry2 = 'AU';
$userage1 = 12;
$userage2 = 14;
$userage3 = 16;
// Test country exists in agedigitalconsentmap and user age is below the particular digital minor age.
$isminor = \core_auth\digital_consent::is_minor($userage1, $usercountry1);
$this->assertTrue($isminor);
// Test country exists in agedigitalconsentmap and user age is above the particular digital minor age.
$isminor = \core_auth\digital_consent::is_minor($userage2, $usercountry1);
$this->assertFalse($isminor);
// Test country does not exists in agedigitalconsentmap and user age is below the particular digital minor age.
$isminor = \core_auth\digital_consent::is_minor($userage2, $usercountry2);
$this->assertTrue($isminor);
// Test country does not exists in agedigitalconsentmap and user age is above the particular digital minor age.
$isminor = \core_auth\digital_consent::is_minor($userage3, $usercountry2);
$this->assertFalse($isminor);
}
public function test_parse_age_digital_consent_map_valid_format() {
// Value of agedigitalconsentmap has a valid format.
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'AT, 14',
'BE, 13'
]);
$ageconsentmapparsed = \core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
$this->assertEquals([
'*' => 16,
'AT' => 14,
'BE' => 13
], $ageconsentmapparsed
);
}
public function test_parse_age_digital_consent_map_invalid_format_missing_spaces() {
// Value of agedigitalconsentmap has an invalid format (missing space separator between values).
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'AT14',
]);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('agedigitalconsentmapinvalidcomma', 'error', 'AT14'));
\core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
}
public function test_parse_age_digital_consent_map_invalid_format_missing_default_value() {
// Value of agedigitalconsentmap has an invalid format (missing default value).
$agedigitalconsentmap = implode(PHP_EOL, [
'BE, 16',
'AT, 14'
]);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('agedigitalconsentmapinvaliddefault', 'error'));
\core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
}
public function test_parse_age_digital_consent_map_invalid_format_invalid_country() {
// Value of agedigitalconsentmap has an invalid format (invalid value for country).
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'TEST, 14'
]);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('agedigitalconsentmapinvalidcountry', 'error', 'TEST'));
\core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
}
public function test_parse_age_digital_consent_map_invalid_format_invalid_age_string() {
// Value of agedigitalconsentmap has an invalid format (string value for age).
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'AT, ten'
]);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('agedigitalconsentmapinvalidage', 'error', 'ten'));
\core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
}
public function test_parse_age_digital_consent_map_invalid_format_missing_age() {
// Value of agedigitalconsentmap has an invalid format (missing value for age).
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'AT, '
]);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('agedigitalconsentmapinvalidage', 'error', ''));
\core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
}
public function test_parse_age_digital_consent_map_invalid_format_missing_country() {
// Value of agedigitalconsentmap has an invalid format (missing value for country).
$agedigitalconsentmap = implode(PHP_EOL, [
'*, 16',
', 12'
]);
$this->expectException('moodle_exception');
$this->expectExceptionMessage(get_string('agedigitalconsentmapinvalidcountry', 'error', ''));
\core_auth\digital_consent::parse_age_digital_consent_map($agedigitalconsentmap);
}
}

View File

@ -39,6 +39,10 @@ $string['adminseesall'] = 'Admins see all';
$string['adminseesallevents'] = 'Administrators see all events';
$string['adminseesownevents'] = 'Administrators are just like other users';
$string['advancedfeatures'] = 'Advanced features';
$string['agedigitalconsentverification'] = 'Digital age of consent verification';
$string['agedigitalconsentverification_desc'] = 'Enables verification of the digital age of consent before displaying the sign-up page for self-registration users. This protects your site from minors signing up without parental/guardian consent. <a target="_blank" href="{$a}">Support contact</a> details are provided to minors for further assistance.';
$string['ageofdigitalconsentmap'] = 'Digital age of consent';
$string['ageofdigitalconsentmap_desc'] = 'The default digital age of consent, and the age in any country where it differs from the default, may be specified here. Enter each age on a new line with format: country code, age (separated by a comma). The default age is indicated by * in place of the country code. Country codes are as specified in ISO 3166-2.';
$string['allcountrycodes'] = 'All country codes';
$string['allowattachments'] = 'Allow attachments';
$string['allowbeforeblock'] = 'Allowed list will be processed first';
@ -617,6 +621,7 @@ $string['installhijacked'] = 'Installation must be finished from the original IP
$string['installsessionerror'] = 'Can not initialise PHP session, please verify that your browser accepts cookies.';
$string['intlrecommended'] = 'Intl extension is used to improve internationalization support, such as locale aware sorting.';
$string['intlrequired'] = 'Intl extension is required to improve internationalization support, such as locale aware sorting and international domain names.';
$string['invalidagedigitalconsent'] = 'The digital age of consent is not valid: {$a}';
$string['invalidforgottenpasswordurl'] = 'The forgotten password URL is not a valid URL.';
$string['invalidsection'] = 'Invalid section.';
$string['invaliduserchangeme'] = 'Username "changeme" is reserved -- you cannot create an account with it.';

View File

@ -62,6 +62,7 @@ $string['cachedef_navigation_expandcourse'] = 'Navigation expandable courses';
$string['cachedef_observers'] = 'Event observers';
$string['cachedef_plugin_functions'] = 'Plugins available callbacks';
$string['cachedef_plugin_manager'] = 'Plugin info manager';
$string['cachedef_presignup'] = 'Pre sign-up data for particular unregistered user';
$string['cachedef_postprocessedcss'] = 'Post processed CSS';
$string['cachedef_tagindexbuilder'] = 'Search results for tagged items';
$string['cachedef_questiondata'] = 'Question definitions';

View File

@ -23,6 +23,11 @@
*/
$string['activityisscheduledfordeletion'] = 'Activity deletion in progress...';
$string['agedigitalconsentmapinvalidage'] = '"{$a}" is not a valid value for age.';
$string['agedigitalconsentmapinvalidcomma'] = '"{$a}" has more or less than one comma separator.';
$string['agedigitalconsentmapinvalidcountry'] = '"{$a}" is not a valid value for country.';
$string['agedigitalconsentmapinvaliddefault'] = 'Default (*) value is missing.';
$string['agelocationverificationdisabled'] = 'Age and location verification disabled';
$string['authnotexisting'] = 'The autorization plugin doesn\'t exist';
$string['backupcontainexternal'] = 'This backup file contains external Moodle Network Hosts that are not configured locally';
$string['backuptablefail'] = 'Backup tables could NOT be set up successfully!';
@ -177,6 +182,7 @@ $string['confirmationnotenabled'] = 'User confirmation is not enabled on this si
$string['confirmsesskeybad'] = 'Sorry, but your session key could not be confirmed to carry out this action. This security feature prevents against accidental or malicious execution of important functions in your name. Please make sure you really wanted to execute this function.';
$string['couldnotassignrole'] = 'A serious but unspecified error occurred while trying to assign a role to you';
$string['couldnotupdatenoexistinguser'] = 'Cannot update the user - user doesn\'t exist';
$string['couldnotverifyagedigitalconsent'] = 'An error occurred while trying to verify the age of digital consent.<br />Please contact administrator.';
$string['countriesphpempty'] = 'Error: The file countries.php in language pack {$a} is empty or missing.';
$string['coursedoesnotbelongtocategory'] = 'The course doesn\'t belong to this category';
$string['courseformatnotfound'] = 'The course format \'{$a}\' doesn\'t exist or is not recognized';
@ -578,6 +584,7 @@ $string['usernotupdatederror'] = 'User not updated - error';
$string['usernotupdatednotexists'] = 'User not updated - does not exist';
$string['userquotalimit'] = 'You have reached your file quota limit.';
$string['userselectortoomany'] = 'user_selector got more than one selected user, even though multiselect is false.';
$string['verifyagedigitalconsentnotpossible'] = 'Sorry, digital age consent verification is not possible at this time.';
$string['wrongcall'] = 'This script is called wrongly';
$string['wrongcontextid'] = 'Context ID was incorrect (cannot find it)';
$string['wrongdestpath'] = 'Wrong destination path';

View File

@ -119,6 +119,7 @@ $string['advancedsettings'] = 'Advanced settings';
$string['afterresource'] = 'After resource "{$a}"';
$string['aftersection'] = 'After section "{$a}"';
$string['again'] = 'again';
$string['agelocationverification'] = 'Age and location verification';
$string['aimid'] = 'AIM ID';
$string['ajaxuse'] = 'AJAX and Javascript';
$string['all'] = 'All';
@ -170,6 +171,7 @@ $string['availablecourses'] = 'Available courses';
$string['back'] = 'Back';
$string['backto'] = 'Back to {$a}';
$string['backtocourselisting'] = 'Back to course listing';
$string['backtohome'] = 'Back to the site home';
$string['backtopageyouwereon'] = 'Back to the page you were on';
$string['backtoparticipants'] = 'Back to participants list';
$string['backup'] = 'Backup';
@ -267,6 +269,7 @@ $string['confirmed'] = 'Your registration has been confirmed';
$string['confirmednot'] = 'Your registration has not yet been confirmed!';
$string['confirmcheckfull'] = 'Are you absolutely sure you want to confirm {$a} ?';
$string['confirmcoursemove'] = 'Are you sure you want to move this course ({$a->course}) into this category ({$a->category})?';
$string['considereddigitalminor'] = 'You are considered to be a digital minor.';
$string['content'] = 'Content';
$string['continue'] = 'Continue';
$string['continuetocourse'] = 'Click here to enter your course';
@ -498,6 +501,8 @@ $string['description'] = 'Description';
$string['deselectall'] = 'Deselect all';
$string['detailedless'] = 'Less detailed';
$string['detailedmore'] = 'More detailed';
$string['digitalminor'] = 'Digital minor';
$string['digitalminor_desc'] = 'To create an account on this site please have your parent/guardian contact the following person.';
$string['directory'] = 'Directory';
$string['disable'] = 'Disable';
$string['disabledcomments'] = 'Comments are disabled';
@ -794,6 +799,7 @@ $string['expand'] = 'Expand';
$string['expandall'] = 'Expand all';
$string['expandcategory'] = 'Expand {$a}';
$string['explanation'] = 'Explanation';
$string['explanationdigitalminor'] = 'This information is required to determine if your age is over the digital age of consent. This is the age when an individual can consent to terms and conditions and their data being legally stored and processed.';
$string['extendperiod'] = 'Extended period';
$string['failedloginattempts'] = '{$a->attempts} failed logins since your last login';
$string['feedback'] = 'Feedback';
@ -1547,6 +1553,7 @@ $string['primaryadminsetup'] = 'Setup administrator account';
$string['privatefiles'] = 'Private files';
$string['private_files_handler'] = 'Store attachments to an e-mail in the user\'s private files storage space.';
$string['private_files_handler_name'] = 'Email to Private files';
$string['proceed'] = 'Proceed';
$string['profile'] = 'Profile';
$string['profilenotshown'] = 'This profile description will not be shown until this person is enrolled in at least one course.';
$string['publicprofile'] = 'Public profile';
@ -2102,8 +2109,11 @@ If you have not done so already, you should edit your profile page so that we ca
{$a->profileurl}';
$string['whatforlink'] = 'What do you want to do with the link?';
$string['whatforpage'] = 'What do you want to do with the text?';
$string['whatisyourage'] = 'What is your age?';
$string['whattocallzip'] = 'What do you want to call the zip file?';
$string['whattodo'] = 'What to do';
$string['wheredoyoulive'] = 'In which country do you live?';
$string['whyisthisrequired'] = 'Why is this required?';
$string['windowclosing'] = 'This window should close automatically. If not, please close it now.';
$string['withchosenfiles'] = 'With chosen files';
$string['withdisablednote'] = '{$a} (disabled)';

View File

@ -10579,3 +10579,50 @@ class admin_setting_filetypes extends admin_setting_configtext {
return true;
}
}
/**
* Used to validate the content and format of the age of digital consent map and ensuring it is parsable.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
*/
class admin_setting_agedigitalconsentmap extends admin_setting_configtextarea {
/**
* Constructor.
*
* @param string $name
* @param string $visiblename
* @param string $description
* @param mixed $defaultsetting string or array
* @param mixed $paramtype
* @param string $cols
* @param string $rows
*/
public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype = PARAM_RAW,
$cols = '60', $rows = '8') {
parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
// Pre-set force LTR to false.
$this->set_force_ltr(false);
}
/**
* Validate the content and format of the age of digital consent map to ensure it is parsable.
*
* @param string $data The age of digital consent map from text field.
* @return mixed bool true for success or string:error on failure.
*/
public function validate($data) {
if (empty($data)) {
return true;
}
try {
\core_auth\digital_consent::parse_age_digital_consent_map($data);
} catch (\moodle_exception $e) {
return get_string('invalidagedigitalconsent', 'admin', $e->getMessage());
}
return true;
}
}

View File

@ -362,4 +362,14 @@ $definitions = array(
'simpledata' => true,
'staticacceleration' => true,
),
// This is the user's pre sign-up session cache.
// This cache is used to record the user's pre sign-up data such as
// age of digital consent (minor) status, accepted policies, etc.
'presignup' => array(
'mode' => cache_store::MODE_SESSION,
'simplekeys' => true,
'simpledata' => true,
'ttl' => 1800,
),
);

View File

@ -50,6 +50,13 @@ $functions = array(
'ajax' => true,
'loginrequired' => false,
),
'core_auth_is_minor' => array(
'classname' => 'core_auth_external',
'methodname' => 'is_minor',
'description' => 'Requests a check if a user is a digital minor.',
'type' => 'read',
'loginrequired' => false,
),
'core_badges_get_user_badges' => array(
'classname' => 'core_badges_external',
'methodname' => 'get_user_badges',

View File

@ -4451,6 +4451,30 @@ EOD;
return $this->render_from_template('core/signup_form_layout', $context);
}
/**
* Render the verify age and location page into a nice template for the theme.
*
* @param \core_auth\output\verify_age_location_page $page The renderable
* @return string
*/
protected function render_verify_age_location_page($page) {
$context = $page->export_for_template($this);
return $this->render_from_template('core/auth_verify_age_location_page', $context);
}
/**
* Render the digital minor contact information page into a nice template for the theme.
*
* @param \core_auth\output\digital_minor_page $page The renderable
* @return string
*/
protected function render_digital_minor_page($page) {
$context = $page->export_for_template($this);
return $this->render_from_template('core/auth_digital_minor_page', $context);
}
/**
* Renders a progress bar.
*

View File

@ -0,0 +1,37 @@
{{!
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/>.
}}
{{!
@template core_auth/output/digital_minor_page
Example context (json):
{
"logourl": "https://moodle.org/logo/moodle-logo.svg",
"sitename": "Site name",
"supportname": "John Doe",
"supportemail": "johndoe@example.com",
"homelink": "/"
}
}}
<h3>{{#str}}considereddigitalminor{{/str}}</h3>
<p class="m-b-0">{{#str}}digitalminor_desc{{/str}}</p>
<div class="p-t-1 p-b-1">
<p class="m-b-0">{{{supportname}}}</p>
<p class="m-b-0">{{{supportemail}}}</p>
</div>
<div class="backlink">
<a href="{{homelink}}">{{#str}}backtohome{{/str}}</a>
</div>

View File

@ -0,0 +1,37 @@
{{!
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/>.
}}
{{!
@template core_auth/output/verify_age_location_page
Example context (json):
{
"logourl": "https://moodle.org/logo/moodle-logo.svg",
"sitename": "Site name",
"error": "Error message",
"formhtml": "(Form html would go here)"
}
}}
{{#error}}
<div class="alert alert-danger" role="alert">
{{{error}}}
</div>
{{/error}}
<h3>{{#str}}agelocationverification{{/str}}</h3>
{{{formhtml}}}
<hr>
<h3>{{#str}}whyisthisrequired{{/str}}</h3>
<p >{{#str}}explanationdigitalminor{{/str}}</p>

64
login/digital_minor.php Normal file
View File

@ -0,0 +1,64 @@
<?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/>.
/**
* Display page to a digital minor. Display support contact details.
*
* @package core
* @subpackage auth
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require('../config.php');
require_once($CFG->libdir . '/authlib.php');
$authplugin = signup_is_enabled();
if (!$authplugin || !\core_auth\digital_consent::is_age_digital_consent_verification_enabled()) {
// Redirect user if signup or digital age of consent verification is disabled.
redirect(new moodle_url('/'), get_string('verifyagedigitalconsentnotpossible', 'error'));
}
$PAGE->set_context(context_system::instance());
$PAGE->set_url($CFG->wwwroot.'/login/digital_minor.php');
if (isloggedin() and !isguestuser()) {
// Prevent signing up when already logged in.
redirect(new moodle_url('/'), get_string('cannotsignup', 'error', fullname($USER)));
}
$cache = cache::make('core', 'presignup');
$isminor = $cache->get('isminor');
if ($isminor !== 'yes') {
// Redirect when the signup session does not exists, minor check has not been done or the user is not a minor.
redirect(new moodle_url('/login/index.php'));
}
$PAGE->navbar->add(get_string('login'));
$PAGE->navbar->add(get_string('digitalminor'));
$PAGE->set_pagelayout('login');
$PAGE->set_title(get_string('digitalminor'));
$sitename = format_string($SITE->fullname);
$PAGE->set_heading($sitename);
$page = new \core_auth\output\digital_minor_page();
echo $OUTPUT->header();
echo $OUTPUT->render($page);
echo $OUTPUT->footer();

View File

@ -60,6 +60,19 @@ if (isloggedin() and !isguestuser()) {
exit;
}
// If verification of age and location (digital minor check) is enabled.
if (\core_auth\digital_consent::is_age_digital_consent_verification_enabled()) {
$cache = cache::make('core', 'presignup');
$isminor = $cache->get('isminor');
if ($isminor === false) {
// The verification of age and location (minor) has not been done.
redirect(new moodle_url('/login/verify_age_location.php'));
} else if ($isminor === 'yes') {
// The user that attempts to sign up is a digital minor.
redirect(new moodle_url('/login/digital_minor.php'));
}
}
// Plugins can create pre sign up requests.
// Can be used to force additional actions before sign up such as acceptance of policies, validations, etc.
core_login_pre_signup_requests();

View File

@ -0,0 +1,88 @@
<?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/>.
/**
* Verify age and location (digital minor check).
*
* @package core
* @subpackage auth
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require('../config.php');
require_once($CFG->libdir . '/authlib.php');
$authplugin = signup_is_enabled();
if (!$authplugin || !\core_auth\digital_consent::is_age_digital_consent_verification_enabled()) {
// Redirect user if signup or digital age of consent verification is disabled.
redirect(new moodle_url('/'), get_string('verifyagedigitalconsentnotpossible', 'error'));
}
$PAGE->set_context(context_system::instance());
$PAGE->set_url(new moodle_url('/login/verify_age_location.php'));
if (isloggedin() and !isguestuser()) {
// Prevent signing up when already logged in.
redirect(new moodle_url('/'), get_string('cannotsignup', 'error', fullname($USER)));
}
$cache = cache::make('core', 'presignup');
$isminor = $cache->get('isminor');
if ($isminor === 'yes') {
// The user that attempts to sign up is a digital minor.
redirect(new moodle_url('/login/digital_minor.php'));
} else if ($isminor === 'no') {
// The user that attempts to sign up has already verified that they are not a digital minor.
redirect(new moodle_url('/login/signup.php'));
}
$PAGE->navbar->add(get_string('login'));
$PAGE->navbar->add(get_string('agelocationverification'));
$PAGE->set_pagelayout('login');
$PAGE->set_title(get_string('agelocationverification'));
$sitename = format_string($SITE->fullname);
$PAGE->set_heading($sitename);
$mform = new \core_auth\form\verify_age_location_form();
$page = new \core_auth\output\verify_age_location_page($mform);
if ($mform->is_cancelled()) {
redirect(new moodle_url('/login/index.php'));
} else if ($data = $mform->get_data()) {
try {
$isminor = \core_auth\digital_consent::is_minor($data->age, $data->country);
cache::make('core', 'presignup')->set('isminor', $isminor ? 'yes' : 'no');
if ($isminor) {
redirect(new moodle_url('/login/digital_minor.php'));
} else {
redirect(new moodle_url('/login/signup.php'));
}
} catch (moodle_exception $e) {
// Display a user-friendly error message.
$errormessage = get_string('couldnotverifyagedigitalconsent', 'error');
$page = new \core_auth\output\verify_age_location_page($mform, $errormessage);
echo $OUTPUT->header();
echo $OUTPUT->render($page);
echo $OUTPUT->footer();
}
} else {
echo $OUTPUT->header();
echo $OUTPUT->render($page);
echo $OUTPUT->footer();
}

View File

@ -0,0 +1,58 @@
{{!
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/>.
}}
{{!
@template core_auth/output/digital_minor_page
Example context (json):
{
"logourl": "https://moodle.org/logo/moodle-logo.svg",
"sitename": "Site name",
"supportname": "John Doe",
"supportemail": "johndoe@example.com",
"homelink": "/"
}
}}
<div class="container-fluid">
<div class="row">
<div class="col-md-8 push-md-2 col-xl-6 push-xl-3">
<div class="card">
<div class="card-block">
<div class="card-title text-xs-center">
{{#logourl}}
<h2><img src="{{logourl}}" title="{{sitename}}" alt="{{sitename}}"/></h2>
{{/logourl}}
{{^logourl}}
<h2>{{sitename}}</h2>
{{/logourl}}
<hr>
</div>
<div class="card-title">
<h3>{{#str}}considereddigitalminor{{/str}}</h3>
</div>
<div class="p-t-1 p-b-2">
<p>{{#str}}digitalminor_desc{{/str}}</p>
<p class="m-b-0">{{{supportname}}}</p>
<p class="m-b-0">{{{supportemail}}}</p>
</div>
<div class="backlink">
<a href="{{homelink}}">{{#str}}backtohome{{/str}}</a>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,64 @@
{{!
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/>.
}}
{{!
@template core_auth/output/verify_age_location_page
Example context (json):
{
"logourl": "https://moodle.org/logo/moodle-logo.svg",
"sitename": "Site name",
"error": "Error message",
"formhtml": "(Form html would go here)"
}
}}
<div class="container-fluid">
<div class="row">
<div class="col-md-8 push-md-2 col-xl-6 push-xl-3">
<div class="card">
<div class="card-block">
<div class="card-title text-xs-center">
{{#logourl}}
<h2><img src="{{logourl}}" title="{{sitename}}" alt="{{sitename}}"/></h2>
{{/logourl}}
{{^logourl}}
<h2>{{sitename}}</h2>
{{/logourl}}
<hr>
</div>
{{#error}}
<div class="alert alert-danger" role="alert">
{{{error}}}
</div>
{{/error}}
<div class="card-title">
<h3>{{#str}}agelocationverification{{/str}}</h3>
</div>
<div class="m-t-2 m-b-2">
{{{formhtml}}}
</div>
<hr>
<div class="card-title">
<h3>{{#str}}whyisthisrequired{{/str}}</h3>
</div>
<div class="m-t-1">
<p >{{#str}}explanationdigitalminor{{/str}}</p>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2018022800.03; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2018022800.04; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.