# Enable test external resources
sed -i \
-e "/require_once/i \\define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://127.0.0.1:8080');" \
+ -e "/require_once/i \\define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://127.0.0.1:8080');" \
config.php ;
+
# Redis cache store tests
sed -i \
-e "/require_once/i \\define('TEST_CACHESTORE_REDIS_TESTSERVERS', '127.0.0.1');" \
if [ "$TASK" = 'PHPUNIT' ];
then
vendor/bin/phpunit --fail-on-risky --disallow-test-output --verbose;
- EXTTESTS_HITS=$(docker logs exttests 2>&1 | grep -Fv -e 'AH00558' -e '[pid 1]' | wc -l)
- echo -e "\nTest local resources number of hits: ${EXTTESTS_HITS}.\n"
fi
- >
exit 1 ;
fi
fi
+
+after_script:
+ - >
+ if [ "$TASK" = 'PHPUNIT' ];
+ then
+ EXTTESTS_HITS=$(docker logs exttests 2>&1 | grep -Fv -e 'AH00558' -e '[pid 1]' | wc -l)
+ echo -e "\nTest local resources number of hits: ${EXTTESTS_HITS}.\n"
+ fi
'userid' => get_string('user', 'admin'),
'timestart' => get_string('task_starttime', 'admin'),
'duration' => get_string('task_duration', 'admin'),
+ 'hostname' => get_string('hostname', 'tool_task'),
+ 'pid' => get_string('pid', 'tool_task'),
'db' => get_string('task_dbstats', 'admin'),
'result' => get_string('task_result', 'admin'),
'actions' => '',
$sql = "SELECT
tl.id, tl.type, tl.component, tl.classname, tl.userid, tl.timestart, tl.timeend,
+ tl.hostname, tl.pid,
tl.dbreads, tl.dbwrites, tl.result,
tl.dbreads + tl.dbwrites AS db,
tl.timeend - tl.timestart AS duration,
'showsql' => false,
'showdebugging' => false,
'ignorelimits' => false,
+ 'force' => false,
], [
'h' => 'help',
'e' => 'execute',
'k' => 'keep-alive',
'i' => 'ignorelimits',
+ 'f' => 'force',
]
);
-e, --execute Run all queued adhoc tasks
-k, --keep-alive=N Keep this script alive for N seconds and poll for new adhoc tasks
-i --ignorelimits Ignore task_adhoc_concurrency_limit and task_adhoc_max_runtime limits
+ -f, --force Run even if cron is disabled
Example:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --execute
if (empty($options['execute'])) {
exit(0);
}
+
+if (!get_config('core', 'cron_enabled') && !$options['force']) {
+ mtrace('Cron is disabled. Use --force to override.');
+ exit(1);
+}
+
if (empty($options['keep-alive'])) {
$options['keep-alive'] = 0;
}
// now get cli options
list($options, $unrecognized) = cli_get_params(
- array(
+ [
'help' => false,
'stop' => false,
- ),
- array(
+ 'list' => false,
+ 'force' => false,
+ 'enable' => false,
+ 'disable' => false,
+ 'disable-wait' => false,
+ ], [
'h' => 'help',
's' => 'stop',
- )
+ 'l' => 'list',
+ 'f' => 'force',
+ 'e' => 'enable',
+ 'd' => 'disable',
+ 'w' => 'disable-wait',
+ ]
);
if ($unrecognized) {
"Execute periodic cron actions.
Options:
--h, --help Print out this help
--s, --stop Notify all other running cron processes to stop after the current task
+-h, --help Print out this help
+-s, --stop Notify all other running cron processes to stop after the current task
+-l, --list Show the list of currently running tasks and how long they have been running
+-f, --force Execute task even if cron is disabled
+-e, --enable Enable cron
+-d, --disable Disable cron
+-w, --disable-wait=600 Disable cron and wait until all tasks finished or fail after N seconds (optional param)
Example:
\$sudo -u www-data /usr/bin/php admin/cli/cron.php
die;
}
+if ($options['enable']) {
+ set_config('cron_enabled', 1);
+ mtrace('Cron has been enabled for the site.');
+ exit(0);
+}
+
+if ($options['disable']) {
+ set_config('cron_enabled', 0);
+ \core\task\manager::clear_static_caches();
+ mtrace('Cron has been disabled for the site.');
+ exit(0);
+}
+
+if ($options['list']) {
+ $tasks = \core\task\manager::get_running_tasks();
+ mtrace('The list of currently running tasks:');
+ $format = "%7s %-12s %-9s %-20s %-52s\n";
+ printf ($format,
+ 'PID',
+ 'HOST',
+ 'TYPE',
+ 'TIME',
+ 'CLASSNAME'
+ );
+ foreach ($tasks as $task) {
+ printf ($format,
+ $task->pid,
+ substr($task->hostname, 0, 12),
+ $task->type,
+ format_time(time() - $task->timestarted),
+ substr($task->classname, 0, 52)
+ );
+ }
+ exit(0);
+}
+
+if ($wait = $options['disable-wait']) {
+ $started = time();
+ if (true === $wait) {
+ // Default waiting time.
+ $waitsec = 600;
+ } else {
+ $waitsec = $wait;
+ $wait = true;
+ }
+
+ set_config('cron_enabled', 0);
+ \core\task\manager::clear_static_caches();
+ mtrace('Cron has been disabled for the site.');
+ mtrace('Allocating '. format_time($waitsec) . ' for the tasks to finish.');
+
+ $lastcount = 0;
+ while ($wait) {
+ $tasks = \core\task\manager::get_running_tasks();
+
+ if (count($tasks) == 0) {
+ mtrace('');
+ mtrace('All scheduled and adhoc tasks finished.');
+ exit(0);
+ }
+
+ if (time() - $started >= $waitsec) {
+ mtrace('');
+ mtrace('Wait time ('. format_time($waitsec) . ') elapsed, but ' . count($tasks) . ' task(s) still running.');
+ mtrace('Exiting with code 1.');
+ exit(1);
+ }
+
+ if (count($tasks) !== $lastcount) {
+ mtrace('');
+ mtrace(count($tasks) . " tasks currently running.", '');
+ $lastcount = count($tasks);
+ } else {
+ mtrace('.', '');
+ }
+
+ sleep(1);
+ }
+}
+
+if (!get_config('core', 'cron_enabled') && !$options['force']) {
+ mtrace('Cron is disabled. Use --force to override.');
+ exit(1);
+}
+
\core\local\cli\shutdown::script_supports_graceful_exit();
cron_run();
--- /dev/null
+<?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/>.
+
+/**
+ * This script allows to restore a course from CLI.
+ *
+ * @package core
+ * @subpackage cli
+ * @copyright 2020 Catalyst IT
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', 1);
+
+require(__DIR__ . '/../../config.php');
+require_once($CFG->libdir . '/clilib.php');
+require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
+
+list($options, $unrecognized) = cli_get_params([
+ 'file' => '',
+ 'categoryid' => '',
+ 'showdebugging' => false,
+ 'help' => false,
+], [
+ 'f' => 'file',
+ 'c' => 'categoryid',
+ 's' => 'showdebugging',
+ 'h' => 'help',
+]);
+
+if ($unrecognized) {
+ $unrecognized = implode("\n ", $unrecognized);
+ cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+if ($options['help'] || !($options['file']) || !($options['categoryid'])) {
+ $help = <<<EOL
+Restore backup into provided category.
+
+Options:
+-f, --file=STRING Path to the backup file.
+-c, --categoryid=INT ID of the category to restore too.
+-s, --showdebugging Show developer level debugging information
+-h, --help Print out this help.
+
+Example:
+\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/file.mbz --categoryid=1\n
+EOL;
+
+ echo $help;
+ exit(0);
+}
+
+if ($options['showdebugging']) {
+ set_debugging(DEBUG_DEVELOPER, true);
+}
+
+if (!$admin = get_admin()) {
+ print_error('noadmins');
+}
+
+if (!file_exists($options['file'])) {
+ print_error('filenotfound');
+}
+
+if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
+ print_error('invalidcategoryid');
+}
+
+$backupdir = "restore_" . uniqid();
+$path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir;
+
+cli_heading(get_string('extractingbackupfileto', 'backup', $path));
+$fp = get_file_packer('application/vnd.moodle.backup');
+$fp->extract_to_pathname($options['file'], $path);
+
+cli_heading(get_string('preprocessingbackupfile'));
+try {
+ list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
+ get_string('restoringcourseshortname', 'backup'));
+
+ $courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
+
+ $rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
+ backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
+ $rc->execute_precheck();
+ $rc->execute_plan();
+ $rc->destroy();
+} catch (Exception $e) {
+ cli_heading(get_string('cleaningtempdata'));
+ fulldelete($path);
+ print_error('generalexceptionmessage', 'error', '', $e->getMessage());
+}
+
+cli_heading(get_string('restoredcourseid', 'backup', $courseid));
+exit(0);
require_once("$CFG->libdir/cronlib.php");
list($options, $unrecognized) = cli_get_params(
- array('help' => false, 'list' => false, 'execute' => false, 'showsql' => false, 'showdebugging' => false),
- array('h' => 'help')
+ [
+ 'help' => false,
+ 'list' => false,
+ 'execute' => false,
+ 'showsql' => false,
+ 'showdebugging' => false,
+ 'force' => false,
+ ], [
+ 'h' => 'help',
+ 'f' => 'force',
+ ]
);
if ($unrecognized) {
--showsql Show sql queries before they are executed
--showdebugging Show developer level debugging information
-h, --help Print out this help
+ -f, --force Execute task even if cron is disabled
Example:
\$sudo -u www-data /usr/bin/php admin/cli/scheduled_task.php --execute=\\core\\task\\session_cleanup_task
exit(1);
}
+ if (!get_config('core', 'cron_enabled') && !$options['force']) {
+ mtrace('Cron is disabled. Use --force to override.');
+ exit(1);
+ }
+
+ \core\task\manager::scheduled_task_starting($task);
+
// Increase memory limit.
raise_memory_limit(MEMORY_EXTRA);
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
+ <MOODLE version="3.10" requires="3.5">
+ <UNICODE level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unicoderequired" />
+ </FEEDBACK>
+ </UNICODE>
+ <DATABASE level="required">
+ <VENDOR name="mariadb" version="10.2.29" />
+ <VENDOR name="mysql" version="5.7" />
+ <VENDOR name="postgres" version="9.6" />
+ <VENDOR name="mssql" version="11.0" />
+ <VENDOR name="oracle" version="11.2" />
+ </DATABASE>
+ <PHP version="7.2.0" level="required">
+ </PHP>
+ <PCREUNICODE level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="pcreunicodewarning" />
+ </FEEDBACK>
+ </PCREUNICODE>
+ <PHP_EXTENSIONS>
+ <PHP_EXTENSION name="iconv" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="iconvrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="mbstring" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="mbstringrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="curl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="curlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="openssl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="opensslrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="tokenizer" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="tokenizerrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xmlrpc" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="xmlrpcrecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="soap" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="soaprecommended" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="ctype" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="ctyperequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="zip" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="ziprequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="zlib" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="gd" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="gdrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="simplexml" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="simplexmlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="spl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="splrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="pcre" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="dom" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xml" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="xmlreader" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="intl" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="intlrequired" />
+ </FEEDBACK>
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="json" level="required">
+ </PHP_EXTENSION>
+ <PHP_EXTENSION name="hash" level="required"/>
+ <PHP_EXTENSION name="fileinfo" level="required"/>
+ </PHP_EXTENSIONS>
+ <PHP_SETTINGS>
+ <PHP_SETTING name="memory_limit" value="96M" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="settingmemorylimit" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ <PHP_SETTING name="file_uploads" value="1" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="settingfileuploads" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ <PHP_SETTING name="opcache.enable" value="1" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="opcacherecommended" />
+ </FEEDBACK>
+ </PHP_SETTING>
+ </PHP_SETTINGS>
+ <CUSTOM_CHECKS>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddbstorageengine" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="quizattemptsupgradedmessage" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="slashargumentswarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="unsupporteddbtablerowformat" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="unoconvwarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="libcurlwarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddbfileformat" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddbfilepertable" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
+ <FEEDBACK>
+ <ON_ERROR message="unsupporteddblargeprefix" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="ishttpswarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="incompleteunicodesupport" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ <CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
+ <FEEDBACK>
+ <ON_CHECK message="sixtyfourbitswarning" />
+ </FEEDBACK>
+ </CUSTOM_CHECK>
+ </CUSTOM_CHECKS>
+ </MOODLE>
</COMPATIBILITY_MATRIX>
// Add a category for the Activity Chooser.
$ADMIN->add('courses', new admin_category('activitychooser', new lang_string('activitychoosercategory', 'course')));
$temp = new admin_settingpage('activitychoosersettings', new lang_string('activitychoosersettings', 'course'));
+ // Tab mode for the activity chooser.
$temp->add(
new admin_setting_configselect(
'activitychoosertabmode',
]
)
);
+
+ // Build a list of plugins that use the footer callback.
+ $pluginswithfunction = get_plugins_with_function('custom_chooser_footer', 'lib.php');
+ $pluginsoptions = [];
+ $pluginsoptions[COURSE_CHOOSER_FOOTER_NONE] = get_string('activitychooserhidefooter', 'course');
+ if ($pluginswithfunction) {
+ foreach ($pluginswithfunction as $plugintype => $plugins) {
+ foreach ($plugins as $pluginname => $pluginfunction) {
+ $plugin = $plugintype.'_'.$pluginname;
+ $pluginsoptions[$plugin] = get_string('pluginname', $plugin);
+ }
+ }
+ }
+
+ // Select what plugin to show in the footer.
+ $temp->add(
+ new admin_setting_configselect(
+ 'activitychooseractivefooter',
+ new lang_string('activitychooseractivefooter', 'course'),
+ new lang_string('activitychooseractivefooter_desc', 'course'),
+ COURSE_CHOOSER_FOOTER_NONE,
+ $pluginsoptions
+ )
+ );
+
$ADMIN->add('activitychooser', $temp);
$ADMIN->add('activitychooser',
new admin_externalpage('activitychooserrecommended', new lang_string('activitychooserrecommendations', 'course'),
global $CFG;
// Check nobody's setting the indexing and query-only server to the same one.
- if ($CFG->searchenginequeryonly === $value) {
+ if (isset($CFG->searchenginequeryonly) && $CFG->searchenginequeryonly === $value) {
return get_string('searchenginequeryonlysame', 'admin');
} else {
return '';
global $CFG;
// Check nobody's setting the indexing and query-only server to the same one.
- if ($CFG->searchengine === $value) {
+ if (isset($CFG->searchengine) && $CFG->searchengine === $value) {
return get_string('searchenginequeryonlysame', 'admin');
} else {
return '';
$ADMIN->add('server', new admin_category('taskconfig', new lang_string('taskadmintitle', 'admin')));
$temp = new admin_settingpage('taskprocessing', new lang_string('taskprocessing','admin'));
+
+$setting = new admin_setting_configcheckbox(
+ 'cron_enabled',
+ new lang_string('cron_enabled', 'admin'),
+ new lang_string('cron_enabled_desc', 'admin'),
+ 1
+);
+$setting->set_updatedcallback('theme_reset_static_caches');
+$temp->add($setting);
+
$temp->add(
new admin_setting_configtext(
'task_scheduled_concurrency_limit',
$data = new \stdClass();
$newmodelmenu = new \action_menu();
- $newmodelmenu->set_menu_trigger(get_string('newmodel', 'tool_analytics'), 'btn btn-default');
+ $newmodelmenu->set_menu_trigger(get_string('newmodel', 'tool_analytics'), 'btn btn-secondary');
$newmodelmenu->set_alignment(\action_menu::TL, \action_menu::BL);
$newmodelmenu->add(new \action_menu_link(
{{/trainedexternally}}
{{! Hidden by default if #trainedexternally as the default option is trainedmodel in this case.}}
-<div id="id-evaluation-timesplitting-container" class="m-t-1 {{#trainedexternally}}hidden{{/trainedexternally}}">
+<div id="id-evaluation-timesplitting-container" class="mt-3 {{#trainedexternally}}hidden{{/trainedexternally}}">
{{#str}} selecttimesplittingforevaluation, tool_analytics {{/str}}
<div>
- <select id="id-evaluation-timesplitting" name="timesplitting" class="custom-select m-t-1">
+ <select id="id-evaluation-timesplitting" name="timesplitting" class="custom-select mt-3">
{{#timesplittingmethods}}
<option value="{{id}}">{{text}}</option>
{{/timesplittingmethods}}
<input class="custom-control-input" type="radio" name="exportoption" id="id-mode-exportmodel" value="exportmodel" checked>
<label class="custom-control-label" for="id-mode-exportmodel">{{#str}} exportmodel, tool_analytics {{/str}}</label>
</div>
-<div class="custom-control custom-checkbox m-l-2" id="id-includeweights-container">
+<div class="custom-control custom-checkbox ml-5" id="id-includeweights-container">
<input class="custom-control-input" type="checkbox" id="id-includeweights" value="1" checked>
<label class="custom-control-label" for="id-includeweights">{{#str}} exportincludeweights, tool_analytics {{/str}}</label>
</div>
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_analytics'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_availabilityconditions';
'optimize-runs' => '',
'add-core-features-to-theme' => false,
'axe' => false,
+ 'disable-composer' => false,
+ 'composer-upgrade' => true,
+ 'composer-self-update' => true,
),
array(
'j' => 'parallel',
Behat utilities to initialise behat tests
Usage:
- php init.php [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]] [--help]
+ php init.php [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]]
+ [--axe] [-o | --optimize-runs] [-a | --add-core-features-to-theme]
+ [--no-composer-self-update] [--no-composer-upgrade]
+ [--disable-composer]
+ [--help]
Options:
--j, --parallel Number of parallel behat run to initialise
--m, --maxruns Max parallel processes to be executed at one time.
---fromrun Execute run starting from (Used for parallel runs on different vms)
---torun Execute run till (Used for parallel runs on different vms)
---axe Include axe accessibility tests
+-j, --parallel Number of parallel behat run to initialise
+-m, --maxruns Max parallel processes to be executed at one time
+--fromrun Execute run starting from (Used for parallel runs on different vms)
+--torun Execute run till (Used for parallel runs on different vms)
+--axe Include axe accessibility tests
--o, --optimize-runs Split features with specified tags in all parallel runs.
--a, --add-core-features-to-theme Add all core features to specified theme's
+-o, --optimize-runs
+ Split features with specified tags in all parallel runs.
--h, --help Print out this help
+-a, --add-core-features-to-theme
+ Add all core features to specified theme's
+
+--no-composer-self-update
+ Prevent upgrade of the composer utility using its self-update command
+
+--no-composer-upgrade
+ Prevent update development dependencies using composer
+
+--disable-composer
+ A shortcut to disable composer self-update and dependency update
+ Note: Installation of composer and/or dependencies will still happen as required
+
+-h, --help Print out this help
Example from Moodle root directory:
\$ php admin/tool/behat/cli/init.php --parallel=2
$cwd = getcwd();
$output = null;
-// If behat dependencies not downloaded then do it first, else symfony/process can't be used.
-testing_update_composer_dependencies();
+if ($options['disable-composer']) {
+ // Disable self-update and upgrade easily.
+ // Note: Installation will still occur regardless of this setting.
+ $options['composer-self-update'] = false;
+ $options['composer-upgrade'] = false;
+}
+
+// Install and update composer and dependencies as required.
+testing_update_composer_dependencies($options['composer-self-update'], $options['composer-upgrade']);
// Check whether the behat test environment needs to be updated.
chdir(__DIR__);
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
$plugin->dependencies = array(
<input type="hidden" name="sesskey" value="{{{ sesskey }}}">
<input type="hidden" name="p" value="{{ currentpage }}">
- <fieldset class="m-a-1 m-3">
+ <fieldset class="m-3">
<button type="submit" name="savecontinue" class="btn btn-secondary">
{{#str}}savecontinue, tool_customlang{{/str}}
</button>
<div class="list-group">
<div class="container-fluid d-none d-md-block list-group-item border-bottom-0">
- <div class="row-fluid">
+ <div class="row">
<div class="col-sm-4 col-md-2">
<strong>{{#str}}headingcomponent, tool_customlang{{/str}}</strong>
</div>
<strong>{{#str}}headingstandard, tool_customlang{{/str}}</strong>
</div>
<div class="col-sm-12 col-md-6">
- <span class="p-l-1 pl-3">
+ <span class="pl-3">
<strong>{{#str}}headinglocal, tool_customlang{{/str}}</strong>
</span>
</div>
{{#outdated}}list-group-item-warning{{/outdated}}
{{#modified}}list-group-item-info{{/modified}}"
>
- <div class="row-fluid ">
+ <div class="row">
<div class="col-sm-4 col-md-2">
<div class="d-md-none">
<strong>{{#str}}headingcomponent, tool_customlang{{/str}}</strong>
{{/strings}}
</div>
- <fieldset class="m-a-1 m-3">
+ <fieldset class="m-3">
<button type="submit" name="savecontinue" class="btn btn-secondary">
{{#str}}savecontinue, tool_customlang{{/str}}
</button>
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_customlang'; // Full name of the plugin (used for diagnostics)
<hr />
<div class="row">
{{#compliant}}
- <a class="component-expand p-l-2" data-component="{{raw_component}}" href='#'>
- <h4 class=" d-inline p-l-2 " id="{{raw_component}}">{{#pix}}t/collapsed, moodle, {{#str}}expandplugin, tool_dataprivacy{{/str}}{{/pix}}{{component}}</h4>
+ <a class="component-expand pl-5" data-component="{{raw_component}}" href='#'>
+ <h4 class=" d-inline pl-5 " id="{{raw_component}}">{{#pix}}t/collapsed, moodle, {{#str}}expandplugin, tool_dataprivacy{{/str}}{{/pix}}{{component}}</h4>
</a>
{{/compliant}}
{{^compliant}}
- <h4 class="d-inline p-l-3 " id="{{raw_component}}">{{component}}</h4>
+ <h4 class="d-inline pl-6 " id="{{raw_component}}">{{component}}</h4>
<span>{{#pix}}i/risk_xss, moodle, {{#str}}requiresattention, tool_dataprivacy{{/str}}{{/pix}}</span>
{{/compliant}}
{{#external}}
<div class="hide" data-section="{{raw_component}}" aria-expanded="false" role="contentinfo">
{{#metadata}}
<hr />
- <div class="p-l-3">
+ <div class="pl-6">
<dl class="row">
<dt class="col-3">
{{#link}}
{{/metadata}}
{{#nullprovider}}
<hr />
- <div class="p-l-3">
+ <div class="pl-6">
<div class="row">
<div class="col-12">
{{nullprovider}}
{{/nullprovider}}
</div>
{{/compliant}}
-</div>
\ No newline at end of file
+</div>
<div class="container-fluid mt-2">
<div class="row">
- <div class="col-md-4 p-l-0 nav-pills context-tree">
+ <div class="col-md-4 pl-0 nav-pills context-tree">
{{#tree}}
{{> tool_dataprivacy/context_tree_node}}
{{/tree}}
<h3 id="{{plugin_type_raw}}">{{#pix}}t/collapsed, moodle, {{#str}}expandplugintype, tool_dataprivacy{{/str}}{{/pix}}{{plugin_type}}</h3>
</a>
</div>
- <div class="hide p-b-1" data-plugintarget="{{plugin_type_raw}}" aria-expanded="false" role="contentinfo">
+ <div class="hide pb-3" data-plugintarget="{{plugin_type_raw}}" aria-expanded="false" role="contentinfo">
{{#plugins}}
{{> tool_dataprivacy/component_status}}
{{/plugins}}
"contextlevel": 70
}
}}
-<div class="row-fluid rtl-compatible mt-1 mb-1">
+<div class="row rtl-compatible mt-1 mb-1">
<div class="col-md-9">
- <div class="row-fluid rtl-compatible mt-1 mb-1">
+ <div class="row rtl-compatible mt-1 mb-1">
<div class="col-md-3">
<strong>{{#str}}category, tool_dataprivacy{{/str}}</strong>
</div>
{{category}}
</div>
</div>
- <div class="row-fluid rtl-compatible mt-1 mb-1">
+ <div class="row rtl-compatible mt-1 mb-1">
<div class="col-md-3">
<strong>{{#str}}purpose, tool_dataprivacy{{/str}}</strong>
</div>
{{#contexts}}
<div class="card mb-3">
<div class="card-header"><h3>{{contextname}}</h3></div>
- <div class="card-body p-l-2 p-r-2">
+ <div class="card-body pl-5 pr-5">
{{#category.name}}
<h4>{{#str}}category, tool_dataprivacy{{/str}}</h4>
</div>
</div>
{{/contexts}}
-</div>
\ No newline at end of file
+</div>
defined('MOODLE_INTERNAL') || die;
-$plugin->version = 2020061501;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_dataprivacy';
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_filetypes';
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_generator';
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_health'; // Full name of the plugin (used for diagnostics)
$plugin->maturity = MATURITY_ALPHA; // this version's maturity level
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_httpsreplace'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_innodb'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'tool_installaddon';
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->maturity = MATURITY_STABLE;
}
}}
<div class="container-fluid langimport">
- <div class="row row-fluid rtl-compatible">
+ <div class="row rtl-compatible">
<div class="col-md-{{#caninstall}}6{{/caninstall}}{{^caninstall}}12{{/caninstall}} span{{#caninstall}}6{{/caninstall}}{{^caninstall}}12{{/caninstall}} mb-1">
<form id="uninstallform" action="{{uninstallurl}}" method="post">
<fieldset>
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_langimport'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_licensemanager';
$plugin->maturity = MATURITY_STABLE;
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'logstore_legacy'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'logstore_standard'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_log'; // Full name of the plugin (used for diagnostics).
</h2>
<div>{{{framework.description}}}</div>
<h3>{{#str}}competencies, core_competency{{/str}}</h3>
- <div class="row-fluid row">
+ <div class="row">
<div class="col-lg-6">
<p>
<form data-region="filtercompetencies" data-frameworkid="{{framework.id}}" class="form-inline">
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_lpimportcsv'; // Full name of the plugin (used for diagnostics).
-$plugin->dependencies = array('tool_lp' => 2020060900);
+$plugin->dependencies = array('tool_lp' => 2021052500);
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_lpmigrate'; // Full name of the plugin (used for diagnostics).
$plugin->dependencies = array(
'tool_lp' => ANY_VERSION
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_messageinbound';
'type' => 'danger', 'message' => get_string('subscriptionfeaturenotapplied', 'tool_mobile')];
}
break;
+ // Check QR automatic login.
+ case 'qrautomaticlogin':
+ if ($ms->qrcodetype == \tool_mobile\api::QR_CODE_LOGIN) {
+ $feature['message'] = [
+ 'type' => 'danger', 'message' => get_string('subscriptionfeaturenotapplied', 'tool_mobile')];
+ }
+ break;
}
}
}
$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['qrcodetype_desc'] = 'A QR code can be provided for mobile app users to scan. This can be used to fill in the site URL, or where the site is secured using HTTPS, to automatically log the user in without having to enter their username and password.';
$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>.';
$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'),
];
+ $qrcodetypedefault = tool_mobile\api::QR_CODE_URL;
+
+ if (is_https()) { // Allow QR login for https sites.
+ $options[tool_mobile\api::QR_CODE_LOGIN] = new lang_string('qrcodetypelogin', 'tool_mobile');
+ $qrcodetypedefault = tool_mobile\api::QR_CODE_LOGIN;
+ }
+
$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));
+ new lang_string('qrcodetype_desc', 'tool_mobile'), $qrcodetypedefault, $options));
$temp->add(new admin_setting_configtext('tool_mobile/forcedurlscheme',
new lang_string('forcedurlscheme_key', 'tool_mobile'),
*/
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_mobile'; // Full name of the plugin (used for diagnostics).
$plugin->dependencies = array(
- 'webservice_rest' => 2020060900
+ 'webservice_rest' => 2021052500
);
defined('MOODLE_INTERNAL') || die;
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_monitor'; // Full name of the plugin (used for diagnostics).
input.classList.remove('is-invalid'); // Just in case the class has been applied already.
input.classList.add('is-valid');
validationArea.innerText = result.message;
- validationArea.classList.remove('text-error');
+ validationArea.classList.remove('text-danger');
validationArea.classList.add('text-success');
// Give the user some time to see their input is valid.
setTimeout(function() {
} else {
input.classList.add('is-invalid');
validationArea.innerText = result.message;
- validationArea.classList.add('text-error');
+ validationArea.classList.add('text-danger');
}
return;
}).catch();
<input type="hidden" name="resourceurl" value="{{resourceurl}}">
<input type="hidden" name="sesskey" value="{{sesskey}}">
- <div class="box py-3 modal-header p-x-1">
+ <div class="box py-3 modal-header px-3">
<h4>{{#str}}confirm, core{{/str}}</h4>
</div>
<div class="box py-3 modal-body">
<input type="hidden" name="section" value="{{section}}">
<input type="hidden" name="resourceurl" value="{{resourceurl}}">
<input type="hidden" name="sesskey" value="{{sesskey}}">
- <div class="box py-3 modal-header p-x-1">
+ <div class="box py-3 modal-header px-3">
<h4>{{#str}}importformatselectheader, tool_moodlenet{{/str}}</h4>
</div>
<div class="box py-3 modal-body">
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'tool_moodlenet';
-$plugin->version = 2020061502;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->maturity = MATURITY_ALPHA;
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_multilangupgrade'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_oauth2'; // Full name of the plugin (used for diagnostics).
require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php');
require_once(__DIR__.'/../../../../lib/testing/lib.php');
+list($options, $unrecognized) = cli_get_params(
+ [
+ 'help' => false,
+ 'disable-composer' => false,
+ 'composer-upgrade' => true,
+ 'composer-self-update' => true,
+ ],
+ [
+ 'h' => 'help',
+ ]
+);
+
+$help = "
+Utilities to initialise the PHPUnit test site.
+
+Usage:
+ php init.php [--no-composer-self-update] [--no-composer-upgrade]
+ [--help]
+
+--no-composer-self-update
+ Prevent upgrade of the composer utility using its self-update command
+
+--no-composer-upgrade
+ Prevent update development dependencies using composer
+
+--disable-composer
+ A shortcut to disable composer self-update and dependency update
+ Note: Installation of composer and/or dependencies will still happen as required
+
+-h, --help Print out this help
+
+Example from Moodle root directory:
+\$ php admin/tool/phpunit/cli/init.php
+";
+
+if (!empty($options['help'])) {
+ echo $help;
+ exit(0);
+}
+
echo "Initialising Moodle PHPUnit test environment...\n";
-testing_update_composer_dependencies();
+
+if ($options['disable-composer']) {
+ // Disable self-update and upgrade easily.
+ // Note: Installation will still occur regardless of this setting.
+ $options['composer-self-update'] = false;
+ $options['composer-upgrade'] = false;
+}
+
+// Install and update composer and dependencies as required.
+testing_update_composer_dependencies($options['composer-self-update'], $options['composer-upgrade']);
$output = null;
exec('php --version', $output, $code);
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_phpunit'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_policy'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_profiling'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_recyclebin'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_replace'; // Full name of the plugin (used for diagnostics)
$plugin->maturity = MATURITY_ALPHA; // this version's maturity level
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'tool_spamcleaner'; // Full name of the plugin (used for diagnostics)
--- /dev/null
+<?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/>.
+
+/**
+ * Running tasks table.
+ *
+ * @package tool_task
+ * @copyright 2019 The Open University
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_task;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->libdir . '/tablelib.php');
+
+/**
+ * Table to display list of running task.
+ *
+ * @copyright 2019 The Open University
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class running_tasks_table extends \table_sql {
+
+ /**
+ * Constructor for the running tasks table.
+ */
+ public function __construct() {
+ parent::__construct('runningtasks');
+
+ $columnheaders = [
+ 'classname' => get_string('classname', 'tool_task'),
+ 'type' => get_string('tasktype', 'admin'),
+ 'time' => get_string('time'),
+ 'timestarted' => get_string('started', 'tool_task'),
+ 'hostname' => get_string('hostname', 'tool_task'),
+ 'pid' => get_string('pid', 'tool_task'),
+ ];
+ $this->define_columns(array_keys($columnheaders));
+ $this->define_headers(array_values($columnheaders));
+
+ // The name column is a header.
+ $this->define_header_column('classname');
+
+ // This table is not collapsible.
+ $this->collapsible(false);
+
+ // Allow pagination.
+ $this->pageable(true);
+ }
+
+ /**
+ * Query the db. Store results in the table object for use by build_table.
+ *
+ * @param int $pagesize size of page for paginated displayed table.
+ * @param bool $useinitialsbar do you want to use the initials bar. Bar
+ * will only be used if there is a fullname column defined for the table.
+ * @throws \dml_exception
+ */
+ public function query_db($pagesize, $useinitialsbar = true) {
+ $sort = $this->get_sql_sort();
+ $this->rawdata = \core\task\manager::get_running_tasks($sort);
+ }
+
+ /**
+ * Format the classname cell.
+ *
+ * @param \stdClass $row
+ * @return string
+ */
+ public function col_classname($row) : string {
+ $output = $row->classname;
+ if ($row->type == 'scheduled') {
+ if (class_exists($row->classname)) {
+ $task = new $row->classname;
+ if ($task instanceof \core\task\scheduled_task) {
+ $output .= \html_writer::tag('div', $task->get_name(), ['class' => 'task-class']);
+ }
+ }
+ } else if ($row->type == 'adhoc') {
+ $output .= \html_writer::tag('div',
+ get_string('adhoctaskid', 'tool_task', $row->id), ['class' => 'task-class']);
+ }
+ return $output;
+ }
+
+ /**
+ * Format the type cell.
+ *
+ * @param \stdClass $row
+ * @return string
+ * @throws \coding_exception
+ */
+ public function col_type($row) : string {
+ if ($row->type == 'scheduled') {
+ $output = \html_writer::span(get_string('scheduled', 'tool_task'), 'badge badge-primary');
+ } else if ($row->type == 'adhoc') {
+ $output = \html_writer::span(get_string('adhoc', 'tool_task'), 'badge badge-warning');
+ } else {
+ // This shouldn't ever happen.
+ $output = '';
+ }
+ return $output;
+ }
+
+ /**
+ * Format the time cell.
+ *
+ * @param \stdClass $row
+ * @return string
+ */
+ public function col_time($row) : string {
+ return format_time($row->time);
+ }
+
+ /**
+ * Format the timestarted cell.
+ *
+ * @param \stdClass $row
+ * @return string
+ */
+ public function col_timestarted($row) : string {
+ return userdate($row->timestarted);
+ }
+}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+$string['adhoc'] = 'Ad-hoc';
+$string['adhoctaskid'] = 'Ad-hoc task id: {$a}';
+$string['adhoctasks'] = 'Ad-hoc tasks';
$string['asap'] = 'ASAP';
$string['adhocempty'] = 'Ad hoc task queue is empty';
$string['adhocqueuesize'] = 'Ad hoc task queue has {$a} tasks';
$string['checkadhocqueue'] = 'Ad hoc task queue';
$string['checkcronrunning'] = 'Cron running';
$string['checkmaxfaildelay'] = 'Tasks max fail delay';
+$string['classname'] = 'Class name';
$string['clearfaildelay_confirm'] = 'Are you sure you want to clear the fail delay for task \'{$a}\'? After clearing the delay, the task will run according to its normal schedule.';
$string['component'] = 'Component';
$string['corecomponent'] = 'Core';
+$string['crondisabled'] = 'Cron is disabled. No new tasks will be started. The system will not operate properly until it is enabled again.';
$string['cronok'] = 'Cron is running frequently';
$string['default'] = 'Default';
$string['defaultx'] = 'Default: {$a}';
$string['enablerunnow_desc'] = 'Allows administrators to run a single scheduled task immediately, rather than waiting for it to run as scheduled. The feature requires \'Path to PHP CLI\' (pathtophp) to be set in System paths. The task runs on the web server, so you may wish to disable this feature to avoid potential performance issues.';
$string['faildelay'] = 'Fail delay';
$string['fromcomponent'] = 'From component: {$a}';
+$string['hostname'] = 'Host name';
$string['lastruntime'] = 'Last run';
+$string['lastupdated'] = 'Last updated {$a}.';
$string['nextruntime'] = 'Next run';
+$string['pid'] = 'PID';
$string['plugindisabled'] = 'Plugin disabled';
$string['pluginname'] = 'Scheduled task configuration';
$string['resettasktodefaults'] = 'Reset task schedule to defaults';
$string['resettasktodefaults_help'] = 'This will discard any local changes and revert the schedule for this task back to its original settings.';
+$string['runningtasks'] = 'Tasks running now';
$string['runnow'] = 'Run now';
$string['runagain'] = 'Run again';
$string['runnow_confirm'] = 'Are you sure you want to run this task \'{$a}\' now? The task will run on the web server and may take some time to complete.';
$string['runpattern'] = 'Run pattern';
+$string['scheduled'] = 'Scheduled';
$string['scheduledtasks'] = 'Scheduled tasks';
$string['scheduledtaskchangesdisabled'] = 'Modifications to the list of scheduled tasks have been prevented in Moodle configuration';
+$string['started'] = 'Started';
$string['taskdisabled'] = 'Task disabled';
$string['taskfailures'] = '{$a} task(s) failing';
$string['tasklogs'] = 'Task logs';
return $cell;
}
+ /**
+ * Displays a warning on the page if cron is disabled.
+ *
+ * @return string HTML code for information about cron being disabled
+ * @throws moodle_exception
+ */
+ public function cron_disabled(): string {
+ return $this->output->notification(get_string('crondisabled', 'tool_task'), 'warning');
+ }
+
/**
* Renders a link back to the scheduled tasks page (used from the 'run now' screen).
*
--- /dev/null
+<?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/>.
+
+/**
+ * Running task admin page.
+ *
+ * @package tool_task
+ * @copyright 2019 The Open University
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+require_once($CFG->libdir.'/tablelib.php');
+
+$pageurl = new \moodle_url('/admin/tool/task/runningtasks.php');
+$heading = get_string('runningtasks', 'tool_task');
+$PAGE->set_url($pageurl);
+$PAGE->set_context(context_system::instance());
+$PAGE->set_pagelayout('admin');
+$PAGE->set_title($heading);
+$PAGE->set_heading($heading);
+
+admin_externalpage_setup('runningtasks');
+
+echo $OUTPUT->header();
+
+if (!get_config('core', 'cron_enabled')) {
+ $renderer = $PAGE->get_renderer('tool_task');
+ echo $renderer->cron_disabled();
+}
+
+$table = new \tool_task\running_tasks_table();
+$table->baseurl = $pageurl;
+$table->out(100, false);
+
+echo $OUTPUT->footer();
} else {
echo $OUTPUT->header();
+ if (!get_config('core', 'cron_enabled')) {
+ echo $renderer->cron_disabled();
+ }
$tasks = core\task\manager::get_all_scheduled_tasks();
echo $renderer->scheduled_tasks_table($tasks, $lastchanged);
echo $OUTPUT->footer();
"$CFG->wwwroot/$CFG->admin/tool/task/scheduledtasks.php"
)
);
+
+ $ADMIN->add(
+ 'taskconfig',
+ new admin_externalpage(
+ 'runningtasks',
+ new lang_string('runningtasks', 'tool_task'),
+ "$CFG->wwwroot/$CFG->admin/tool/task/runningtasks.php"
+ )
+ );
}
-#page-admin-tool-task-scheduledtasks .task-class {
+#page-admin-tool-task-scheduledtasks .task-class,
+#page-admin-tool-task-runningtasks .task-class {
display: block;
padding: 0 0.5em;
color: #888;
--- /dev/null
+@tool @tool_task
+Feature: See warning message if cron is disabled
+ In order to manage scheduled tasks
+ As a Moodle Administrator
+ I need to be able to view a warning message if cron is disabled
+
+ Background:
+ Given I log in as "admin"
+
+ Scenario: If cron is disabled, I should see the message
+ When the following config values are set as admin:
+ | cron_enabled | 0 |
+ And I navigate to "Server > Tasks > Scheduled tasks" in site administration
+ Then I should see "Cron is disabled"
+
+ Scenario: If cron is enabled, I should not see the message
+ When the following config values are set as admin:
+ | cron_enabled | 1 |
+ And I navigate to "Server > Tasks > Scheduled tasks" in site administration
+ Then I should not see "Cron is disabled"
--- /dev/null
+@tool @tool_task
+Feature: See running scheduled tasks
+ In order to configure scheduled tasks
+ As an admin
+ I need to see if tasks are running
+
+ Background:
+ Given I log in as "admin"
+
+ Scenario: If no task is running, I should see the corresponding message
+ Given I navigate to "Server > Tasks > Tasks running now" in site administration
+ Then I should see "Nothing to display"
+
+ Scenario: If tasks are running, I should see task details
+ Given the following "tool_task > scheduled tasks" exist:
+ | classname | seconds | hostname | pid |
+ | \core\task\automated_backup_task | 121 | c69335460f7f | 1914 |
+ And the following "tool_task > adhoc tasks" exist:
+ | classname | seconds | hostname | pid |
+ | \core\task\asynchronous_backup_task | 7201 | c69335460f7f | 1915 |
+ | \core\task\asynchronous_restore_task | 172800 | c69335460f7f | 1916 |
+ And I navigate to "Server > Tasks > Tasks running now" in site administration
+
+ # Check the scheduled task details.
+ Then I should see "Scheduled" in the "\core\task\automated_backup_task" "table_row"
+ And I should see "2 mins" in the "Automated backups" "table_row"
+ And I should see "c69335460f7f" in the "Automated backups" "table_row"
+ And I should see "1914" in the "Automated backups" "table_row"
+
+ # Check the "asynchronous_backup_task" adhoc task details.
+ And I should see "Ad-hoc" in the "\core\task\asynchronous_backup_task" "table_row"
+ And I should see "2 hours" in the "core\task\asynchronous_backup_task" "table_row"
+ And I should see "c69335460f7f" in the "core\task\asynchronous_backup_task" "table_row"
+ And I should see "1915" in the "core\task\asynchronous_backup_task" "table_row"
+
+ # Check the "asynchronous_restore_task" adhoc task details.
+ And I should see "Ad-hoc" in the "\core\task\asynchronous_restore_task" "table_row"
+ And I should see "2 days" in the "core\task\asynchronous_restore_task" "table_row"
+ And I should see "c69335460f7f" in the "core\task\asynchronous_restore_task" "table_row"
+ And I should see "1916" in the "core\task\asynchronous_restore_task" "table_row"
--- /dev/null
+<?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/>.
+
+/**
+ * Behat data generator for tool_task.
+ *
+ * @package tool_task
+ * @category test
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Behat data generator for tool_task.
+ *
+ * @package tool_task
+ * @category test
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class behat_tool_task_generator extends behat_generator_base {
+
+ /**
+ * Get a list of the entities that can be created.
+
+ * @return array entity name => information about how to generate.
+ */
+ protected function get_creatable_entities(): array {
+ return [
+ 'scheduled tasks' => [
+ 'singular' => 'scheduled task',
+ 'datagenerator' => 'scheduled_tasks',
+ 'required' => ['classname', 'seconds', 'hostname', 'pid'],
+ ],
+ 'adhoc tasks' => [
+ 'singular' => 'adhoc task',
+ 'datagenerator' => 'adhoc_tasks',
+ 'required' => ['classname', 'seconds', 'hostname', 'pid'],
+ ],
+ ];
+ }
+}
--- /dev/null
+<?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/>.
+
+/**
+ * Tool task test data generator class
+ *
+ * @package tool_task
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Tool task test data generator class
+ *
+ * @package tool_task
+ * @copyright 2020 Mikhail Golenkov <golenkovm@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_task_generator extends testing_module_generator {
+
+ /**
+ * Mark a scheduled task as running.
+ *
+ * @param array $data Scheduled task properties
+ * @throws dml_exception
+ */
+ public function create_scheduled_tasks($data) {
+ global $DB;
+ $conditions = ['classname' => $data['classname']];
+ $record = $DB->get_record('task_scheduled', $conditions, '*', MUST_EXIST);
+ $record->timestarted = time() - $data['seconds'];
+ $record->hostname = $data['hostname'];
+ $record->pid = $data['pid'];
+ $DB->update_record('task_scheduled', $record);
+ }
+
+ /**
+ * Mark an adhoc task as running.
+ *
+ * @param array $data Adhoc task properties
+ * @throws dml_exception
+ */
+ public function create_adhoc_tasks($data) {
+ global $DB;
+ $adhoctask = (object)[
+ 'classname' => $data['classname'],
+ 'nextruntime' => 0,
+ 'timestarted' => time() - $data['seconds'],
+ 'hostname' => $data['hostname'],
+ 'pid' => $data['pid'],
+ ];
+ $DB->insert_record('task_adhoc', $adhoctask);
+ }
+}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052501; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_task'; // Full name of the plugin (used for diagnostics)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_templatelibrary'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_unsuproles'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_uploadcourse'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_uploaduser'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061501; // The current module version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current module version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'tool_usertours'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'tool_xmldb'; // Full name of the plugin (used for diagnostics)
<br/>
{{#actions}}
- <a class="btn btn-outline-primary m-r-1 m-b-1 btn-insight" href="{{url}}">{{text}}</a><br/><br/>
+ <a class="btn btn-outline-primary mr-3 mb-3 btn-insight" href="{{url}}">{{text}}</a><br/><br/>
{{/actions}}
{{#usefulbuttons}}
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_cas'; // Full name of the plugin (used for diagnostics)
-$plugin->dependencies = array('auth_ldap' => 2020060900);
+$plugin->dependencies = array('auth_ldap' => 2021052500);
}
}
if (!empty($update)) {
- $authdb->Execute("UPDATE {$this->config->table}
- SET ".implode(',', $update)."
- WHERE {$this->config->fielduser}='".$this->ext_addslashes($extusername)."'");
+ $sql = "UPDATE {$this->config->table}
+ SET ".implode(',', $update)."
+ WHERE {$this->config->fielduser} = ?";
+ if (!$authdb->Execute($sql, array($this->ext_addslashes($extusername)))) {
+ print_error('auth_dbupdateerror', 'auth_db');
+ }
}
$authdb->Close();
return true;
$string['auth_dbcannotreadtable'] = 'Cannot read external table.';
$string['auth_dbtableempty'] = 'External table is empty.';
$string['auth_dbcolumnlist'] = 'External table contains the following columns:<br />{$a}';
+$string['auth_dbupdateerror'] = 'Error updating external database.';
$string['pluginname'] = 'External database';
$string['privacy:metadata'] = 'The External database authentication plugin does not store any personal data.';
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_db'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die;
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_email'; // Full name of the plugin (used for diagnostics)
$o['ou'] = 'users';
ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
+ $createdusers = array();
for ($i=1; $i<=5; $i++) {
$this->create_ldap_user($connection, $topdn, $i);
+ $createdusers[] = 'username' . $i;
}
// Set up creators group.
+ $assignedroles = array('username1', 'username2');
$o = array();
$o['objectClass'] = array('posixGroup');
$o['cn'] = 'creators';
$o['gidNumber'] = 1;
- $o['memberUid'] = array('username1', 'username2');
+ $o['memberUid'] = $assignedroles;
ldap_add($connection, 'cn='.$o['cn'].','.$topdn, $o);
$creatorrole = $DB->get_record('role', array('shortname'=>'coursecreator'));
// Check events, 5 users created with 2 users having roles.
$this->assertCount(7, $events);
foreach ($events as $index => $event) {
- $usercreatedindex = array(0, 2, 4, 5, 6);
- $roleassignedindex = array (1, 3);
- if (in_array($index, $usercreatedindex)) {
- $this->assertInstanceOf('\core\event\user_created', $event);
- }
- if (in_array($index, $roleassignedindex)) {
- $this->assertInstanceOf('\core\event\role_assigned', $event);
+ $username = $DB->get_field('user', 'username', array('id' => $event->relateduserid)); // Get username.
+
+ if ($event->eventname === '\core\event\user_created') {
+ $this->assertContains($username, $createdusers);
+ unset($events[$index]); // Remove matching event.
+
+ } else if ($event->eventname === '\core\event\role_assigned') {
+ $this->assertContains($username, $assignedroles);
+ unset($events[$index]); // Remove matching event.
+
+ } else {
+ $this->fail('Unexpected event found: ' . $event->eventname);
}
}
+ // If all the user_created and role_assigned events have matched
+ // then the $events array should be now empty.
+ $this->assertCount(0, $events);
$this->assertEquals(5, $DB->count_records('user', array('auth'=>'ldap')));
$this->assertEquals(2, $DB->count_records('role_assignments'));
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_ldap'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'auth_lti'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_manual'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_mnet'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_nologin'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_none'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2020060900; // Requires this Moodle version.
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2021052500; // Requires this Moodle version.
$plugin->component = 'auth_oauth2'; // Full name of the plugin (used for diagnostics).
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_shibboleth'; // Full name of the plugin (used for diagnostics)
# The following tests are all provided to ensure that the accessibility tests themselves are tested.
# In normal tests only one of the following is required.
Then the page should meet accessibility standards
- And the page should meet "wcag131, wcag412" accessibility standards
- And the page should meet accessibility standards with "wcag131, wcag412" extra tests
+ And the page should meet "wcag131, wcag141, wcag412" accessibility standards
+ And the page should meet accessibility standards with "wcag131, wcag141, wcag412" extra tests
And I follow "Log in"
And the page should meet accessibility standards
- And the page should meet "wcag131, wcag412" accessibility standards
- And the page should meet accessibility standards with "wcag131, wcag412" extra tests
+ And the page should meet "wcag131, wcag141, wcag412" accessibility standards
+ And the page should meet accessibility standards with "wcag131, wcag141, wcag412" extra tests
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires = 2020060900; // Requires this Moodle version
+$plugin->version = 2021052500; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires = 2021052500; // Requires this Moodle version
$plugin->component = 'auth_webservice'; // Full name of the plugin (used for diagnostics)
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'availability_completion';
M.availability_completion.form.getNode = function(json) {
// Create HTML structure.
- var html = '<span class="col-form-label p-r-1"> ' + M.util.get_string('title', 'availability_completion') + '</span>' +
+ var html = '<span class="col-form-label pr-3"> ' + M.util.get_string('title', 'availability_completion') + '</span>' +
' <span class="availability-group form-group"><label>' +
'<span class="accesshide">' + M.util.get_string('label_cm', 'availability_completion') + ' </span>' +
'<select class="custom-select" name="cm" title="' + M.util.get_string('label_cm', 'availability_completion') + '">' +
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'availability_date';
};
M.availability_date.form.getNode = function(json) {
- var html = '<span class="col-form-label p-r-1">' +
+ var html = '<span class="col-form-label pr-3">' +
M.util.get_string('direction_before', 'availability_date') + '</span> <span class="availability-group">' +
'<label><span class="accesshide">' + M.util.get_string('direction_label', 'availability_date') + ' </span>' +
'<select name="direction" class="custom-select">' +
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2020061500;
-$plugin->requires = 2020060900;
+$plugin->version = 2021052500;
+$plugin->requires = 2021052500;
$plugin->component = 'availability_grade';
this.nodesSoFar++;
// Create HTML structure.
- var html = '<label class="form-group"><span class="p-r-1">' + M.util.get_string('title', 'availability_grade') + '</span> ' +
+ var html = '<label class="form-group"><span class="pr-3">' + M.util.get_string('title', 'availability_grade') + '</span> ' +
'<span class="availability-group">' +
'<select name="id" class="custom-select"><option value="0">' + M.util.get_string('choosedots', 'moodle') + '</option>';
for (var i = 0; i < this.grades.length; i++) {