Compare commits
255 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 805361d871 | |||
| 8d68b0b251 | |||
| efc431ba0d | |||
| 9df4aa7210 | |||
| 8481609ba4 | |||
| 194406e923 | |||
| c4665bcf95 | |||
| c70d7d0386 | |||
| 4a3a673d1e | |||
| 31260f8667 | |||
| cb3deb89c1 | |||
| b21aad0837 | |||
| 8ba10c6666 | |||
| b7b45f8c0b | |||
| a2ff87ba44 | |||
| 53a3991927 | |||
| 6b502fbc2b | |||
| 8509f1feb4 | |||
| b692832347 | |||
| a5a6a9c91c | |||
| 25c09b1b1d | |||
| f00ddea3fc | |||
| 4caf331102 | |||
| 0705bb0c07 | |||
| 4748f89945 | |||
| f0abaec208 | |||
| 2933c4e061 | |||
| b808efac50 | |||
| 0df30e445f | |||
| d4f03eb0b1 | |||
| 635b4db751 | |||
| 1821997b7c | |||
| a97fde462d | |||
| 9bcfb74256 | |||
| c0fdc91ea3 | |||
| da1d1af843 | |||
| 85d5216840 | |||
| 95eb7d8343 | |||
| 720a26266a | |||
| 37906d63f9 | |||
| 870e202546 | |||
| 50a72fbcd6 | |||
| b3172cc0fd | |||
| dc39cee4f9 | |||
| f05ff7a66d | |||
| cb2a49009c | |||
| b541ee20fb | |||
| c975694cf5 | |||
| 8c39267d92 | |||
| b74030550e | |||
| 2cfcae67a0 | |||
| dbb784d1ab | |||
| be941e5a05 | |||
| 87080161e0 | |||
| 62931543fb | |||
| 3cb6a5a3b2 | |||
| 765aef276c | |||
| 2da65dae97 | |||
| 4be6148785 | |||
| 5e4ffd0559 | |||
| 99d5aff09b | |||
| ae31e9dfa8 | |||
| d077ffd3a5 | |||
| c61f9a4484 | |||
| 37ef74572d | |||
| d08e7b7e8a | |||
| 4441cfe9ce | |||
| 9dd7ac3bc3 | |||
| 2a912052bc | |||
| addc07be5a | |||
| 6aaa78f044 | |||
| 6ffe3ecc9f | |||
| c4b472700b | |||
| 414a461e41 | |||
| 952d572921 | |||
| fc01f863d3 | |||
| 1b43f6b06d | |||
| 86f297c7c2 | |||
| 21bac71bef | |||
| b400040cff | |||
| 0846b4af08 | |||
| d927703799 | |||
| 8fedcb49a5 | |||
| 0c9fe38643 | |||
| 5c7966eacf | |||
| 0ee03dd15a | |||
| 6dbf1dee71 | |||
| a884eea913 | |||
| b41b74aacb | |||
| fa0e63f9da | |||
| 306eaa606f | |||
| 9ff79ab562 | |||
| 4011bfc71f | |||
| dedb1592cb | |||
| 603e31b820 | |||
| 3dab17b872 | |||
| e81b6194e6 | |||
| b54c18392f | |||
| 7960af6567 | |||
| f24cc998f0 | |||
| 07265da01c | |||
| 6b2bbcbb0e | |||
| c1bc5df576 | |||
| 18aabbd5d5 | |||
| 4f5e2fc266 | |||
| ba801e68d7 | |||
| fbd65fabb2 | |||
| ee0f61cde4 | |||
| 5779862ee7 | |||
| 9a49f51b15 | |||
| 59f947667a | |||
| 6733f41ed1 | |||
| 867d9497f3 | |||
| a9895627a4 | |||
| 1a75be0645 | |||
| 53c3b1bacc | |||
| 730714bc78 | |||
| 4a0abc17d4 | |||
| 7eaadb4bdb | |||
| 2f88edd0c9 | |||
| 03721f06fb | |||
| c0b25af986 | |||
| d869324747 | |||
| 1b1cf1b950 | |||
| d66d85a4d7 | |||
| 67d4f4ea65 | |||
| fe1b4bee20 | |||
| 6292c6299b | |||
| 22177c5c3e | |||
| 9f2e264fd8 | |||
| e1b1a447b5 | |||
| eaf2d6a809 | |||
| a8e2b5cea1 | |||
| 7fda2e9bac | |||
| ea01c38f2c | |||
| ee0a8161dd | |||
| 8adff28414 | |||
| 020810aea0 | |||
| 56930d1d67 | |||
| 2ec76277dc | |||
| bfff57b297 | |||
| 5e7c5b9cec | |||
| caa236c415 | |||
| 52a77683aa | |||
| 6afb3736f8 | |||
| 96582b63db | |||
| a5e149a1b7 | |||
| 7cf3a406ff | |||
| 25d1533b27 | |||
| 462c6e9e2c | |||
| 1db5a1205e | |||
| c3c7b02867 | |||
| 7d1af3ec1d | |||
| 5efefd458e | |||
| ebc198cfb8 | |||
| 1c348b2e8d | |||
| f18444a5d1 | |||
| 6fd48eff30 | |||
| 68082ac364 | |||
| 9edebd4951 | |||
| adfe298af8 | |||
| cd6c7e0068 | |||
| d11806d957 | |||
| 6a5c1ab6f8 | |||
| e453665f7d | |||
| 3f73b4f487 | |||
| 4dbc8e7655 | |||
| 1fb38c5cf6 | |||
| 71b452912a | |||
| 1c9edf3920 | |||
| c4f7a4bc62 | |||
| 9d72d1a9e6 | |||
| 198b653bf7 | |||
| 77a359ca7b | |||
| bf1e44117b | |||
| f8df624e37 | |||
| 704c30b1fb | |||
| a178e09bfb | |||
| 48096011e3 | |||
| 7ef572d39e | |||
| 75ab679716 | |||
| 2dc1afe547 | |||
| 115f4461ce | |||
| c0cf6abf34 | |||
| ff6ea1e369 | |||
| c5c42e96d2 | |||
| 39fd21e4ff | |||
| 49f70858e9 | |||
| 64d75c9a1a | |||
| 695499c681 | |||
| d8c3b7e662 | |||
| 6adc5e89b0 | |||
| c9eeb1a7c1 | |||
| 68e4a7dac8 | |||
| 73bbb3e7a8 | |||
| d00045e8f5 | |||
| 7a8b3702e3 | |||
| 887f9c3fc6 | |||
| 28b0d9256f | |||
| 2e6729e923 | |||
| d3a2788437 | |||
| c04559ccb6 | |||
| a6e4fbe122 | |||
| c1ed11df7a | |||
| 1edd36e905 | |||
| 91aee9939b | |||
| a585ee9432 | |||
| bb0acb3e9c | |||
| 02f08b16c5 | |||
| e206c3b8f2 | |||
| 3246d41cb2 | |||
| 8594f5e8ae | |||
| c0842ca500 | |||
| c670210a1d | |||
| fd908d09fd | |||
| d859e8774c | |||
| a86318bd92 | |||
| 77b19b828b | |||
| d046109d4d | |||
| bc8d03c68d | |||
| f394d9efae | |||
| b67c73c86b | |||
| 9941fbdae4 | |||
| aa23048889 | |||
| c4b8e4ca14 | |||
| e5ec4988b6 | |||
| 35ce17025a | |||
| fc1ddb3289 | |||
| 85b9cf9ce4 | |||
| 05bb501b4f | |||
| 116d41cdfd | |||
| a5cff8a55b | |||
| 06e0263936 | |||
| de98c397f3 | |||
| f091f67f81 | |||
| 7cfbdd0422 | |||
| 089100fdb3 | |||
| 68e85534a8 | |||
| 0f41a0280d | |||
| fd9466fceb | |||
| 6cb1f99459 | |||
| 8bc3576bb3 | |||
| 4158b39809 | |||
| c7afe02401 | |||
| 37524fa1e6 | |||
| 44c7386d16 | |||
| c3f4abed6f | |||
| 2acb24d84e | |||
| 6783597dc0 | |||
| 8c3f81aa69 | |||
| 3dd509b06b | |||
| da1a4189e1 | |||
| 213abaaf97 | |||
| 9e9c0912e3 | |||
| ad7d0f05de |
+27
-12
@@ -151,6 +151,9 @@ module.exports = function(grunt) {
|
||||
tasks: ['yui']
|
||||
},
|
||||
gherkinlint: {
|
||||
options: {
|
||||
nospawn: false,
|
||||
},
|
||||
files: ['**/tests/behat/*.feature'],
|
||||
tasks: ['gherkinlint']
|
||||
}
|
||||
@@ -293,19 +296,31 @@ module.exports = function(grunt) {
|
||||
};
|
||||
|
||||
tasks.gherkinlint = function() {
|
||||
var done = this.async(),
|
||||
options = grunt.config('gherkinlint.options');
|
||||
const done = this.async();
|
||||
const options = grunt.config('gherkinlint.options');
|
||||
|
||||
var args = grunt.file.expand(options.files);
|
||||
args.unshift(path.normalize(__dirname + '/node_modules/.bin/gherkin-lint'));
|
||||
grunt.util.spawn({
|
||||
cmd: 'node',
|
||||
args: args,
|
||||
opts: {stdio: 'inherit', env: process.env}
|
||||
}, function(error, result, code) {
|
||||
// Propagate the exit code.
|
||||
done(code === 0);
|
||||
});
|
||||
// Grab the gherkin-lint linter and required scaffolding.
|
||||
const linter = require('gherkin-lint/src/linter.js');
|
||||
const featureFinder = require('gherkin-lint/src/feature-finder.js');
|
||||
const configParser = require('gherkin-lint/src/config-parser.js');
|
||||
const formatter = require('gherkin-lint/src/formatters/stylish.js');
|
||||
|
||||
// Run the linter.
|
||||
const results = linter.lint(
|
||||
featureFinder.getFeatureFiles(grunt.file.expand(options.files)),
|
||||
configParser.getConfiguration(configParser.defaultConfigFileName)
|
||||
);
|
||||
|
||||
// Print the results out uncondtionally.
|
||||
formatter.printResults(results);
|
||||
|
||||
// Report on the results.
|
||||
// We exit 1 if there is at least one error, otherwise we exit cleanly.
|
||||
if (results.some(result => result.errors.length > 0)) {
|
||||
done(1);
|
||||
} else {
|
||||
done(0);
|
||||
}
|
||||
};
|
||||
|
||||
tasks.startup = function() {
|
||||
|
||||
@@ -45,7 +45,7 @@ $error = optional_param('error', '', PARAM_ALPHANUM);
|
||||
|
||||
admin_externalpage_setup('registrationmoodleorg');
|
||||
|
||||
if ($url !== HUB_MOODLEORGHUBURL) {
|
||||
if (parse_url($url, PHP_URL_HOST) !== parse_url(HUB_MOODLEORGHUBURL, PHP_URL_HOST)) {
|
||||
// Allow other plugins to confirm registration on custom hubs. Plugins implementing this
|
||||
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
|
||||
$callbacks = get_plugins_with_function('hub_registration');
|
||||
|
||||
@@ -39,7 +39,7 @@ $token = optional_param('token', '', PARAM_TEXT);
|
||||
|
||||
admin_externalpage_setup('registrationmoodleorg');
|
||||
|
||||
if ($url !== HUB_MOODLEORGHUBURL) {
|
||||
if (parse_url($url, PHP_URL_HOST) !== parse_url(HUB_MOODLEORGHUBURL, PHP_URL_HOST)) {
|
||||
// Allow other plugins to renew registration on custom hubs. Plugins implementing this
|
||||
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
|
||||
$callbacks = get_plugins_with_function('hub_registration');
|
||||
|
||||
@@ -97,7 +97,10 @@ $options = array(
|
||||
GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'HTTP_X_FORWARDED_FOR, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR => 'HTTP_CLIENT, REMOTE_ADDR',
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'REMOTE_ADDR');
|
||||
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'), new lang_string('configgetremoteaddrconf', 'admin'), 0, $options));
|
||||
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'),
|
||||
new lang_string('configgetremoteaddrconf', 'admin'),
|
||||
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP, $options));
|
||||
$temp->add(new admin_setting_configtext('reverseproxyignore', new lang_string('reverseproxyignore', 'admin'), new lang_string('configreverseproxyignore', 'admin'), ''));
|
||||
|
||||
$temp->add(new admin_setting_heading('webproxy', new lang_string('webproxy', 'admin'), new lang_string('webproxyinfo', 'admin')));
|
||||
$temp->add(new admin_setting_configtext('proxyhost', new lang_string('proxyhost', 'admin'), new lang_string('configproxyhost', 'admin'), '', PARAM_HOST));
|
||||
|
||||
@@ -32,7 +32,7 @@ require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
|
||||
// systems, but let's allow room for expansion.
|
||||
core_php_time_limit::raise(300);
|
||||
|
||||
$filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
|
||||
$filter = optional_param('filter', '', PARAM_NOTAGS);
|
||||
$type = optional_param('type', false, PARAM_ALPHAEXT);
|
||||
$component = optional_param('component', '', PARAM_ALPHAEXT);
|
||||
|
||||
|
||||
@@ -55,13 +55,13 @@ class tool_behat {
|
||||
// The loaded steps depends on the component specified.
|
||||
behat_config_manager::update_config_file($component, false);
|
||||
|
||||
// The Moodle\BehatExtension\HelpPrinter\MoodleDefinitionsPrinter will parse this search format.
|
||||
// The Moodle\BehatExtension\Definition\Printer\ConsoleDefinitionInformationPrinter will parse this search format.
|
||||
if ($type) {
|
||||
$filter .= '&&' . $type;
|
||||
}
|
||||
|
||||
if ($filter) {
|
||||
$filteroption = ' -d "' . $filter . '"';
|
||||
$filteroption = ' -d ' . escapeshellarg($filter);
|
||||
} else {
|
||||
$filteroption = ' -di';
|
||||
}
|
||||
|
||||
@@ -44,13 +44,9 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/behat/classes/behat_selectors.php');
|
||||
|
||||
$html = $this->generic_info();
|
||||
|
||||
// Form.
|
||||
ob_start();
|
||||
$form->display();
|
||||
$html .= ob_get_contents();
|
||||
ob_end_clean();
|
||||
$html = $this->output->header();
|
||||
$html .= $this->output->heading(get_string('pluginname', 'tool_behat'));
|
||||
$html .= $form->render();
|
||||
|
||||
if (empty($stepsdefinitions)) {
|
||||
$stepsdefinitions = get_string('nostepsdefinitions', 'tool_behat');
|
||||
@@ -128,7 +124,9 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
*/
|
||||
public function render_error($msg) {
|
||||
|
||||
$html = $this->generic_info();
|
||||
$html = $this->output->header();
|
||||
$html .= $this->output->heading(get_string('pluginname', 'tool_behat'));
|
||||
$html .= $this->generic_info();
|
||||
|
||||
$a = new stdClass();
|
||||
$a->errormsg = $msg;
|
||||
@@ -153,13 +151,7 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generic_info() {
|
||||
|
||||
$title = get_string('pluginname', 'tool_behat');
|
||||
|
||||
// Header.
|
||||
$html = $this->output->header();
|
||||
$html .= $this->output->heading($title);
|
||||
public function generic_info() {
|
||||
|
||||
// Info.
|
||||
$installurl = behat_command::DOCS_URL;
|
||||
@@ -175,8 +167,7 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
);
|
||||
|
||||
// List of steps.
|
||||
$html .= $this->output->box_start();
|
||||
$html .= html_writer::tag('h3', get_string('infoheading', 'tool_behat'));
|
||||
$html = $this->output->box_start();
|
||||
$html .= html_writer::tag('div', get_string('aim', 'tool_behat'));
|
||||
$html .= html_writer::start_tag('div');
|
||||
$html .= html_writer::start_tag('ul');
|
||||
|
||||
@@ -40,8 +40,14 @@ class steps_definitions_form extends moodleform {
|
||||
* @return void
|
||||
*/
|
||||
public function definition() {
|
||||
global $PAGE;
|
||||
|
||||
$mform = $this->_form;
|
||||
$output = $PAGE->get_renderer('tool_behat');
|
||||
|
||||
$mform->addElement('header', 'info', get_string('infoheading', 'tool_behat'));
|
||||
$mform->setExpanded('info', false);
|
||||
$mform->addElement('html', $output->generic_info());
|
||||
|
||||
$mform->addElement('header', 'filters', get_string('stepsdefinitionsfilters', 'tool_behat'));
|
||||
|
||||
|
||||
+20
-14
@@ -1,25 +1,31 @@
|
||||
.steps-definitions {
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #bbb;
|
||||
padding: 5px;
|
||||
margin: auto;
|
||||
width: 50%;
|
||||
#page-admin-tool-behat-index .steps-definitions {
|
||||
margin: 1rem auto;
|
||||
}
|
||||
|
||||
.steps-definitions .step {
|
||||
margin: 10px 0 10px 0;
|
||||
#page-admin-tool-behat-index .steps-definitions .step {
|
||||
margin: 1rem 0 0 0;
|
||||
border: 1px solid #eee;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.steps-definitions .stepdescription {
|
||||
color: #bf8c12;
|
||||
#page-admin-tool-behat-index .steps-definitions .stepdescription {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.steps-definitions .steptype {
|
||||
#page-admin-tool-behat-index .steps-definitions .stepcontent {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
#page-admin-tool-behat-index .steps-definitions .steptype {
|
||||
color: #1467a6;
|
||||
margin-right: 5px;
|
||||
margin-right: 1ex;
|
||||
}
|
||||
|
||||
.steps-definitions .stepregex {
|
||||
#page-admin-tool-behat-index .steps-definitions .stepapipath {
|
||||
font-family: monospace;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#page-admin-tool-behat-index .steps-definitions .stepregex {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
@@ -26,3 +26,11 @@ Feature: List the system steps definitions
|
||||
Given I set the field "Contains" to "homepage"
|
||||
When I press "Filter"
|
||||
Then I should see "Opens Moodle homepage."
|
||||
|
||||
@javascript
|
||||
Scenario: Filtering by the multiple words pattern
|
||||
Given I set the field "Contains" to "should exist"
|
||||
When I press "Filter"
|
||||
Then I should not see "There aren't steps definitions matching this filter"
|
||||
And I should see "Checks the provided element and selector type exists in the current page."
|
||||
And I should see "Checks that an element and selector type exists in another element and selector type on the current page."
|
||||
|
||||
@@ -75,6 +75,7 @@ class tool_capability_renderer extends plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function capability_comparison_table(array $capabilities, $contextid, array $roles) {
|
||||
static $capabilitycontexts = array();
|
||||
|
||||
$strpermissions = $this->get_permission_strings();
|
||||
$permissionclasses = $this->get_permission_classes();
|
||||
@@ -92,8 +93,13 @@ class tool_capability_renderer extends plugin_renderer_base {
|
||||
}
|
||||
$table->data = array();
|
||||
|
||||
$childcontextsids = [];
|
||||
foreach ($capabilities as $capability) {
|
||||
$contexts = tool_capability_calculate_role_data($capability, $roles);
|
||||
if (empty($capabilitycontexts[$capability])) {
|
||||
$capabilitycontexts[$capability] = tool_capability_calculate_role_data($capability, $roles);
|
||||
}
|
||||
$contexts = $capabilitycontexts[$capability];
|
||||
|
||||
$captitle = new html_table_cell(get_capability_string($capability) . html_writer::span($capability));
|
||||
$captitle->header = true;
|
||||
|
||||
@@ -111,6 +117,10 @@ class tool_capability_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$table->data[] = $row;
|
||||
if (!empty($contexts[$contextid]->children)) {
|
||||
$childcontextsids = array_merge($childcontextsids, $contexts[$contextid]->children);
|
||||
$childcontextsids = array_unique($childcontextsids);
|
||||
}
|
||||
}
|
||||
|
||||
// Start the list item, and print the context name as a link to the place to make changes.
|
||||
@@ -127,9 +137,9 @@ class tool_capability_renderer extends plugin_renderer_base {
|
||||
$html = $this->output->heading(html_writer::link($url, $context->get_context_name(), ['title' => $title]), 3);
|
||||
$html .= html_writer::table($table);
|
||||
// If there are any child contexts, print them recursively.
|
||||
if (!empty($contexts[$contextid]->children)) {
|
||||
foreach ($contexts[$contextid]->children as $childcontextid) {
|
||||
$html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles, true);
|
||||
if (!empty($childcontextsids)) {
|
||||
foreach ($childcontextsids as $childcontextid) {
|
||||
$html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles);
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
@tool @tool_capability
|
||||
Feature: Show capabilities for multiple contexts
|
||||
In order to check roles capabilities
|
||||
As an admin
|
||||
I need to be able to see capability overrides on several contexts
|
||||
|
||||
Background:
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
| Course 2 | C2 | 0 |
|
||||
And the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| enrol/category:config | Allow | student | Course | C1 |
|
||||
| enrol/cohort:unenrol | Allow | student | Course | C2 |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Users > Permissions > Capability overview" in site administration
|
||||
|
||||
Scenario: Show capabilities table with one capability with overrides
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/category:config |
|
||||
| Roles: | Student |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should see "Category: Miscellaneous"
|
||||
And I should see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with one capability without overrides
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/cohort:config |
|
||||
| Roles: | Student |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should not see "Category: Miscellaneous"
|
||||
And I should not see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with two capabilities, 1st without overrides and 2nd with
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/category:synchronised, enrol/category:config |
|
||||
| Roles: | Student |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should see "Category: Miscellaneous"
|
||||
And I should see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with two capabilities, 1st with overrides and 2nd without
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/category:config, enrol/cohort:config |
|
||||
| Roles: | Student |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should see "Category: Miscellaneous"
|
||||
And I should see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with two capabilities, none with overrides
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/category:synchronised, enrol/cohort:config |
|
||||
| Roles: | Student |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should not see "Category: Miscellaneous"
|
||||
And I should not see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with capability with override and no role selected
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/category:config |
|
||||
| Roles: | |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should see "Category: Miscellaneous"
|
||||
And I should see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with capability without override and no role selected
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/cohort:config |
|
||||
| Roles: | |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should not see "Category: Miscellaneous"
|
||||
And I should not see "Course: Course 1"
|
||||
And I should not see "Course: Course 2"
|
||||
|
||||
Scenario: Show capabilities table with capability with two overrides on different contexts
|
||||
When I set the following fields to these values:
|
||||
| Capability: | enrol/category:config, enrol/cohort:unenrol |
|
||||
| Roles: | |
|
||||
And I click on "Get the overview" "button"
|
||||
Then I should see "System"
|
||||
And I should see "Category: Miscellaneous"
|
||||
And I should see "Course: Course 1"
|
||||
And I should see "Course: Course 2"
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Plugin upgrade code
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2020 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Function to upgrade tool_cohortroles.
|
||||
*
|
||||
* @param int $oldversion the version we are upgrading from
|
||||
* @return bool result
|
||||
*/
|
||||
function xmldb_tool_cohortroles_upgrade($oldversion) {
|
||||
global $DB;
|
||||
|
||||
if ($oldversion < 2019052001) {
|
||||
// Delete any tool_cohortroles mappings for roles which no longer exist.
|
||||
$DB->delete_records_select('tool_cohortroles', 'roleid NOT IN (SELECT id FROM {role})');
|
||||
|
||||
// Cohortroles savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2019052001, 'tool', 'cohortroles');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$plugin->version = 2019052000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2019052001; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2019051100; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
|
||||
@@ -45,13 +45,22 @@ if ($manage) {
|
||||
$context = context_system::instance();
|
||||
// Make sure the user has the proper capability.
|
||||
require_capability('tool/dataprivacy:managedatarequests', $context);
|
||||
navigation_node::override_active_url($returnurl);
|
||||
} else {
|
||||
// For the case where a user makes request for themselves (or for their children if they are the parent).
|
||||
$returnurl = new moodle_url($CFG->wwwroot . '/admin/tool/dataprivacy/mydatarequests.php');
|
||||
$context = context_user::instance($USER->id);
|
||||
}
|
||||
|
||||
$PAGE->set_context($context);
|
||||
|
||||
if (!$manage && $profilenode = $PAGE->settingsnav->find('myprofile', null)) {
|
||||
$profilenode->make_active();
|
||||
}
|
||||
|
||||
$title = get_string('createnewdatarequest', 'tool_dataprivacy');
|
||||
$PAGE->navbar->add($title);
|
||||
|
||||
// If contactdataprotectionofficer is disabled, send the user back to the profile page, or the privacy policy page.
|
||||
// That is, unless you have sufficient capabilities to perform this on behalf of a user.
|
||||
if (!$manage && !\tool_dataprivacy\api::can_contact_dpo()) {
|
||||
@@ -100,7 +109,6 @@ if ($data = $mform->get_data()) {
|
||||
redirect($returnurl, $redirectmessage);
|
||||
}
|
||||
|
||||
$title = get_string('createnewdatarequest', 'tool_dataprivacy');
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
$PAGE->set_title($title);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
@@ -42,6 +42,13 @@ if (isguestuser()) {
|
||||
$usercontext = context_user::instance($USER->id);
|
||||
$PAGE->set_context($usercontext);
|
||||
|
||||
if ($profilenode = $PAGE->settingsnav->find('myprofile', null)) {
|
||||
$profilenode->make_active();
|
||||
}
|
||||
|
||||
$title = get_string('datarequests', 'tool_dataprivacy');
|
||||
$PAGE->navbar->add($title);
|
||||
|
||||
// Return URL.
|
||||
$params = ['id' => $USER->id];
|
||||
if ($courseid) {
|
||||
@@ -49,7 +56,6 @@ if ($courseid) {
|
||||
}
|
||||
$returnurl = new moodle_url('/user/profile.php', $params);
|
||||
|
||||
$title = get_string('datarequests', 'tool_dataprivacy');
|
||||
$PAGE->set_heading($title);
|
||||
$PAGE->set_title($title);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
@@ -27,12 +27,10 @@ require_once('../../../config.php');
|
||||
$requestid = required_param('requestid', PARAM_INT);
|
||||
$confirm = optional_param('confirm', null, PARAM_INT);
|
||||
|
||||
$PAGE->set_url(new moodle_url('/admin/tool/dataprivacy/resubmitrequest.php', ['requestid' => $requestid]));
|
||||
$url = new moodle_url('/admin/tool/dataprivacy/resubmitrequest.php', ['requestid' => $requestid]);
|
||||
$title = get_string('resubmitrequestasnew', 'tool_dataprivacy');
|
||||
|
||||
require_login();
|
||||
|
||||
$PAGE->set_context(\context_system::instance());
|
||||
require_capability('tool/dataprivacy:managedatarequests', $PAGE->context);
|
||||
\tool_dataprivacy\page_helper::setup($url, $title, 'datarequests', 'tool/dataprivacy:managedatarequests');
|
||||
|
||||
$manageurl = new moodle_url('/admin/tool/dataprivacy/datarequests.php');
|
||||
|
||||
@@ -53,10 +51,6 @@ if (null !== $confirm && confirm_sesskey()) {
|
||||
redirect($manageurl, get_string('resubmittedrequest', 'tool_dataprivacy', $stringparams));
|
||||
}
|
||||
|
||||
$heading = get_string('resubmitrequest', 'tool_dataprivacy', $stringparams);
|
||||
$PAGE->set_title($heading);
|
||||
$PAGE->set_heading($heading);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$confirmstring = get_string('confirmrequestresubmit', 'tool_dataprivacy', $stringparams);
|
||||
|
||||
@@ -34,6 +34,13 @@ $PAGE->set_context($context);
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
|
||||
// If user is logged in, then use profile navigation in breadcrumbs.
|
||||
if ($profilenode = $PAGE->settingsnav->find('myprofile', null)) {
|
||||
$profilenode->make_active();
|
||||
}
|
||||
|
||||
$PAGE->navbar->add($title);
|
||||
|
||||
$output = $PAGE->get_renderer('tool_dataprivacy');
|
||||
echo $output->header();
|
||||
$summarypage = new \tool_dataprivacy\output\summary_page();
|
||||
|
||||
@@ -346,6 +346,7 @@ class api {
|
||||
*/
|
||||
public static function get_features_list() {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/authlib.php');
|
||||
|
||||
$general = new lang_string('general');
|
||||
$mainmenu = new lang_string('mainmenu', 'tool_mobile');
|
||||
@@ -355,6 +356,7 @@ class api {
|
||||
$user = new lang_string('user');
|
||||
$files = new lang_string('files');
|
||||
$remoteaddons = new lang_string('remoteaddons', 'tool_mobile');
|
||||
$identityproviders = new lang_string('oauth2identityproviders', 'tool_mobile');
|
||||
|
||||
$availablemods = core_plugin_manager::instance()->get_plugins_of_type('mod');
|
||||
$coursemodules = array();
|
||||
@@ -421,6 +423,7 @@ class api {
|
||||
'NoDelegate_CoreTag' => new lang_string('tags'),
|
||||
'$mmLoginEmailSignup' => new lang_string('startsignup'),
|
||||
'NoDelegate_ResponsiveMainMenuItems' => new lang_string('responsivemainmenuitems', 'tool_mobile'),
|
||||
'NoDelegate_DarkMode' => new lang_string('darkmode', 'tool_mobile'),
|
||||
),
|
||||
"$mainmenu" => array(
|
||||
'$mmSideMenuDelegate_mmaFrontpage' => new lang_string('sitehome'),
|
||||
@@ -473,6 +476,31 @@ class api {
|
||||
$features["$remoteaddons"] = $remoteaddonslist;
|
||||
}
|
||||
|
||||
// Display OAuth 2 identity providers.
|
||||
if (is_enabled_auth('oauth2')) {
|
||||
$identityproviderslist = array();
|
||||
$idps = \auth_plugin_base::get_identity_providers(['oauth2']);
|
||||
|
||||
foreach ($idps as $idp) {
|
||||
// Only add identity providers that have an ID.
|
||||
$id = isset($idp['url']) ? $idp['url']->get_param('id') : null;
|
||||
if ($id != null) {
|
||||
$identityproviderslist['NoDelegate_IdentityProvider_' . $id] = $idp['name'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($identityproviderslist)) {
|
||||
$features["$identityproviders"] = array();
|
||||
|
||||
if (count($identityproviderslist) > 1) {
|
||||
// Include an option to disable them all.
|
||||
$features["$identityproviders"]['NoDelegate_IdentityProviders'] = new lang_string('all');
|
||||
}
|
||||
|
||||
$features["$identityproviders"] = array_merge($features["$identityproviders"], $identityproviderslist);
|
||||
}
|
||||
}
|
||||
|
||||
return $features;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,12 +45,16 @@ $string['custommenuitems_desc'] = 'Additional items can be added to the app\'s m
|
||||
|
||||
Link-opening methods are: app (for linking to an activity supported by the app), inappbrowser (for opening a link in a browser without leaving the app), browser (for opening the link in the device default browser outside the app) and embedded (for displaying the link in an iframe in a new page in the app).
|
||||
|
||||
When items are missing a translation for a given language, they will use other languages as fallback unless "_only" is appended to the language code.
|
||||
|
||||
For example:
|
||||
<pre>
|
||||
App help|https://someurl.xyz/help|inappbrowser
|
||||
My grades|https://someurl.xyz/local/mygrades/index.php|embedded|en
|
||||
Mis calificaciones|https://someurl.xyz/local/mygrades/index.php|embedded|es
|
||||
You will only see this in English|https://someurl.xyz/english|browser|en_only
|
||||
</pre>';
|
||||
$string['darkmode'] = 'Dark mode';
|
||||
$string['disabledfeatures'] = 'Disabled features';
|
||||
$string['disabledfeatures_desc'] = 'Select here the features you want to disable in the Mobile app for your site. Please note that some features listed here could be already disabled via other site settings. You will have to log out and log in again in the app to see the changes.';
|
||||
$string['displayerrorswarning'] = 'Display debug messages (debugdisplay) is enabled. It should be disabled.';
|
||||
@@ -84,6 +88,7 @@ $string['mobilecssurl'] = 'CSS';
|
||||
$string['mobilefeatures'] = 'Mobile features';
|
||||
$string['mobilenotificationsdisabledwarning'] = 'Mobile notifications are not enabled. They should be enabled in Notification settings.';
|
||||
$string['mobilesettings'] = 'Mobile settings';
|
||||
$string['oauth2identityproviders'] = 'OAuth 2 identity providers';
|
||||
$string['offlineuse'] = 'Offline use';
|
||||
$string['pluginname'] = 'Moodle app tools';
|
||||
$string['pluginnotenabledorconfigured'] = 'Plugin not enabled or configured.';
|
||||
|
||||
@@ -30,10 +30,16 @@ require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
$serviceshortname = required_param('service', PARAM_ALPHANUMEXT);
|
||||
$passport = required_param('passport', PARAM_RAW); // Passport send from the app to validate the response URL.
|
||||
$urlscheme = optional_param('urlscheme', 'moodlemobile', PARAM_ALPHANUM); // The URL scheme the app supports.
|
||||
$urlscheme = optional_param('urlscheme', 'moodlemobile', PARAM_NOTAGS); // The URL scheme the app supports.
|
||||
$confirmed = optional_param('confirmed', false, PARAM_BOOL); // If we are being redirected after user confirmation.
|
||||
$oauthsso = optional_param('oauthsso', 0, PARAM_INT); // Id of the OpenID issuer (for OAuth direct SSO).
|
||||
|
||||
// Validate that the urlscheme is valid.
|
||||
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9-\+\.]*$/', $urlscheme)) {
|
||||
throw new moodle_exception('Invalid parameter: the value of urlscheme isn\'t valid. ' .
|
||||
'It should start with a letter and can only contain letters, numbers and the characters "." "+" "-".');
|
||||
}
|
||||
|
||||
// Check web services enabled.
|
||||
if (!$CFG->enablewebservices) {
|
||||
throw new moodle_exception('enablewsdescription', 'webservice');
|
||||
|
||||
@@ -63,7 +63,7 @@ if ($hassiteconfig) {
|
||||
|
||||
$temp->add(new admin_setting_configtext('tool_mobile/forcedurlscheme',
|
||||
new lang_string('forcedurlscheme_key', 'tool_mobile'),
|
||||
new lang_string('forcedurlscheme', 'tool_mobile'), '', PARAM_ALPHANUM));
|
||||
new lang_string('forcedurlscheme', 'tool_mobile'), '', PARAM_NOTAGS));
|
||||
|
||||
$ADMIN->add('mobileapp', $temp);
|
||||
|
||||
|
||||
@@ -131,11 +131,12 @@ if ($execute) {
|
||||
tool_phpunit_problem('Can not create configuration file');
|
||||
}
|
||||
}
|
||||
$configdir = escapeshellarg($configdir);
|
||||
// no cleanup of path - this is tricky because we can not use escapeshellarg and friends for escaping,
|
||||
// this is from admin user so PARAM_PATH must be enough
|
||||
chdir($CFG->dirroot);
|
||||
passthru("php $CFG->admin/tool/phpunit/cli/util.php --run -c $configdir $testclass $testpath", $code);
|
||||
$configdir = escapeshellarg($configdir);
|
||||
$cleanclass = escapeshellarg($testclass);
|
||||
$cleanpath = escapeshellarg($testpath);
|
||||
|
||||
passthru("php $CFG->admin/tool/phpunit/cli/util.php --run -c $configdir $cleanclass $cleanpath", $code);
|
||||
chdir($oldcwd);
|
||||
|
||||
echo '</pre>';
|
||||
@@ -146,7 +147,7 @@ if ($execute) {
|
||||
}
|
||||
|
||||
echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
|
||||
echo '<form method="get" action="webrunner.php">';
|
||||
echo '<form method="post" action="webrunner.php">';
|
||||
echo '<fieldset class="invisiblefieldset">';
|
||||
echo '<label for="testpath">Test one file</label> ';
|
||||
echo '<input type="text" id="testpath" name="testpath" value="'.s($testpath).'" size="50" /> (all test cases from webrunner.xml if empty)';
|
||||
|
||||
@@ -39,15 +39,29 @@ if ($userid != $USER->id) {
|
||||
if (!has_capability('tool/policy:acceptbehalf', $context)) {
|
||||
require_capability('tool/policy:viewacceptances', $context);
|
||||
}
|
||||
|
||||
$user = core_user::get_user($userid);
|
||||
$PAGE->navigation->extend_for_user($user);
|
||||
}
|
||||
|
||||
$title = get_string('policiesagreements', 'tool_policy');
|
||||
|
||||
$PAGE->set_context($context);
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_url(new moodle_url('/admin/tool/policy/user.php', ['userid' => $userid]));
|
||||
$PAGE->set_title($title);
|
||||
|
||||
if ($userid == $USER->id &&
|
||||
($profilenode = $PAGE->settingsnav->find('myprofile', null))) {
|
||||
|
||||
$profilenode->make_active();
|
||||
}
|
||||
|
||||
$PAGE->navbar->add($title);
|
||||
|
||||
$output = $PAGE->get_renderer('tool_policy');
|
||||
echo $output->header();
|
||||
echo $output->heading(get_string('policiesagreements', 'tool_policy'));
|
||||
echo $output->heading($title);
|
||||
$acceptances = new \tool_policy\output\acceptances($userid, $returnurl);
|
||||
echo $output->render($acceptances);
|
||||
$PAGE->requires->js_call_amd('tool_policy/acceptmodal', 'getInstance', [context_system::instance()->id]);
|
||||
|
||||
@@ -100,9 +100,9 @@ if (!$problems) {
|
||||
$count = $problem->racount;
|
||||
$edit = array();
|
||||
$aurl = new moodle_url('/admin/roles/define.php', array('roleid'=>$problem->roleid, 'action'=>'edit'));
|
||||
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/edit', 'core', get_string('edit')));
|
||||
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
|
||||
$aurl = new moodle_url($PAGE->url, array('roleid'=>$problem->roleid, 'contextlevel'=>$problem->contextlevel, 'action'=>'delete'));
|
||||
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/delete', 'core', get_string('delete')));
|
||||
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
|
||||
$data[] = array($levelname, $rolename, $count, implode(' ', $edit));
|
||||
}
|
||||
$table = new html_table();
|
||||
|
||||
@@ -412,6 +412,12 @@ class tool_uploadcourse_course {
|
||||
$this->error('invalidshortname', new lang_string('invalidshortname', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we don't overflow the maximum length of the shortname field.
|
||||
if (core_text::strlen($this->shortname) > 255) {
|
||||
$this->error('invalidshortnametoolong', new lang_string('invalidshortnametoolong', 'tool_uploadcourse', 255));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$exists = $this->exists();
|
||||
@@ -479,6 +485,12 @@ class tool_uploadcourse_course {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure we don't overflow the maximum length of the fullname field.
|
||||
if (!empty($coursedata['fullname']) && core_text::strlen($coursedata['fullname']) > 254) {
|
||||
$this->error('invalidfullnametoolong', new lang_string('invalidfullnametoolong', 'tool_uploadcourse', 254));
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the course does not exist, or will be forced created.
|
||||
if (!$exists || $mode === tool_uploadcourse_processor::MODE_CREATE_ALL) {
|
||||
|
||||
|
||||
@@ -93,6 +93,8 @@ $string['invalideupdatemode'] = 'Invalid update mode selected';
|
||||
$string['invalidvisibilitymode'] = 'Invalid visible mode';
|
||||
$string['invalidroles'] = 'Invalid role names: {$a}';
|
||||
$string['invalidshortname'] = 'Invalid shortname';
|
||||
$string['invalidfullnametoolong'] = 'The fullname field is limited to {$a} characters';
|
||||
$string['invalidshortnametoolong'] = 'The shortname field is limited to {$a} characters';
|
||||
$string['missingmandatoryfields'] = 'Missing value for mandatory fields: {$a}';
|
||||
$string['missingshortnamenotemplate'] = 'Missing shortname and shortname template not set';
|
||||
$string['mode'] = 'Upload mode';
|
||||
|
||||
@@ -82,6 +82,37 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
|
||||
$this->assertArrayHasKey('invalidshortname', $co->get_errors());
|
||||
}
|
||||
|
||||
public function test_invalid_shortname_too_long() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
|
||||
$upload = new tool_uploadcourse_course($mode, $updatemode, [
|
||||
'category' => 1,
|
||||
'fullname' => 'New course',
|
||||
'shortname' => str_repeat('X', 2000),
|
||||
]);
|
||||
|
||||
$this->assertFalse($upload->prepare());
|
||||
$this->assertArrayHasKey('invalidshortnametoolong', $upload->get_errors());
|
||||
}
|
||||
|
||||
public function test_invalid_fullname_too_long() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
|
||||
$upload = new tool_uploadcourse_course($mode, $updatemode, [
|
||||
'category' => 1,
|
||||
'fullname' => str_repeat('X', 2000),
|
||||
]);
|
||||
|
||||
$this->assertFalse($upload->prepare());
|
||||
$this->assertArrayHasKey('invalidfullnametoolong', $upload->get_errors());
|
||||
}
|
||||
|
||||
public function test_invalid_visibility() {
|
||||
$this->resetAfterTest(true);
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
|
||||
@@ -149,7 +149,7 @@ class auth_email_external extends external_api {
|
||||
new external_single_structure(
|
||||
array(
|
||||
'id' => new external_value(PARAM_INT, 'Profile field id', VALUE_OPTIONAL),
|
||||
'shortname' => new external_value(PARAM_ALPHANUM, 'Password policy', VALUE_OPTIONAL),
|
||||
'shortname' => new external_value(PARAM_ALPHANUMEXT, 'Profile field shortname', VALUE_OPTIONAL),
|
||||
'name' => new external_value(PARAM_TEXT, 'Profield field name', VALUE_OPTIONAL),
|
||||
'datatype' => new external_value(PARAM_ALPHANUMEXT, 'Profield field datatype', VALUE_OPTIONAL),
|
||||
'description' => new external_value(PARAM_RAW, 'Profield field description', VALUE_OPTIONAL),
|
||||
|
||||
@@ -263,7 +263,8 @@ class auth_plugin_shibboleth extends auth_plugin_base {
|
||||
global $OUTPUT;
|
||||
|
||||
if (!isset($this->config->user_attribute) || empty($this->config->user_attribute)) {
|
||||
echo $OUTPUT->notification(get_string("shib_not_set_up_error", "auth_shibboleth"), 'notifyproblem');
|
||||
echo $OUTPUT->notification(get_string("shib_not_set_up_error", "auth_shibboleth",
|
||||
(new moodle_url('/auth/shibboleth/README.txt'))->out()), 'notifyproblem');
|
||||
return;
|
||||
}
|
||||
if ($this->config->convert_data and $this->config->convert_data != '' and !is_readable($this->config->convert_data)) {
|
||||
|
||||
@@ -32,8 +32,9 @@
|
||||
$shibbolethauth = get_auth_plugin('shibboleth');
|
||||
|
||||
// Check whether Shibboleth is configured properly
|
||||
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
|
||||
if (empty($pluginconfig->user_attribute)) {
|
||||
print_error('shib_not_set_up_error', 'auth_shibboleth');
|
||||
print_error('shib_not_set_up_error', 'auth_shibboleth', '', $readmeurl);
|
||||
}
|
||||
|
||||
/// If we can find the Shibboleth attribute, save it in session and return to main login page
|
||||
@@ -91,7 +92,7 @@
|
||||
elseif (!empty($_SERVER['HTTP_SHIB_APPLICATION_ID']) || !empty($_SERVER['Shib-Application-ID'])) {
|
||||
print_error('shib_no_attributes_error', 'auth_shibboleth' , '', '\''.$pluginconfig->user_attribute.'\', \''.$pluginconfig->field_map_firstname.'\', \''.$pluginconfig->field_map_lastname.'\' and \''.$pluginconfig->field_map_email.'\'');
|
||||
} else {
|
||||
print_error('shib_not_set_up_error', 'auth_shibboleth');
|
||||
print_error('shib_not_set_up_error', 'auth_shibboleth', '', $readmeurl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ $string['auth_shib_auth_method_description'] = 'Provide a name for the Shibbolet
|
||||
$string['auth_shib_auth_logo'] = 'Authentication method logo';
|
||||
$string['auth_shib_auth_logo_description'] = 'Provide a logo for the Shibboleth authentication method that is familiar to your users. This could be the logo of your Shibboleth federation, e.g. <tt>SWITCHaai Login</tt> or <tt>InCommon Login</tt> or similar.';
|
||||
$string['auth_shib_contact_administrator'] = 'In case you are not associated with the given organizations and you need access to a course on this server, please contact the <a href="mailto:{$a}">Moodle Administrator</a>.';
|
||||
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth. For set-up details, see the <a href="../auth/shibboleth/README.txt">Shibboleth README</a>.';
|
||||
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth. For set-up details, see the <a href="{$a}">Shibboleth README</a>.';
|
||||
$string['auth_shibboleth_errormsg'] = 'Please select the organization you are member of!';
|
||||
$string['auth_shibboleth_login'] = 'Shibboleth login';
|
||||
$string['auth_shibboleth_login_long'] = 'Login to Moodle via Shibboleth';
|
||||
@@ -36,7 +36,7 @@ $string['auth_shibboleth_manual_login'] = 'Manual login';
|
||||
$string['auth_shibboleth_select_member'] = 'I\'m a member of ...';
|
||||
$string['auth_shibboleth_select_organization'] = 'For authentication via Shibboleth, please select your organisation from the drop-down menu:';
|
||||
$string['auth_shib_convert_data'] = 'Data modification API';
|
||||
$string['auth_shib_convert_data_description'] = 'You can use this API to further modify the data provided by Shibboleth. Read the <a href="../auth/shibboleth/README.txt">README</a> for further instructions.';
|
||||
$string['auth_shib_convert_data_description'] = 'You can use this API to further modify the data provided by Shibboleth. Read the <a href="{$a}">README</a> for further instructions.';
|
||||
$string['auth_shib_convert_data_warning'] = 'The file does not exist or is not readable by the webserver process!';
|
||||
$string['auth_shib_changepasswordurl'] = 'Password-change URL';
|
||||
$string['auth_shib_idp_list'] = 'Identity providers';
|
||||
@@ -57,6 +57,6 @@ $string['auth_shib_username_description'] = 'Name of the webserver Shibboleth en
|
||||
$string['shib_invalid_account_error'] = 'You seem to be Shibboleth authenticated but Moodle has no valid account for your username. Your account may not exist or it may have been suspended.';
|
||||
$string['shib_no_attributes_error'] = 'You seem to be Shibboleth authenticated but Moodle didn\'t receive any user attributes. Please check that your Identity Provider releases the necessary attributes ({$a}) to the Service Provider Moodle is running on or inform the webmaster of this server.';
|
||||
$string['shib_not_all_attributes_error'] = 'Moodle needs certain Shibboleth attributes which are not present in your case. The attributes are: {$a}<br />Please contact the webmaster of this server or your Identity Provider.';
|
||||
$string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="README.txt">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
|
||||
$string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="{$a}">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
|
||||
$string['pluginname'] = 'Shibboleth';
|
||||
$string['privacy:metadata'] = 'The Shibboleth authentication plugin does not store any personal data.';
|
||||
|
||||
@@ -30,8 +30,9 @@ if ($ADMIN->fulltree) {
|
||||
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_idp_configtextarea.php');
|
||||
|
||||
// Introductory explanation.
|
||||
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
|
||||
$settings->add(new admin_setting_heading('auth_shibboleth/pluginname', '',
|
||||
new lang_string('auth_shibbolethdescription', 'auth_shibboleth')));
|
||||
new lang_string('auth_shibbolethdescription', 'auth_shibboleth', $readmeurl)));
|
||||
|
||||
// Username.
|
||||
$settings->add(new admin_setting_configtext('auth_shibboleth/user_attribute', get_string('username'),
|
||||
@@ -40,7 +41,7 @@ if ($ADMIN->fulltree) {
|
||||
// COnvert Data configuration file.
|
||||
$settings->add(new admin_setting_configfile('auth_shibboleth/convert_data',
|
||||
get_string('auth_shib_convert_data', 'auth_shibboleth'),
|
||||
get_string('auth_shib_convert_data_description', 'auth_shibboleth'), ''));
|
||||
get_string('auth_shib_convert_data_description', 'auth_shibboleth', $readmeurl), ''));
|
||||
|
||||
// WAYF.
|
||||
$settings->add(new auth_shibboleth_admin_setting_special_wayf_select());
|
||||
|
||||
@@ -91,7 +91,6 @@ class core_backup_external extends external_api {
|
||||
require_capability('moodle/backup:backupactivity', $context);
|
||||
} else {
|
||||
require_capability('moodle/backup:backupcourse', $context);
|
||||
$instanceid = $course->id;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
|
||||
+2
-2
@@ -55,9 +55,11 @@ require_capability('moodle/restore:restorecourse', $context);
|
||||
if (is_null($course)) {
|
||||
$coursefullname = $SITE->fullname;
|
||||
$courseshortname = $SITE->shortname;
|
||||
$courseurl = new moodle_url('/');
|
||||
} else {
|
||||
$coursefullname = $course->fullname;
|
||||
$courseshortname = $course->shortname;
|
||||
$courseurl = course_get_url($course->id);
|
||||
}
|
||||
|
||||
// Show page header.
|
||||
@@ -173,7 +175,6 @@ if ($restore->get_stage() != restore_ui::STAGE_PROCESS) {
|
||||
\core\task\manager::queue_adhoc_task($asynctask);
|
||||
|
||||
// Add ajax progress bar and initiate ajax via a template.
|
||||
$courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
|
||||
$restoreurl = new moodle_url('/backup/restorefile.php', array('contextid' => $contextid));
|
||||
$progresssetup = array(
|
||||
'backupid' => $restoreid,
|
||||
@@ -182,7 +183,6 @@ if ($restore->get_stage() != restore_ui::STAGE_PROCESS) {
|
||||
'restoreurl' => $restoreurl->out()
|
||||
);
|
||||
echo $renderer->render_from_template('core/async_backup_status', $progresssetup);
|
||||
|
||||
}
|
||||
|
||||
$restore->destroy();
|
||||
|
||||
@@ -199,7 +199,7 @@ class core_badges_assertion {
|
||||
$class['criteria'] = $this->_url->out(false); // Currently issued badge URL.
|
||||
if ($issued) {
|
||||
if ($this->_obversion == OPEN_BADGES_V2) {
|
||||
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id(), 'action' => 0));
|
||||
$issuerurl = new moodle_url('/badges/issuer_json.php', array('id' => $this->get_badge_id()));
|
||||
} else {
|
||||
$issuerurl = new moodle_url('/badges/assertion.php', array('b' => $this->_data->uniquehash, 'action' => 0));
|
||||
}
|
||||
@@ -233,7 +233,8 @@ class core_badges_assertion {
|
||||
$issuer['email'] = $CFG->badges_defaultissuercontact;
|
||||
}
|
||||
} else {
|
||||
$issuer = badges_get_default_issuer();
|
||||
$badge = new badge($this->get_badge_id());
|
||||
$issuer = $badge->get_badge_issuer();
|
||||
}
|
||||
}
|
||||
$this->embed_data_badge_version2($issuer, OPEN_BADGES_V2_TYPE_ISSUER);
|
||||
@@ -341,8 +342,7 @@ class core_badges_assertion {
|
||||
'/badges/badge_json.php',
|
||||
array('id' => $this->get_badge_id())
|
||||
);
|
||||
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id(), 'action' => 0,
|
||||
'obversion' => $this->_obversion));
|
||||
$issuerurl = new moodle_url('/badges/issuer_json.php', ['id' => $this->get_badge_id()]);
|
||||
// For assertion.
|
||||
if ($type == OPEN_BADGES_V2_TYPE_ASSERTION) {
|
||||
$json['@context'] = OPEN_BADGES_V2_CONTEXT;
|
||||
|
||||
@@ -929,12 +929,12 @@ class badge {
|
||||
*/
|
||||
public function get_badge_issuer() {
|
||||
$issuer = array();
|
||||
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $this->id, 'action' => 0));
|
||||
$issuer['name'] = $this->issuername;
|
||||
$issuer['url'] = $this->issuerurl;
|
||||
$issuer['email'] = $this->issuercontact;
|
||||
$issuer['@context'] = OPEN_BADGES_V2_CONTEXT;
|
||||
$issuer['id'] = $this->issuerurl;
|
||||
$issueridurl = new moodle_url('/badges/issuer_json.php', array('id' => $this->id));
|
||||
$issuer['id'] = $issueridurl->out(false);
|
||||
$issuer['type'] = OPEN_BADGES_V2_TYPE_ISSUER;
|
||||
return $issuer;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ class badge extends moodleform {
|
||||
$mform = $this->_form;
|
||||
$badge = (isset($this->_customdata['badge'])) ? $this->_customdata['badge'] : false;
|
||||
$action = $this->_customdata['action'];
|
||||
$languages = get_string_manager()->get_list_of_languages();
|
||||
|
||||
$mform->addElement('header', 'badgedetails', get_string('badgedetails', 'badges'));
|
||||
$mform->addElement('text', 'name', get_string('name'), array('size' => '70'));
|
||||
@@ -61,6 +60,8 @@ class badge extends moodleform {
|
||||
$mform->addElement('text', 'version', get_string('version', 'badges'), array('size' => '70'));
|
||||
$mform->setType('version', PARAM_TEXT);
|
||||
$mform->addHelpButton('version', 'version', 'badges');
|
||||
|
||||
$languages = get_string_manager()->get_list_of_languages();
|
||||
$mform->addElement('select', 'language', get_string('language'), $languages);
|
||||
$mform->addHelpButton('language', 'language', 'badges');
|
||||
|
||||
@@ -157,7 +158,16 @@ class badge extends moodleform {
|
||||
$mform->setType('action', PARAM_TEXT);
|
||||
|
||||
if ($action == 'new') {
|
||||
$mform->setDefault('language', $CFG->lang);
|
||||
// Try to set default badge language to that of current language, or it's parent.
|
||||
$language = current_language();
|
||||
if (isset($languages[$language])) {
|
||||
$defaultlanguage = $language;
|
||||
} else {
|
||||
// Calling get_parent_language returns an empty string instead of 'en'.
|
||||
$defaultlanguage = get_parent_language($language) ?: 'en';
|
||||
}
|
||||
|
||||
$mform->setDefault('language', $defaultlanguage);
|
||||
$this->add_action_buttons(true, get_string('createbutton', 'badges'));
|
||||
} else {
|
||||
// Add hidden fields.
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Serve Issuer JSON for related badge or default Issuer if no badge is defined.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage badges
|
||||
* @copyright 2020 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define('AJAX_SCRIPT', true);
|
||||
define('NO_MOODLE_COOKIES', true); // No need for a session here.
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
|
||||
|
||||
$id = optional_param('id', null, PARAM_INT);
|
||||
|
||||
if (empty($id)) {
|
||||
// Get the default issuer for this site.
|
||||
$json = badges_get_default_issuer();
|
||||
} else {
|
||||
// Get the issuer for this badge.
|
||||
$badge = new badge($id);
|
||||
if ($badge->status != BADGE_STATUS_INACTIVE) {
|
||||
$json = $badge->get_badge_issuer();
|
||||
} else {
|
||||
// The badge doen't exist or not accessible for the users.
|
||||
header("HTTP/1.0 410 Gone");
|
||||
$badgeurl = new moodle_url('/badges/issuer_json.php', array('id' => $id));
|
||||
$json = ['id' => $badgeurl->out()];
|
||||
$json['error'] = get_string('error:relatedbadgedoesntexist', 'badges');
|
||||
}
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo json_encode($json);
|
||||
+41
-5
@@ -114,23 +114,59 @@ class PNG_MetaDataHandler
|
||||
* @param string $value Currently an assertion URL that is added to an image metadata.
|
||||
*
|
||||
* @return string $result File content with a new chunk as a string. Can be used in file_put_contents() to write to a file.
|
||||
* @throws \moodle_exception when unsupported chunk type is defined.
|
||||
*/
|
||||
public function add_chunks($type, $key, $value) {
|
||||
if (strlen($key) > 79) {
|
||||
debugging('Key is too big');
|
||||
}
|
||||
|
||||
// tEXt Textual data.
|
||||
// Keyword: 1-79 bytes (character string)
|
||||
// Null separator: 1 byte
|
||||
// Text: n bytes (character string)
|
||||
$data = $key . "\0" . $value;
|
||||
$dataparts = [];
|
||||
if ($type === 'iTXt') {
|
||||
// International textual data (iTXt).
|
||||
// Keyword: 1-79 bytes (character string).
|
||||
$dataparts[] = $key;
|
||||
// Null separator: 1 byte.
|
||||
$dataparts[] = "\x00";
|
||||
// Compression flag: 1 byte
|
||||
// A value of 0 means no compression.
|
||||
$dataparts[] = "\x00";
|
||||
// Compression method: 1 byte
|
||||
// If compression is disabled, the method should also be 0.
|
||||
$dataparts[] = "\x00";
|
||||
// Language tag: 0 or more bytes (character string)
|
||||
// When there is no language specified leave empty.
|
||||
|
||||
// Null separator: 1 byte.
|
||||
$dataparts[] = "\x00";
|
||||
// Translated keyword: 0 or more bytes
|
||||
// When there is no translation specified, leave empty.
|
||||
|
||||
// Null separator: 1 byte.
|
||||
$dataparts[] = "\x00";
|
||||
// Text: 0 or more bytes.
|
||||
$dataparts[] = $value;
|
||||
} else if ($type === 'tEXt') {
|
||||
// Textual data (tEXt).
|
||||
// Keyword: 1-79 bytes (character string).
|
||||
$dataparts[] = $key;
|
||||
// Null separator: 1 byte.
|
||||
$dataparts[] = "\0";
|
||||
// Text: n bytes (character string).
|
||||
$dataparts[] = $value;
|
||||
} else {
|
||||
throw new \moodle_exception('Unsupported chunk type: ' . $type);
|
||||
}
|
||||
|
||||
$data = implode($dataparts);
|
||||
|
||||
$crc = pack("N", crc32($type . $data));
|
||||
$len = pack("N", strlen($data));
|
||||
|
||||
// Chunk format: length + type + data + CRC.
|
||||
// CRC is a CRC-32 computed over the chunk type and chunk data.
|
||||
$newchunk = $len . $type . $data . $crc;
|
||||
$this->_chunks[$type] = $data;
|
||||
|
||||
$result = substr($this->_contents, 0, $this->_size - 12)
|
||||
. $newchunk
|
||||
|
||||
+8
-5
@@ -37,11 +37,14 @@ $string['privacy:metadata'] = 'The File cache cachestore plugin stores data brie
|
||||
$string['prescan'] = 'Prescan directory';
|
||||
$string['prescan_help'] = 'If enabled the directory is scanned when the cache is first used and requests for files are first checked against the scan data. This can help if you have a slow file system and are finding that file operations are causing you a bottle neck.';
|
||||
$string['singledirectory'] = 'Single directory store';
|
||||
$string['singledirectory_help'] = 'If enabled files (cached items) will be stored in a single directory rather than being broken up into multiple directories.<br />
|
||||
Enabling this will speed up file interactions but comes at the cost of increased risk of hitting file system limitations.<br />
|
||||
It is advisable to only turn this on if the following is true:<br />
|
||||
- If you know the number of items in the cache is going to be small enough that it won\'t cause issues on the file system you are running with.<br />
|
||||
- The data being cached is not expensive to generate. If it is then sticking with the default may still be the better option as it reduces the chance of issues.';
|
||||
$string['singledirectory_help'] = 'If enabled files (cached items) will be stored in a single directory rather than being broken up into multiple directories.
|
||||
|
||||
Enabling this will speed up file interactions but comes at the cost of increased risk of hitting file system limitations.
|
||||
|
||||
It is advisable to only turn this on if the following is true:
|
||||
|
||||
* If you know the number of items in the cache is going to be small enough that it won\'t cause issues on the file system you are running with.
|
||||
* The data being cached is not expensive to generate. If it is then sticking with the default may still be the better option as it reduces the chance of issues.';
|
||||
|
||||
/**
|
||||
* This is is like the file store, but designed for siutations where:
|
||||
|
||||
@@ -52,11 +52,23 @@ require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
$categoryid = optional_param('category', null, PARAM_INT);
|
||||
$courseid = optional_param('course', SITEID, PARAM_INT);
|
||||
$view = optional_param('view', 'upcoming', PARAM_ALPHA);
|
||||
$day = optional_param('cal_d', 0, PARAM_INT);
|
||||
$mon = optional_param('cal_m', 0, PARAM_INT);
|
||||
$year = optional_param('cal_y', 0, PARAM_INT);
|
||||
$time = optional_param('time', 0, PARAM_INT);
|
||||
$lookahead = optional_param('lookahead', null, PARAM_INT);
|
||||
|
||||
$url = new moodle_url('/calendar/view.php');
|
||||
|
||||
// If a day, month and year were passed then convert it to a timestamp. If these were passed
|
||||
// then we can assume the day, month and year are passed as Gregorian, as no where in core
|
||||
// should we be passing these values rather than the time. This is done for BC.
|
||||
if (!empty($day) && !empty($mon) && !empty($year)) {
|
||||
if (checkdate($mon, $day, $year)) {
|
||||
$time = make_timestamp($year, $mon, $day);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($time)) {
|
||||
$time = time();
|
||||
}
|
||||
|
||||
@@ -4777,6 +4777,40 @@ class api {
|
||||
$DB->delete_records(template_cohort::TABLE, array('cohortid' => $cohort->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to perform when a user is deleted.
|
||||
*
|
||||
* @param int $userid The user id.
|
||||
*/
|
||||
public static function hook_user_deleted($userid) {
|
||||
global $DB;
|
||||
|
||||
$usercompetencies = $DB->get_records(user_competency::TABLE, ['userid' => $userid], '', 'id');
|
||||
foreach ($usercompetencies as $usercomp) {
|
||||
$DB->delete_records(evidence::TABLE, ['usercompetencyid' => $usercomp->id]);
|
||||
}
|
||||
|
||||
$DB->delete_records(user_competency::TABLE, ['userid' => $userid]);
|
||||
$DB->delete_records(user_competency_course::TABLE, ['userid' => $userid]);
|
||||
$DB->delete_records(user_competency_plan::TABLE, ['userid' => $userid]);
|
||||
|
||||
// Delete any associated files.
|
||||
$fs = get_file_storage();
|
||||
$context = context_user::instance($userid);
|
||||
$userevidences = $DB->get_records(user_evidence::TABLE, ['userid' => $userid], '', 'id');
|
||||
foreach ($userevidences as $userevidence) {
|
||||
$DB->delete_records(user_evidence_competency::TABLE, ['userevidenceid' => $userevidence->id]);
|
||||
$DB->delete_records(user_evidence::TABLE, ['id' => $userevidence->id]);
|
||||
$fs->delete_area_files($context->id, 'core_competency', 'userevidence', $userevidence->id);
|
||||
}
|
||||
|
||||
$userplans = $DB->get_records(plan::TABLE, ['userid' => $userid], '', 'id');
|
||||
foreach ($userplans as $userplan) {
|
||||
$DB->delete_records(plan_competency::TABLE, ['planid' => $userplan->id]);
|
||||
$DB->delete_records(plan::TABLE, ['id' => $userplan->id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually grade a user competency.
|
||||
*
|
||||
|
||||
@@ -207,4 +207,47 @@ class core_competency_hooks_testcase extends advanced_testcase {
|
||||
$this->assertEquals(1, \core_competency\template_cohort::count_records(array('templateid' => $t1->get('id'))));
|
||||
$this->assertEquals(0, \core_competency\template_cohort::count_records(array('templateid' => $t2->get('id'))));
|
||||
}
|
||||
|
||||
public function test_hook_user_deleted() {
|
||||
$this->resetAfterTest();
|
||||
$dg = $this->getDataGenerator();
|
||||
$ccg = $dg->get_plugin_generator('core_competency');
|
||||
|
||||
$u1 = $dg->create_user();
|
||||
|
||||
$framework = $ccg->create_framework();
|
||||
$comp1 = $ccg->create_competency(['competencyframeworkid' => $framework->get('id')]);
|
||||
$comp2 = $ccg->create_competency(['competencyframeworkid' => $framework->get('id')]);
|
||||
|
||||
$c1 = $dg->create_course();
|
||||
$cc1a = $ccg->create_course_competency(['competencyid' => $comp1->get('id'), 'courseid' => $c1->id]);
|
||||
$cc1b = $ccg->create_course_competency(['competencyid' => $comp2->get('id'), 'courseid' => $c1->id]);
|
||||
$assign1a = $dg->create_module('assign', ['course' => $c1]);
|
||||
$assign1b = $dg->create_module('assign', ['course' => $c1]);
|
||||
$cmc1a = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign1a->cmid]);
|
||||
$cmc1b = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign1b->cmid]);
|
||||
$ucc1a = $ccg->create_user_competency_course(['competencyid' => $comp1->get('id'), 'courseid' => $c1->id,
|
||||
'userid' => $u1->id]);
|
||||
$ucc1b = $ccg->create_user_competency_course(['competencyid' => $comp2->get('id'), 'courseid' => $c1->id,
|
||||
'userid' => $u1->id]);
|
||||
|
||||
$c2 = $dg->create_course();
|
||||
$cc2a = $ccg->create_course_competency(['competencyid' => $comp1->get('id'), 'courseid' => $c2->id]);
|
||||
$cc2b = $ccg->create_course_competency(['competencyid' => $comp2->get('id'), 'courseid' => $c2->id]);
|
||||
$assign2a = $dg->create_module('assign', ['course' => $c2]);
|
||||
$assign2b = $dg->create_module('assign', ['course' => $c2]);
|
||||
$cmc2a = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign2a->cmid]);
|
||||
$cmc2b = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign2b->cmid]);
|
||||
$ucc2a = $ccg->create_user_competency_course(['competencyid' => $comp1->get('id'), 'courseid' => $c2->id,
|
||||
'userid' => $u1->id]);
|
||||
$ucc2b = $ccg->create_user_competency_course(['competencyid' => $comp2->get('id'), 'courseid' => $c2->id,
|
||||
'userid' => $u1->id]);
|
||||
|
||||
reset_course_userdata((object) ['id' => $c1->id, 'reset_competency_ratings' => true]);
|
||||
|
||||
delete_user($u1);
|
||||
|
||||
// Assert the records don't exist anymore.
|
||||
$this->assertEquals(0, user_competency_course::count_records(['courseid' => $c1->id, 'userid' => $u1->id]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,13 +717,49 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function get_tree($id) {
|
||||
global $DB;
|
||||
$coursecattreecache = cache::make('core', 'coursecattree');
|
||||
$rv = $coursecattreecache->get($id);
|
||||
if ($rv !== false) {
|
||||
return $rv;
|
||||
}
|
||||
// Might need to rebuild the tree. Put a lock in place to ensure other requests don't try and do this in parallel.
|
||||
$lockfactory = \core\lock\lock_config::get_lock_factory('core_coursecattree');
|
||||
$lock = $lockfactory->get_lock('core_coursecattree_cache',
|
||||
course_modinfo::COURSE_CACHE_LOCK_WAIT, course_modinfo::COURSE_CACHE_LOCK_EXPIRY);
|
||||
if ($lock === false) {
|
||||
// Couldn't get a lock to rebuild the tree.
|
||||
return [];
|
||||
}
|
||||
$rv = $coursecattreecache->get($id);
|
||||
if ($rv !== false) {
|
||||
// Tree was built while we were waiting for the lock.
|
||||
$lock->release();
|
||||
return $rv;
|
||||
}
|
||||
// Re-build the tree.
|
||||
try {
|
||||
$all = self::rebuild_coursecattree_cache_contents();
|
||||
$coursecattreecache->set_many($all);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
if (array_key_exists($id, $all)) {
|
||||
return $all[$id];
|
||||
}
|
||||
// Requested non-existing category.
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the course category tree as an array, including an extra "countall" field.
|
||||
*
|
||||
* @return array
|
||||
* @throws coding_exception
|
||||
* @throws dml_exception
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
private static function rebuild_coursecattree_cache_contents() : array {
|
||||
global $DB;
|
||||
$sql = "SELECT cc.id, cc.parent, cc.visible
|
||||
FROM {course_categories} cc
|
||||
ORDER BY cc.sortorder";
|
||||
@@ -760,12 +796,7 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
|
||||
}
|
||||
// We must add countall to all in case it was the requested ID.
|
||||
$all['countall'] = $count;
|
||||
$coursecattreecache->set_many($all);
|
||||
if (array_key_exists($id, $all)) {
|
||||
return $all[$id];
|
||||
}
|
||||
// Requested non-existing category.
|
||||
return array();
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -68,6 +68,17 @@ class course_handler extends \core_customfield\handler {
|
||||
return self::$singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run reset code after unit tests to reset the singleton usage.
|
||||
*/
|
||||
public static function reset_caches(): void {
|
||||
if (!PHPUNIT_TEST) {
|
||||
throw new \coding_exception('This feature is only intended for use in unit tests');
|
||||
}
|
||||
|
||||
static::$singleton = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current user can configure custom fields on this component.
|
||||
*
|
||||
|
||||
@@ -514,7 +514,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
|
||||
// Output section activities summary:
|
||||
$o = '';
|
||||
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
|
||||
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities pr-2 mdl-right'));
|
||||
foreach ($sectionmods as $mod) {
|
||||
$o.= html_writer::start_tag('span', array('class' => 'activity-count'));
|
||||
$o.= $mod['name'].': '.$mod['count'];
|
||||
@@ -528,7 +528,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
$a->complete = $complete;
|
||||
$a->total = $total;
|
||||
|
||||
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
|
||||
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities pr-2 mdl-right'));
|
||||
$o.= html_writer::tag('span', get_string('progresstotal', 'completion', $a), array('class' => 'activity-count'));
|
||||
$o.= html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
+4
-1
@@ -1144,7 +1144,9 @@ function course_delete_module($cmid, $async = false) {
|
||||
}
|
||||
|
||||
// Delete activity context questions and question categories.
|
||||
question_delete_activity($cm);
|
||||
$showinfo = !defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0';
|
||||
|
||||
question_delete_activity($cm, $showinfo);
|
||||
|
||||
// Call the delete_instance function, if it returns false throw an exception.
|
||||
if (!$deleteinstancefunction($cm->instance)) {
|
||||
@@ -2202,6 +2204,7 @@ function move_courses($courseids, $categoryid) {
|
||||
foreach ($dbcourses as $dbcourse) {
|
||||
$course = new stdClass();
|
||||
$course->id = $dbcourse->id;
|
||||
$course->timemodified = time();
|
||||
$course->category = $category->id;
|
||||
$course->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - $i++;
|
||||
if ($category->visible == 0) {
|
||||
|
||||
@@ -316,7 +316,8 @@ if ($action !== false && confirm_sesskey()) {
|
||||
$notificationsfail[] = get_string('movecategoryownparent', 'error', $cattomove->get_formatted_name());
|
||||
continue;
|
||||
}
|
||||
if (strpos($movetocat->path, $cattomove->path) === 0) {
|
||||
// Don't allow user to move selected category into one of it's own sub-categories.
|
||||
if (strpos($movetocat->path, $cattomove->path . '/') === 0) {
|
||||
$notificationsfail[] = get_string('movecategoryparentconflict', 'error', $cattomove->get_formatted_name());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<form action="{{searchurl}}" id="{{id}}" method="get" class="form-inline">
|
||||
<fieldset class="coursesearchbox invisiblefieldset">
|
||||
<label for="{{inputid}}">{{#str}}searchcourses{{/str}}</label>
|
||||
<input id="{{inputid}}" name="search" type="text" size="{{inputsize}}" value="{{value}}" class="form-control">
|
||||
<input id="{{inputid}}" name="search" type="text" size="{{inputsize}}" value="{{value}}" class="form-control mb-1 mb-sm-0">
|
||||
<button class="btn btn-secondary" type="submit">{{#str}}go{{/str}}</button>
|
||||
{{#helpicon}}
|
||||
{{>core/help_icon}}
|
||||
|
||||
@@ -38,25 +38,11 @@ use \core_customfield\category_controller;
|
||||
class core_customfield_api_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$handler->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get generator
|
||||
* Get generator.
|
||||
*
|
||||
* @return core_customfield_generator
|
||||
*/
|
||||
protected function get_generator() : core_customfield_generator {
|
||||
protected function get_generator(): core_customfield_generator {
|
||||
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
}
|
||||
|
||||
@@ -65,7 +51,7 @@ class core_customfield_api_testcase extends advanced_testcase {
|
||||
*
|
||||
* @param array $expected
|
||||
* @param array $array array of objects with "get($property)" method
|
||||
* @param sring $propertyname
|
||||
* @param string $propertyname
|
||||
*/
|
||||
protected function assert_property_in_array($expected, $array, $propertyname) {
|
||||
$this->assertEquals($expected, array_values(array_map(function($a) use ($propertyname) {
|
||||
@@ -80,6 +66,8 @@ class core_customfield_api_testcase extends advanced_testcase {
|
||||
* in the interface using drag-drop.
|
||||
*/
|
||||
public function test_move_category() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create the categories.
|
||||
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0];
|
||||
$id0 = $this->get_generator()->create_category($params)->get('id');
|
||||
@@ -129,6 +117,8 @@ class core_customfield_api_testcase extends advanced_testcase {
|
||||
* Tests for \core_customfield\api::get_categories_with_fields() behaviour.
|
||||
*/
|
||||
public function test_get_categories_with_fields() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create the categories.
|
||||
$options = [
|
||||
'component' => 'core_course',
|
||||
@@ -163,6 +153,8 @@ class core_customfield_api_testcase extends advanced_testcase {
|
||||
* Test for functions api::save_category() and rename_category)
|
||||
*/
|
||||
public function test_save_category() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
|
||||
'contextid' => context_system::instance()->id];
|
||||
$c1 = category_controller::create(0, (object)$params);
|
||||
@@ -196,6 +188,8 @@ class core_customfield_api_testcase extends advanced_testcase {
|
||||
* Test for function handler::create_category
|
||||
*/
|
||||
public function test_create_category() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$handler = \core_course\customfield\course_handler::create();
|
||||
$c1id = $handler->create_category();
|
||||
$c1 = $handler->get_categories_with_fields()[$c1id];
|
||||
@@ -218,6 +212,8 @@ class core_customfield_api_testcase extends advanced_testcase {
|
||||
* Tests for \core_customfield\api::delete_category() behaviour.
|
||||
*/
|
||||
public function test_delete_category_with_fields() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
global $DB;
|
||||
// Create two categories with fields and data.
|
||||
$options = [
|
||||
|
||||
@@ -37,29 +37,20 @@ use \core_customfield\field_controller;
|
||||
class core_customfield_category_controller_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$handler->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get generator
|
||||
* Get generator.
|
||||
*
|
||||
* @return core_customfield_generator
|
||||
*/
|
||||
protected function get_generator() : core_customfield_generator {
|
||||
protected function get_generator(): core_customfield_generator {
|
||||
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the field_controller::__construct function.
|
||||
*/
|
||||
public function test_constructor() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$c = category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course', 'itemid' => 0]);
|
||||
$handler = $c->get_handler();
|
||||
$this->assertTrue($c instanceof category_controller);
|
||||
@@ -83,6 +74,8 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_constructor_errors() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$cat = $this->get_generator()->create_category();
|
||||
$catrecord = $cat->to_record();
|
||||
|
||||
@@ -181,6 +174,7 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
|
||||
* \core_customfield\category_controller::get()
|
||||
*/
|
||||
public function test_create_category() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create the category.
|
||||
$lpg = $this->get_generator();
|
||||
@@ -209,6 +203,8 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
|
||||
* Tests for \core_customfield\category_controller::set() behaviour.
|
||||
*/
|
||||
public function test_rename_category() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create the category.
|
||||
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
|
||||
'contextid' => context_system::instance()->id];
|
||||
@@ -232,6 +228,8 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
|
||||
* Tests for \core_customfield\category_controller::delete() behaviour.
|
||||
*/
|
||||
public function test_delete_category() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create the category.
|
||||
$lpg = $this->get_generator();
|
||||
$category0 = $lpg->create_category();
|
||||
|
||||
@@ -35,25 +35,11 @@ use core_customfield\data_controller;
|
||||
class core_customfield_data_controller_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$handler->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get generator
|
||||
* Get generator.
|
||||
*
|
||||
* @return core_customfield_generator
|
||||
*/
|
||||
protected function get_generator() : core_customfield_generator {
|
||||
protected function get_generator(): core_customfield_generator {
|
||||
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
}
|
||||
|
||||
@@ -62,6 +48,8 @@ class core_customfield_data_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_constructor() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a course, fields category and fields.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$category0 = $this->get_generator()->create_category(['name' => 'aaaa']);
|
||||
@@ -130,6 +118,8 @@ class core_customfield_data_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_constructor_errors() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a category, field and data.
|
||||
$category = $this->get_generator()->create_category();
|
||||
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
|
||||
@@ -188,4 +178,4 @@ class core_customfield_data_controller_testcase extends advanced_testcase {
|
||||
$this->assertEquals(moodle_exception::class, get_class($e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,25 +39,11 @@ use \core_customfield\field_controller;
|
||||
class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$handler->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get generator
|
||||
* Get generator.
|
||||
*
|
||||
* @return core_customfield_generator
|
||||
*/
|
||||
protected function get_generator() : core_customfield_generator {
|
||||
protected function get_generator(): core_customfield_generator {
|
||||
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
}
|
||||
|
||||
@@ -66,6 +52,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_constructor() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create the category.
|
||||
$category0 = $this->get_generator()->create_category();
|
||||
|
||||
@@ -111,6 +99,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_constructor_errors() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create a category and a field.
|
||||
$category = $this->get_generator()->create_category();
|
||||
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
|
||||
@@ -183,6 +173,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_create_field() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$lpg = $this->get_generator();
|
||||
$category = $lpg->create_category();
|
||||
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
|
||||
@@ -211,6 +203,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
*/
|
||||
public function test_delete_field() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$lpg = $this->get_generator();
|
||||
$category = $lpg->create_category();
|
||||
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
|
||||
@@ -237,6 +231,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
* Tests for \core_customfield\field_controller::get_configdata_property() behaviour.
|
||||
*/
|
||||
public function test_get_configdata_property() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$lpg = $this->get_generator();
|
||||
$category = $lpg->create_category();
|
||||
$configdata = ['a' => 'b', 'c' => ['d', 'e']];
|
||||
@@ -251,4 +247,4 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
|
||||
$this->assertEquals(['d', 'e'], $field->get_configdata_property('c'));
|
||||
$this->assertEquals(null, $field->get_configdata_property('x'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,19 +35,11 @@ defined('MOODLE_INTERNAL') || die();
|
||||
*/
|
||||
class core_customfield_generator_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$handler->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get generator
|
||||
* @return core_customfield_generator
|
||||
*/
|
||||
protected function get_generator() : core_customfield_generator {
|
||||
protected function get_generator(): core_customfield_generator {
|
||||
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
}
|
||||
|
||||
|
||||
@@ -38,71 +38,59 @@ use core_customfield\privacy\provider;
|
||||
*/
|
||||
class core_customfield_privacy_testcase extends provider_testcase {
|
||||
|
||||
/** @var stdClass[] */
|
||||
private $courses = [];
|
||||
/** @var \core_customfield\category_controller[] */
|
||||
private $cfcats = [];
|
||||
/** @var \core_customfield\field_controller[] */
|
||||
private $cffields = [];
|
||||
|
||||
/**
|
||||
* This method is called after the last test of this test class is run.
|
||||
* Generate data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function tearDownAfterClass() {
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$handler->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up
|
||||
*/
|
||||
public function setUp() {
|
||||
protected function generate_test_data(): array {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->cfcats[1] = $this->get_generator()->create_category();
|
||||
$this->cfcats[2] = $this->get_generator()->create_category();
|
||||
$this->cffields[11] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'checkbox']);
|
||||
$this->cffields[12] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'date']);
|
||||
$this->cffields[13] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[1]->get('id'),
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
$cfcats[1] = $generator->create_category();
|
||||
$cfcats[2] = $generator->create_category();
|
||||
$cffields[11] = $generator->create_field(
|
||||
['categoryid' => $cfcats[1]->get('id'), 'type' => 'checkbox']);
|
||||
$cffields[12] = $generator->create_field(
|
||||
['categoryid' => $cfcats[1]->get('id'), 'type' => 'date']);
|
||||
$cffields[13] = $generator->create_field(
|
||||
['categoryid' => $cfcats[1]->get('id'),
|
||||
'type' => 'select', 'configdata' => ['options' => "a\nb\nc"]]);
|
||||
$this->cffields[14] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'text']);
|
||||
$this->cffields[15] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'textarea']);
|
||||
$this->cffields[21] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[2]->get('id')]);
|
||||
$this->cffields[22] = $this->get_generator()->create_field(
|
||||
['categoryid' => $this->cfcats[2]->get('id')]);
|
||||
$cffields[14] = $generator->create_field(
|
||||
['categoryid' => $cfcats[1]->get('id'), 'type' => 'text']);
|
||||
$cffields[15] = $generator->create_field(
|
||||
['categoryid' => $cfcats[1]->get('id'), 'type' => 'textarea']);
|
||||
$cffields[21] = $generator->create_field(
|
||||
['categoryid' => $cfcats[2]->get('id')]);
|
||||
$cffields[22] = $generator->create_field(
|
||||
['categoryid' => $cfcats[2]->get('id')]);
|
||||
|
||||
$this->courses[1] = $this->getDataGenerator()->create_course();
|
||||
$this->courses[2] = $this->getDataGenerator()->create_course();
|
||||
$this->courses[3] = $this->getDataGenerator()->create_course();
|
||||
$courses[1] = $this->getDataGenerator()->create_course();
|
||||
$courses[2] = $this->getDataGenerator()->create_course();
|
||||
$courses[3] = $this->getDataGenerator()->create_course();
|
||||
|
||||
$this->get_generator()->add_instance_data($this->cffields[11], $this->courses[1]->id, 1);
|
||||
$this->get_generator()->add_instance_data($this->cffields[12], $this->courses[1]->id, 1546300800);
|
||||
$this->get_generator()->add_instance_data($this->cffields[13], $this->courses[1]->id, 2);
|
||||
$this->get_generator()->add_instance_data($this->cffields[14], $this->courses[1]->id, 'Hello1');
|
||||
$this->get_generator()->add_instance_data($this->cffields[15], $this->courses[1]->id,
|
||||
$generator->add_instance_data($cffields[11], $courses[1]->id, 1);
|
||||
$generator->add_instance_data($cffields[12], $courses[1]->id, 1546300800);
|
||||
$generator->add_instance_data($cffields[13], $courses[1]->id, 2);
|
||||
$generator->add_instance_data($cffields[14], $courses[1]->id, 'Hello1');
|
||||
$generator->add_instance_data($cffields[15], $courses[1]->id,
|
||||
['text' => '<p>Hi there</p>', 'format' => FORMAT_HTML]);
|
||||
|
||||
$this->get_generator()->add_instance_data($this->cffields[21], $this->courses[1]->id, 'hihi1');
|
||||
$generator->add_instance_data($cffields[21], $courses[1]->id, 'hihi1');
|
||||
|
||||
$this->get_generator()->add_instance_data($this->cffields[14], $this->courses[2]->id, 'Hello2');
|
||||
$generator->add_instance_data($cffields[14], $courses[2]->id, 'Hello2');
|
||||
|
||||
$this->get_generator()->add_instance_data($this->cffields[21], $this->courses[2]->id, 'hihi2');
|
||||
$generator->add_instance_data($cffields[21], $courses[2]->id, 'hihi2');
|
||||
|
||||
$this->setUser($this->getDataGenerator()->create_user());
|
||||
}
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
|
||||
/**
|
||||
* Get generator
|
||||
* @return core_customfield_generator
|
||||
*/
|
||||
protected function get_generator() : core_customfield_generator {
|
||||
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
|
||||
return [
|
||||
'user' => $user,
|
||||
'cfcats' => $cfcats,
|
||||
'cffields' => $cffields,
|
||||
'courses' => $courses,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,11 +107,17 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
*/
|
||||
public function test_get_customfields_data_contexts() {
|
||||
global $DB;
|
||||
list($sql, $params) = $DB->get_in_or_equal([$this->courses[1]->id, $this->courses[2]->id], SQL_PARAMS_NAMED);
|
||||
[
|
||||
'cffields' => $cffields,
|
||||
'cfcats' => $cfcats,
|
||||
'courses' => $courses,
|
||||
] = $this->generate_test_data();
|
||||
|
||||
list($sql, $params) = $DB->get_in_or_equal([$courses[1]->id, $courses[2]->id], SQL_PARAMS_NAMED);
|
||||
$r = provider::get_customfields_data_contexts('core_course', 'course', '=0',
|
||||
$sql, $params);
|
||||
$this->assertEquals([context_course::instance($this->courses[1]->id)->id,
|
||||
context_course::instance($this->courses[2]->id)->id],
|
||||
$this->assertEquals([context_course::instance($courses[1]->id)->id,
|
||||
context_course::instance($courses[2]->id)->id],
|
||||
$r->get_contextids(), '', 0, 10, true);
|
||||
}
|
||||
|
||||
@@ -131,6 +125,8 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
* Test for provider::get_customfields_configuration_contexts()
|
||||
*/
|
||||
public function test_get_customfields_configuration_contexts() {
|
||||
$this->generate_test_data();
|
||||
|
||||
$r = provider::get_customfields_configuration_contexts('core_course', 'course');
|
||||
$this->assertEquals([context_system::instance()->id], $r->get_contextids());
|
||||
}
|
||||
@@ -140,13 +136,20 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
*/
|
||||
public function test_export_customfields_data() {
|
||||
global $USER, $DB;
|
||||
$this->resetAfterTest();
|
||||
[
|
||||
'cffields' => $cffields,
|
||||
'cfcats' => $cfcats,
|
||||
'courses' => $courses,
|
||||
] = $this->generate_test_data();
|
||||
|
||||
// Hack one of the fields so it has an invalid field type.
|
||||
$invalidfieldid = $this->cffields[21]->get('id');
|
||||
$invalidfieldid = $cffields[21]->get('id');
|
||||
$DB->update_record('customfield_field', ['id' => $invalidfieldid, 'type' => 'invalid']);
|
||||
|
||||
$context = context_course::instance($this->courses[1]->id);
|
||||
$context = context_course::instance($courses[1]->id);
|
||||
$contextlist = new approved_contextlist($USER, 'core_customfield', [$context->id]);
|
||||
provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $this->courses[1]->id]);
|
||||
provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $courses[1]->id]);
|
||||
/** @var core_privacy\tests\request\content_writer $writer */
|
||||
$writer = writer::with_context($context);
|
||||
|
||||
@@ -155,7 +158,7 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
$invaldfieldischecked = false;
|
||||
foreach ($DB->get_records('customfield_data', []) as $dbrecord) {
|
||||
$data = $writer->get_data(['Custom fields data', $dbrecord->id]);
|
||||
if ($dbrecord->instanceid == $this->courses[1]->id) {
|
||||
if ($dbrecord->instanceid == $courses[1]->id) {
|
||||
$this->assertEquals($dbrecord->fieldid, $data->fieldid);
|
||||
$this->assertNotEmpty($data->fieldtype);
|
||||
$this->assertNotEmpty($data->fieldshortname);
|
||||
@@ -175,10 +178,17 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
*/
|
||||
public function test_delete_customfields_data() {
|
||||
global $USER, $DB;
|
||||
$approvedcontexts = new approved_contextlist($USER, 'core_course', [context_course::instance($this->courses[1]->id)->id]);
|
||||
$this->resetAfterTest();
|
||||
[
|
||||
'cffields' => $cffields,
|
||||
'cfcats' => $cfcats,
|
||||
'courses' => $courses,
|
||||
] = $this->generate_test_data();
|
||||
|
||||
$approvedcontexts = new approved_contextlist($USER, 'core_course', [context_course::instance($courses[1]->id)->id]);
|
||||
provider::delete_customfields_data($approvedcontexts, 'core_course', 'course');
|
||||
$this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $this->courses[1]->id]));
|
||||
$this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $this->courses[2]->id]));
|
||||
$this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[1]->id]));
|
||||
$this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[2]->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,9 +196,16 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
*/
|
||||
public function test_delete_customfields_configuration() {
|
||||
global $USER, $DB;
|
||||
$this->resetAfterTest();
|
||||
[
|
||||
'cffields' => $cffields,
|
||||
'cfcats' => $cfcats,
|
||||
'courses' => $courses,
|
||||
] = $this->generate_test_data();
|
||||
|
||||
// Remember the list of fields in the category 2 before we delete it.
|
||||
$catid1 = $this->cfcats[1]->get('id');
|
||||
$catid2 = $this->cfcats[2]->get('id');
|
||||
$catid1 = $cfcats[1]->get('id');
|
||||
$catid2 = $cfcats[2]->get('id');
|
||||
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
|
||||
$this->assertNotEmpty($fids2);
|
||||
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
|
||||
@@ -216,9 +233,16 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
*/
|
||||
public function test_delete_customfields_configuration_for_context() {
|
||||
global $USER, $DB;
|
||||
$this->resetAfterTest();
|
||||
[
|
||||
'cffields' => $cffields,
|
||||
'cfcats' => $cfcats,
|
||||
'courses' => $courses,
|
||||
] = $this->generate_test_data();
|
||||
|
||||
// Remember the list of fields in the category 2 before we delete it.
|
||||
$catid1 = $this->cfcats[1]->get('id');
|
||||
$catid2 = $this->cfcats[2]->get('id');
|
||||
$catid1 = $cfcats[1]->get('id');
|
||||
$catid2 = $cfcats[2]->get('id');
|
||||
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
|
||||
$this->assertNotEmpty($fids2);
|
||||
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
|
||||
@@ -246,12 +270,19 @@ class core_customfield_privacy_testcase extends provider_testcase {
|
||||
*/
|
||||
public function test_delete_customfields_data_for_context() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
[
|
||||
'cffields' => $cffields,
|
||||
'cfcats' => $cfcats,
|
||||
'courses' => $courses,
|
||||
] = $this->generate_test_data();
|
||||
|
||||
provider::delete_customfields_data_for_context('core_course', 'course',
|
||||
context_course::instance($this->courses[1]->id));
|
||||
context_course::instance($courses[1]->id));
|
||||
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', '1=1', []);
|
||||
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
|
||||
$fparams['course1'] = $this->courses[1]->id;
|
||||
$fparams['course2'] = $this->courses[2]->id;
|
||||
$fparams['course1'] = $courses[1]->id;
|
||||
$fparams['course2'] = $courses[2]->id;
|
||||
$this->assertEmpty($DB->get_records_select('customfield_data', 'instanceid = :course1 AND fieldid ' . $fsql, $fparams));
|
||||
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'instanceid = :course2 AND fieldid ' . $fsql, $fparams));
|
||||
}
|
||||
|
||||
+7
-5
@@ -448,8 +448,9 @@ class enrol_self_plugin extends enrol_plugin {
|
||||
$userid = $instance->userid;
|
||||
unset($instance->userid);
|
||||
$this->unenrol_user($instance, $userid);
|
||||
$days = $instance->customint2 / 60*60*24;
|
||||
$trace->output("unenrolling user $userid from course $instance->courseid as they have did not log in for at least $days days", 1);
|
||||
$days = $instance->customint2 / DAYSECS;
|
||||
$trace->output("unenrolling user $userid from course $instance->courseid " .
|
||||
"as they did not log in for at least $days days", 1);
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
@@ -465,8 +466,9 @@ class enrol_self_plugin extends enrol_plugin {
|
||||
$userid = $instance->userid;
|
||||
unset($instance->userid);
|
||||
$this->unenrol_user($instance, $userid);
|
||||
$days = $instance->customint2 / 60*60*24;
|
||||
$trace->output("unenrolling user $userid from course $instance->courseid as they have did not access course for at least $days days", 1);
|
||||
$days = $instance->customint2 / DAYSECS;
|
||||
$trace->output("unenrolling user $userid from course $instance->courseid " .
|
||||
"as they did not access the course for at least $days days", 1);
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
@@ -712,7 +714,7 @@ class enrol_self_plugin extends enrol_plugin {
|
||||
* @return bool
|
||||
*/
|
||||
public function edit_instance_form($instance, MoodleQuickForm $mform, $context) {
|
||||
global $CFG;
|
||||
global $CFG, $DB;
|
||||
|
||||
// Merge these two settings to one value for the single selection element.
|
||||
if ($instance->notifyall and $instance->expirynotify) {
|
||||
|
||||
@@ -61,7 +61,7 @@ class enrol_self_testcase extends advanced_testcase {
|
||||
|
||||
$now = time();
|
||||
|
||||
$trace = new null_progress_trace();
|
||||
$trace = new progress_trace_buffer(new text_progress_trace(), false);
|
||||
|
||||
// Prepare some data.
|
||||
|
||||
@@ -133,18 +133,32 @@ class enrol_self_testcase extends advanced_testcase {
|
||||
// Execute sync - this is the same thing used from cron.
|
||||
|
||||
$selfplugin->sync($trace, $course2->id);
|
||||
$output = $trace->get_buffer();
|
||||
$trace->reset_buffer();
|
||||
$this->assertEquals(10, $DB->count_records('user_enrolments'));
|
||||
|
||||
$this->assertStringContainsString('No expired enrol_self enrolments detected', $output);
|
||||
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id)));
|
||||
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id)));
|
||||
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
|
||||
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
|
||||
|
||||
$selfplugin->sync($trace, null);
|
||||
$output = $trace->get_buffer();
|
||||
$trace->reset_buffer();
|
||||
$this->assertEquals(6, $DB->count_records('user_enrolments'));
|
||||
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id)));
|
||||
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id)));
|
||||
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
|
||||
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
|
||||
$this->assertStringContainsString('unenrolling user ' . $user1->id . ' from course ' . $course1->id .
|
||||
' as they did not log in for at least 14 days', $output);
|
||||
$this->assertStringContainsString('unenrolling user ' . $user1->id . ' from course ' . $course3->id .
|
||||
' as they did not log in for at least 50 days', $output);
|
||||
$this->assertStringContainsString('unenrolling user ' . $user2->id . ' from course ' . $course1->id .
|
||||
' as they did not access the course for at least 14 days', $output);
|
||||
$this->assertStringContainsString('unenrolling user ' . $user3->id . ' from course ' . $course3->id .
|
||||
' as they did not access the course for at least 50 days', $output);
|
||||
$this->assertStringNotContainsString('unenrolling user ' . $user4->id, $output);
|
||||
|
||||
$this->assertEquals(6, $DB->count_records('role_assignments'));
|
||||
$this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
|
||||
|
||||
@@ -88,7 +88,7 @@ class component_favourite_service_testcase extends advanced_testcase {
|
||||
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
$returns[$index] = $mockrow;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class component_favourite_service_testcase extends advanced_testcase {
|
||||
$crit = ['userid' => $userid, 'component' => $comp, 'itemtype' => $type, 'itemid' => $id, 'contextid' => $ctxid];
|
||||
foreach ($mockstore as $fakerow) {
|
||||
$fakerowarr = (array)$fakerow;
|
||||
if (array_diff($crit, $fakerowarr) == []) {
|
||||
if (array_diff_assoc($crit, $fakerowarr) == []) {
|
||||
return $fakerow;
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class component_favourite_service_testcase extends advanced_testcase {
|
||||
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ class component_favourite_service_testcase extends advanced_testcase {
|
||||
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
unset($mockstore[$index]);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@ class component_favourite_service_testcase extends advanced_testcase {
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
echo "Here";
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class user_favourite_service_testcase extends advanced_testcase {
|
||||
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
$returns[$index] = $mockrow;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class user_favourite_service_testcase extends advanced_testcase {
|
||||
$crit = ['userid' => $userid, 'component' => $comp, 'itemtype' => $type, 'itemid' => $id, 'contextid' => $ctxid];
|
||||
foreach ($mockstore as $fakerow) {
|
||||
$fakerowarr = (array)$fakerow;
|
||||
if (array_diff($crit, $fakerowarr) == []) {
|
||||
if (array_diff_assoc($crit, $fakerowarr) == []) {
|
||||
return $fakerow;
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ class user_favourite_service_testcase extends advanced_testcase {
|
||||
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ class user_favourite_service_testcase extends advanced_testcase {
|
||||
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
|
||||
foreach ($mockstore as $index => $mockrow) {
|
||||
$mockrowarr = (array)$mockrow;
|
||||
if (array_diff($criteria, $mockrowarr) == []) {
|
||||
if (array_diff_assoc($criteria, $mockrowarr) == []) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ require_once($CFG->dirroot . '/filter/activitynames/filter.php'); // Include the
|
||||
class filter_activitynames_filter_testcase extends advanced_testcase {
|
||||
|
||||
public function test_links() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create a test course.
|
||||
@@ -59,8 +58,8 @@ class filter_activitynames_filter_testcase extends advanced_testcase {
|
||||
preg_match_all('~<a class="autolink" title="([^"]*)" href="[^"]*/mod/page/view.php\?id=([0-9]+)">([^<]*)</a>~',
|
||||
$filtered, $matches);
|
||||
|
||||
// There should be 3 links links.
|
||||
$this->assertEquals(2, count($matches[1]));
|
||||
// There should be 2 links links.
|
||||
$this->assertCount(2, $matches[1]);
|
||||
|
||||
// Check text of title attribute.
|
||||
$this->assertEquals($page1->name, $matches[1][0]);
|
||||
@@ -74,4 +73,33 @@ class filter_activitynames_filter_testcase extends advanced_testcase {
|
||||
$this->assertEquals($page1->name, $matches[3][0]);
|
||||
$this->assertEquals($page2->name, $matches[3][1]);
|
||||
}
|
||||
|
||||
public function test_links_activity_named_hyphen() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create a test course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$context = context_course::instance($course->id);
|
||||
|
||||
// Work around an issue with the activity names filter which maintains a static cache
|
||||
// of activities for current course ID. We can re-build the cache by switching user.
|
||||
$this->setUser($this->getDataGenerator()->create_user());
|
||||
|
||||
// Create a page activity named '-' (single hyphen).
|
||||
$page = $this->getDataGenerator()->create_module('page', ['course' => $course->id, 'name' => '-']);
|
||||
|
||||
$html = '<p>Please read the - page.</p>';
|
||||
$filtered = format_text($html, FORMAT_HTML, array('context' => $context));
|
||||
|
||||
// Find the page link in the filtered html.
|
||||
preg_match_all('~<a class="autolink" title="([^"]*)" href="[^"]*/mod/page/view.php\?id=([0-9]+)">([^<]*)</a>~',
|
||||
$filtered, $matches);
|
||||
|
||||
// We should have exactly one match.
|
||||
$this->assertCount(1, $matches[1]);
|
||||
|
||||
$this->assertEquals($page->name, $matches[1][0]);
|
||||
$this->assertEquals($page->cmid, $matches[2][0]);
|
||||
$this->assertEquals($page->name, $matches[3][0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ $string['leveldefinition'] = 'Level {$a} definition';
|
||||
$string['levelempty'] = 'Click to edit level';
|
||||
$string['levelsgroup'] = 'Levels group';
|
||||
$string['lockzeropoints'] = 'Calculate grade having a minimum score of the minimum achievable grade for the rubric';
|
||||
$string['lockzeropoints_help'] = 'This setting only applies if the sum of the minimum number of points for each criterion is greater than 0. If ticked, the minimum achievable grade for the rubric will be the minimum achievable grade for the rubric. If unticked, the minimum possible score for the rubric will be mapped to the minimum grade available for the activity (which is 0 unless a scale is used).';
|
||||
$string['lockzeropoints_help'] = 'This setting only applies if the sum of the minimum number of points for each criterion is greater than 0. If ticked, the minimum score of the activity will be the minimum achievable grade for the rubric. If unticked, the minimum possible score for the rubric will be mapped to the minimum grade available for the activity (which is 0 unless a scale is used).';
|
||||
$string['name'] = 'Name';
|
||||
$string['needregrademessage'] = 'The rubric definition was changed after this student had been graded. The student can not see this rubric until you check the rubric and update the grade.';
|
||||
$string['pluginname'] = 'Rubric';
|
||||
|
||||
@@ -128,6 +128,7 @@ class helper {
|
||||
* @return array sql and params list
|
||||
*/
|
||||
protected static function get_users_sql_and_params($context, $search = '', $count = false) {
|
||||
global $DB, $USER;
|
||||
|
||||
// Fields we need from the user table.
|
||||
$extrafields = get_extra_user_fields($context);
|
||||
@@ -147,13 +148,33 @@ class helper {
|
||||
$select = "SELECT DISTINCT $ufields ";
|
||||
$orderby = " ORDER BY u.lastname ASC, u.firstname ASC";
|
||||
}
|
||||
|
||||
$groupjoinsql = '';
|
||||
$groupwheresql = '';
|
||||
$courseid = $context->instanceid;
|
||||
$groupmode = groups_get_course_groupmode(get_course($courseid));
|
||||
|
||||
// We're only interested in separate groups mode because it's the only group mode that requires the user to be a member of
|
||||
// specific group(s), except when they have the 'moodle/site:accessallgroups' capability.
|
||||
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
|
||||
// Fetch the groups that the user can see.
|
||||
$groups = groups_get_all_groups($courseid, $USER->id, 0, 'g.id');
|
||||
|
||||
// Add join condition to include users that only belong to the same group as the user.
|
||||
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED, 'gid', true, 0);
|
||||
$groupjoinsql = " JOIN {groups_members} gm ON gm.userid = u.id ";
|
||||
$groupwheresql = " AND gm.groupid $insql ";
|
||||
$params = array_merge($params, $inparams);
|
||||
}
|
||||
|
||||
$sql = "$select
|
||||
FROM {user} u
|
||||
JOIN {grade_grades_history} ggh ON u.id = ggh.userid
|
||||
JOIN {grade_items} gi ON gi.id = ggh.itemid
|
||||
WHERE $filtersql gi.courseid = :courseid";
|
||||
$groupjoinsql
|
||||
WHERE $filtersql gi.courseid = :courseid $groupwheresql";
|
||||
$sql .= $orderby;
|
||||
$params['courseid'] = $context->instanceid;
|
||||
$params['courseid'] = $courseid;
|
||||
|
||||
return array($sql, $params);
|
||||
}
|
||||
@@ -166,18 +187,31 @@ class helper {
|
||||
* @return array list of graders.
|
||||
*/
|
||||
public static function get_graders($courseid) {
|
||||
global $DB;
|
||||
global $DB, $USER;
|
||||
|
||||
$groupjoinsql = $groupwheresql = '';
|
||||
$inparams = [];
|
||||
$groupmode = groups_get_course_groupmode(get_course($courseid));
|
||||
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', \context_course::instance($courseid))) {
|
||||
// Fetch the groups that the user can see.
|
||||
$groups = groups_get_all_groups($courseid, $USER->id, 0, 'g.id');
|
||||
// Add join condition to include users that only belong to the same group as the user.
|
||||
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED, 'gid', true, 0);
|
||||
$groupjoinsql = " JOIN {groups_members} gm ON gm.userid = u.id ";
|
||||
$groupwheresql = " AND gm.groupid $insql ";
|
||||
}
|
||||
|
||||
$ufields = get_all_user_name_fields(true, 'u');
|
||||
$sql = "SELECT u.id, $ufields
|
||||
FROM {user} u
|
||||
JOIN {grade_grades_history} ggh ON ggh.usermodified = u.id
|
||||
JOIN {grade_items} gi ON gi.id = ggh.itemid
|
||||
WHERE gi.courseid = :courseid
|
||||
$groupjoinsql
|
||||
WHERE gi.courseid = :courseid $groupwheresql
|
||||
GROUP BY u.id, $ufields
|
||||
ORDER BY u.lastname ASC, u.firstname ASC";
|
||||
|
||||
$graders = $DB->get_records_sql($sql, array('courseid' => $courseid));
|
||||
$graders = $DB->get_records_sql($sql, array('courseid' => $courseid) + $inparams);
|
||||
$return = array(0 => get_string('allgraders', 'gradereport_history'));
|
||||
foreach ($graders as $grader) {
|
||||
$return[$grader->id] = fullname($grader);
|
||||
|
||||
@@ -337,7 +337,7 @@ class tablelog extends \table_sql implements \renderable {
|
||||
* @return array containing sql to use and an array of params.
|
||||
*/
|
||||
protected function get_filters_sql_and_params() {
|
||||
global $DB;
|
||||
global $DB, $USER;
|
||||
|
||||
$coursecontext = $this->context;
|
||||
$filter = 'gi.courseid = :courseid';
|
||||
@@ -368,6 +368,16 @@ class tablelog extends \table_sql implements \renderable {
|
||||
$params += array('grader' => $this->filters->grader);
|
||||
}
|
||||
|
||||
// If the course is separate group mode and the current user is not allowed to see all groups make sure
|
||||
// that we display only users from the same groups as current user.
|
||||
$groupmode = get_course($coursecontext->instanceid)->groupmode;
|
||||
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $coursecontext)) {
|
||||
$groupids = array_column(groups_get_all_groups($coursecontext->instanceid, $USER->id, 0, 'g.id'), 'id');
|
||||
list($gsql, $gparams) = $DB->get_in_or_equal($groupids, SQL_PARAMS_NAMED, 'gmuparam', true, 0);
|
||||
$filter .= " AND EXISTS (SELECT 1 FROM {groups_members} gmu WHERE gmu.userid=ggh.userid AND gmu.groupid $gsql)";
|
||||
$params += $gparams;
|
||||
}
|
||||
|
||||
return array($filter, $params);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,12 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$u5 = $this->getDataGenerator()->create_user();
|
||||
$grader1 = $this->getDataGenerator()->create_user();
|
||||
$grader2 = $this->getDataGenerator()->create_user();
|
||||
self::getDataGenerator()->enrol_user($grader1->id, $c1->id, 'teacher');
|
||||
self::getDataGenerator()->enrol_user($grader2->id, $c1->id, 'teacher');
|
||||
self::getDataGenerator()->enrol_user($u2->id, $c1->id, 'student');
|
||||
self::getDataGenerator()->enrol_user($u3->id, $c1->id, 'student');
|
||||
self::getDataGenerator()->enrol_user($u4->id, $c1->id, 'student');
|
||||
self::getDataGenerator()->enrol_user($u5->id, $c1->id, 'student');
|
||||
|
||||
// Modules.
|
||||
$c1m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c1));
|
||||
@@ -65,6 +71,8 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign');
|
||||
$grades = array();
|
||||
|
||||
$this->setUser($grader1);
|
||||
|
||||
$gi = grade_item::fetch($giparams + array('iteminstance' => $c1m1->id));
|
||||
$grades['c1m1u1'] = $this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id,
|
||||
'timemodified' => time() - 3600));
|
||||
@@ -163,6 +171,20 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$this->assertEquals(null, $results[$grades['c2m2u1a']->id]->prevgrade);
|
||||
$this->assertEquals($grades['c2m2u1a']->finalgrade, $results[$grades['c2m2u1c']->id]->prevgrade);
|
||||
$this->assertEquals($grades['c2m2u1c']->finalgrade, $results[$grades['c2m2u1e']->id]->prevgrade);
|
||||
|
||||
// Put course in separate groups mode, add grader1 and two students to the same group.
|
||||
$c1->groupmode = SEPARATEGROUPS;
|
||||
update_course($c1);
|
||||
$this->assertFalse(has_capability('moodle/site:accessallgroups', \context_course::instance($c1->id)));
|
||||
$g1 = self::getDataGenerator()->create_group(['courseid' => $c1->id, 'name' => 'g1']);
|
||||
self::getDataGenerator()->create_group_member(['groupid' => $g1->id, 'userid' => $grader1->id]);
|
||||
self::getDataGenerator()->create_group_member(['groupid' => $g1->id, 'userid' => $u1->id]);
|
||||
self::getDataGenerator()->create_group_member(['groupid' => $g1->id, 'userid' => $u2->id]);
|
||||
$this->assertEquals(2, $this->get_tablelog_results($c1ctx, array(), true));
|
||||
|
||||
// Grader2 is not in any groups.
|
||||
$this->setUser($grader2);
|
||||
$this->assertEquals(0, $this->get_tablelog_results($c1ctx, array(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,6 +241,118 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$this->assertEquals(1, \gradereport_history\helper::get_users_count($c1ctx, 'c'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider method for \gradereport_history_report_testcase::test_get_users_with_groups()
|
||||
*/
|
||||
public function get_users_provider() {
|
||||
return [
|
||||
'Visible groups, non-editing teacher, not in any group' => [
|
||||
VISIBLEGROUPS, 'teacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
|
||||
],
|
||||
'Visible groups, non-editing teacher' => [
|
||||
VISIBLEGROUPS, 'teacher', [], ['s1', 's2', 's3', 's4', 's5']
|
||||
],
|
||||
'Visible groups, editing teacher' => [
|
||||
VISIBLEGROUPS, 'editingteacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
|
||||
],
|
||||
'Separate groups, non-editing teacher' => [
|
||||
SEPARATEGROUPS, 'teacher', ['g1', 'g2'], ['s1', 's2']
|
||||
],
|
||||
'Separate groups, non-editing teacher, not in any group' => [
|
||||
SEPARATEGROUPS, 'teacher', [], []
|
||||
],
|
||||
'Separate groups, non-editing teacher and student share two groups' => [
|
||||
SEPARATEGROUPS, 'teacher', ['g4', 'g5'], ['s5']
|
||||
],
|
||||
'Separate groups, editing teacher' => [
|
||||
SEPARATEGROUPS, 'editingteacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for helper::get_users() with course group mode set.
|
||||
*
|
||||
* @dataProvider get_users_provider
|
||||
* @param $groupmode
|
||||
* @param $teacherrole
|
||||
* @param $teachergroups
|
||||
* @param $expectedusers
|
||||
*/
|
||||
public function test_get_users_with_groups($groupmode, $teacherrole, $teachergroups, $expectedusers) {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$generator = $this->getDataGenerator();
|
||||
|
||||
// Create a test course.
|
||||
$course = $generator->create_course(['groupmode' => $groupmode]);
|
||||
|
||||
// Create an assignment module.
|
||||
$assign = $generator->create_module('assign', ['course' => $course]);
|
||||
|
||||
// Fetch roles.
|
||||
$role = $DB->get_record('role', ['shortname' => $teacherrole], '*', MUST_EXIST);
|
||||
$studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
|
||||
|
||||
// Create users.
|
||||
$t1 = $generator->create_user(['username' => 't1', 'email' => 't1@example.com']);
|
||||
$s1 = $generator->create_user(['username' => 's1', 'email' => 's1@example.com']);
|
||||
$s2 = $generator->create_user(['username' => 's2', 'email' => 's2@example.com']);
|
||||
$s3 = $generator->create_user(['username' => 's3', 'email' => 's3@example.com']);
|
||||
$s4 = $generator->create_user(['username' => 's4', 'email' => 's4@example.com']);
|
||||
$s5 = $generator->create_user(['username' => 's5', 'email' => 's5@example.com']);
|
||||
|
||||
// Enrol users.
|
||||
$generator->enrol_user($t1->id, $course->id, $role->id);
|
||||
$generator->enrol_user($s1->id, $course->id, $studentrole->id);
|
||||
$generator->enrol_user($s2->id, $course->id, $studentrole->id);
|
||||
$generator->enrol_user($s3->id, $course->id, $studentrole->id);
|
||||
$generator->enrol_user($s4->id, $course->id, $studentrole->id);
|
||||
$generator->enrol_user($s5->id, $course->id, $studentrole->id);
|
||||
|
||||
// Create groups.
|
||||
$groups = [];
|
||||
$groups['g1'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g1']);
|
||||
$groups['g2'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g2']);
|
||||
$groups['g3'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g3']);
|
||||
$groups['g4'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g4']);
|
||||
$groups['g5'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g5']);
|
||||
|
||||
// Add teacher to the assigned groups.
|
||||
foreach ($teachergroups as $groupname) {
|
||||
$group = $groups[$groupname];
|
||||
$generator->create_group_member(['groupid' => $group->id, 'userid' => $t1->id]);
|
||||
}
|
||||
|
||||
// Add students to groups.
|
||||
$generator->create_group_member(['groupid' => $groups['g1']->id, 'userid' => $s1->id]);
|
||||
$generator->create_group_member(['groupid' => $groups['g2']->id, 'userid' => $s2->id]);
|
||||
$generator->create_group_member(['groupid' => $groups['g3']->id, 'userid' => $s3->id]);
|
||||
$generator->create_group_member(['groupid' => $groups['g4']->id, 'userid' => $s5->id]);
|
||||
$generator->create_group_member(['groupid' => $groups['g5']->id, 'userid' => $s5->id]);
|
||||
|
||||
// Creating grade history for the students.
|
||||
$gi = grade_item::fetch(['iteminstance' => $assign->id, 'itemtype' => 'mod', 'itemmodule' => 'assign']);
|
||||
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s1->id]);
|
||||
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s2->id]);
|
||||
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s3->id]);
|
||||
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s4->id]);
|
||||
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s5->id]);
|
||||
|
||||
// Log in as the teacher.
|
||||
$this->setUser($t1);
|
||||
|
||||
// Fetch the users.
|
||||
$users = \gradereport_history\helper::get_users(context_course::instance($course->id));
|
||||
// Confirm that the number of users fetched is the same as the count of expected users.
|
||||
$this->assertCount(count($expectedusers), $users);
|
||||
foreach ($users as $user) {
|
||||
// Confirm that each user returned is in the list of expected users.
|
||||
$this->assertTrue(in_array($user->username, $expectedusers));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the get graders helper method.
|
||||
*/
|
||||
@@ -228,9 +362,11 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
// Making the setup.
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c2 = $this->getDataGenerator()->create_course();
|
||||
$c3 = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS]);
|
||||
|
||||
$c1m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c1));
|
||||
$c2m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c2));
|
||||
$c3m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c3));
|
||||
|
||||
// Users.
|
||||
$u1 = $this->getDataGenerator()->create_user(array('firstname' => 'Eric', 'lastname' => 'Cartman'));
|
||||
@@ -238,6 +374,12 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$u3 = $this->getDataGenerator()->create_user(array('firstname' => 'Kyle', 'lastname' => 'Broflovski'));
|
||||
$u4 = $this->getDataGenerator()->create_user(array('firstname' => 'Kenny', 'lastname' => 'McCormick'));
|
||||
|
||||
foreach ([$c1, $c2, $c3] as $course) {
|
||||
foreach ([$u1, $u2, $u3, $u4] as $user) {
|
||||
self::getDataGenerator()->enrol_user($user->id, $course->id, 'student');
|
||||
}
|
||||
}
|
||||
|
||||
// Creating grade history for some users.
|
||||
$gi = grade_item::fetch(array('iteminstance' => $c1m1->id, 'itemtype' => 'mod', 'itemmodule' => 'assign'));
|
||||
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id, 'usermodified' => $u1->id));
|
||||
@@ -247,6 +389,10 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$gi = grade_item::fetch(array('iteminstance' => $c2m1->id, 'itemtype' => 'mod', 'itemmodule' => 'assign'));
|
||||
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id, 'usermodified' => $u4->id));
|
||||
|
||||
$gi = grade_item::fetch(array('iteminstance' => $c3m1->id, 'itemtype' => 'mod', 'itemmodule' => 'assign'));
|
||||
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id, 'usermodified' => $u1->id));
|
||||
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u2->id, 'usermodified' => $u2->id));
|
||||
|
||||
// Checking fetching some users.
|
||||
$graders = \gradereport_history\helper::get_graders($c1->id);
|
||||
$this->assertCount(4, $graders); // Including "all graders" .
|
||||
@@ -256,6 +402,17 @@ class gradereport_history_report_testcase extends advanced_testcase {
|
||||
$graders = \gradereport_history\helper::get_graders($c2->id);
|
||||
$this->assertCount(2, $graders); // Including "all graders" .
|
||||
$this->assertArrayHasKey($u4->id, $graders);
|
||||
|
||||
// Third course is in separate groups mode. Only graders from the same group will be returned.
|
||||
$g = self::getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'g1']);
|
||||
self::getDataGenerator()->create_group_member(['groupid' => $g->id, 'userid' => $u1->id]);
|
||||
self::getDataGenerator()->create_group_member(['groupid' => $g->id, 'userid' => $u2->id]);
|
||||
$this->setUser($u1);
|
||||
$graders = \gradereport_history\helper::get_graders($c3->id);
|
||||
$this->assertCount(3, $graders); // Including "all graders" .
|
||||
$this->setUser($u3);
|
||||
$graders = \gradereport_history\helper::get_graders($c3->id);
|
||||
$this->assertCount(1, $graders); // Including "all graders" .
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
Bulk insert attribute.
|
||||
}}
|
||||
<div class="enable">
|
||||
<input type="checkbox" name="{{applyname}}" value="1" id="{{applyname}}">
|
||||
<input type="checkbox" name="{{applyname}}" value="1" id="{{applyname}}" class="ml-0">
|
||||
<label for="{{applyname}}">{{applylabel}}</label>
|
||||
</div>
|
||||
<fieldset class="form-inline">
|
||||
<legend class="accesshide">{{label}}</legend>
|
||||
<label for="{{menuname}}">{{menulabel}}</label>
|
||||
<select name="{{menuname}}" id="{{menuname}}" class="form-control">
|
||||
<select name="{{menuname}}" id="{{menuname}}" class="form-control custom-select">
|
||||
{{#menuoptions}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/menuoptions}}
|
||||
|
||||
+2
-2
@@ -171,7 +171,7 @@ if ($editform->is_cancelled()) {
|
||||
$table->width = '90%';
|
||||
}
|
||||
$table->data = array();
|
||||
|
||||
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
|
||||
foreach ($groups as $group) {
|
||||
$line = array();
|
||||
if (groups_get_group_by_name($courseid, $group['name'])) {
|
||||
@@ -183,7 +183,7 @@ if ($editform->is_cancelled()) {
|
||||
if ($data->allocateby != 'no') {
|
||||
$unames = array();
|
||||
foreach ($group['members'] as $user) {
|
||||
$unames[] = fullname($user, true);
|
||||
$unames[] = fullname($user, $viewfullnames);
|
||||
}
|
||||
$line[] = implode(', ', $unames);
|
||||
$line[] = count($group['members']);
|
||||
|
||||
@@ -77,8 +77,10 @@ class user_groups_editable extends \core\output\inplace_editable {
|
||||
foreach ($coursegroups as $group) {
|
||||
$options[$group->id] = format_string($group->name, true, ['context' => $this->context]);
|
||||
}
|
||||
$this->edithint = get_string('editusersgroupsa', 'group', fullname($user));
|
||||
$this->editlabel = get_string('editusersgroupsa', 'group', fullname($user));
|
||||
|
||||
$fullname = fullname($user, has_capability('moodle/site:viewfullnames', $this->context));
|
||||
$this->edithint = get_string('editusersgroupsa', 'group', $fullname);
|
||||
$this->editlabel = get_string('editusersgroupsa', 'group', $fullname);
|
||||
|
||||
$attributes = ['multiple' => true];
|
||||
$this->set_type_autocomplete($options, $attributes);
|
||||
|
||||
@@ -556,7 +556,8 @@ class core_group_external extends external_api {
|
||||
require_capability('moodle/course:managegroups', $context);
|
||||
|
||||
if (!groups_remove_member_allowed($group, $user)) {
|
||||
throw new moodle_exception('errorremovenotpermitted', 'group', '', fullname($user));
|
||||
$fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
|
||||
throw new moodle_exception('errorremovenotpermitted', 'group', '', $fullname);
|
||||
}
|
||||
groups_remove_member($group, $user);
|
||||
}
|
||||
|
||||
+8
-2
@@ -81,6 +81,9 @@ switch ($action) {
|
||||
case 'ajax_getmembersingroup':
|
||||
$roles = array();
|
||||
if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, ' . get_all_user_name_fields(true, 'u'))) {
|
||||
|
||||
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
|
||||
|
||||
foreach($groupmemberroles as $roleid=>$roledata) {
|
||||
$shortroledata = new stdClass();
|
||||
$shortroledata->name = $roledata->name;
|
||||
@@ -88,7 +91,7 @@ switch ($action) {
|
||||
foreach($roledata->users as $member) {
|
||||
$shortmember = new stdClass();
|
||||
$shortmember->id = $member->id;
|
||||
$shortmember->name = fullname($member, true);
|
||||
$shortmember->name = fullname($member, $viewfullnames);
|
||||
$shortroledata->users[] = $shortmember;
|
||||
}
|
||||
$roles[] = $shortroledata;
|
||||
@@ -190,12 +193,15 @@ $members = array();
|
||||
if ($singlegroup) {
|
||||
$usernamefields = get_all_user_name_fields(true, 'u');
|
||||
if ($groupmemberroles = groups_get_members_by_role(reset($groupids), $courseid, 'u.id, ' . $usernamefields)) {
|
||||
|
||||
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
|
||||
|
||||
foreach ($groupmemberroles as $roleid => $roledata) {
|
||||
$users = array();
|
||||
foreach ($roledata->users as $member) {
|
||||
$users[] = (object)[
|
||||
'value' => $member->id,
|
||||
'text' => fullname($member, true)
|
||||
'text' => fullname($member, $viewfullnames)
|
||||
];
|
||||
}
|
||||
$members[] = (object)[
|
||||
|
||||
+3
-1
@@ -248,9 +248,11 @@ foreach ($members as $gpgid=>$groupdata) {
|
||||
$line[] = html_writer::tag('span', $name, array('class' => 'group_hoverdescription', 'data-groupid' => $gpid));
|
||||
$hoverevents[$gpid] = get_string('descriptiona', null, $jsdescription);
|
||||
}
|
||||
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
|
||||
$fullnames = array();
|
||||
foreach ($users as $user) {
|
||||
$fullnames[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&course='.$course->id.'">'.fullname($user, true).'</a>';
|
||||
$fullnames[] = html_writer::link(new moodle_url('/user/view.php', ['id' => $user->id, 'course' => $course->id]),
|
||||
fullname($user, $viewfullnames));
|
||||
}
|
||||
$line[] = implode(', ', $fullnames);
|
||||
$line[] = count($users);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'ar';
|
||||
$string['thislanguage'] = 'بالعربي workplace';
|
||||
@@ -46,7 +46,7 @@ $string['downloadedfilecheckfailed'] = 'Ha fallat la comprovació del fitxer bai
|
||||
$string['invalidmd5'] = 'L\'md5 no és vàlid. Torneu a provar-ho';
|
||||
$string['missingrequiredfield'] = 'Falta algun camp necessari';
|
||||
$string['remotedownloaderror'] = '<p>No s\'ha pogut baixar el component al vostre servidor. Verifiqueu els paràmetres del servidor intermediari. Es recomana vivament l\'extensió cURL de PHP.</p>
|
||||
<p>Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació «{$a->dest}» del vostre servidor i descomprimir-lo allí.</p>';
|
||||
<p>Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació «{$a->dest}» del vostre servidor i descomprimir-lo allà.</p>';
|
||||
$string['wrongdestpath'] = 'El camí de destinació és erroni';
|
||||
$string['wrongsourcebase'] = 'L\'adreça (URL) base de la font és errònia';
|
||||
$string['wrongzipfilename'] = 'El nom del fitxer ZIP és erroni';
|
||||
|
||||
@@ -45,7 +45,7 @@ $string['datarootpermission'] = 'Zugriffsrechte zum Datenverzeichnis';
|
||||
$string['dbprefix'] = 'Tabellen-Prefix';
|
||||
$string['dirroot'] = 'Moodle-Verzeichnis';
|
||||
$string['environmenthead'] = 'Installationsvoraussetzungen werden geprüft ...';
|
||||
$string['environmentsub2'] = 'Jede Version hat Mindestvoraussetzungen für der PHP-Version und für verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird eine vollständige Prüfung durchgeführt. Bitte fragen Sie den Administrator des Servers, wenn Sie mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommen.';
|
||||
$string['environmentsub2'] = 'Jede Version hat Mindestvoraussetzungen für der PHP-Version und für verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird eine vollständige Prüfung durchgeführt. Bitte fragen Sie die Administrator/innen des Servers, wenn Sie mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommen.';
|
||||
$string['errorsinenvironment'] = 'Fehler bei der Prüfung der Systemvoraussetzungen!';
|
||||
$string['installation'] = 'Installation';
|
||||
$string['langdownloaderror'] = 'Das Sprachpaket \'{$a}\' konnte nicht heruntergeladen werden. Die Installation wird in englischer Sprache fortgesetzt.';
|
||||
@@ -63,7 +63,7 @@ $string['pathserrcreatedataroot'] = 'Das Datenverzeichnis ({$a->dataroot}) kann
|
||||
$string['pathshead'] = 'Pfade bestätigen';
|
||||
$string['pathsrodataroot'] = 'Das Verzeichnis dataroot ist schreibgeschützt.';
|
||||
$string['pathsroparentdataroot'] = 'Das Verzeichnis ({$a->parent}) ist schreibgeschützt. Deswegen kann das Datenverzeichnis ({$a->dataroot}) vom Installer nicht angelegt werden.';
|
||||
$string['pathssubadmindir'] = 'Einige Webserver benutzen /admin als speziellen Link, um auf Einstellungsseiten oder Ähnliches zu verweisen. Unglücklicherweise kollidiert dies mit dem standardmäßigen Verzeichnis für die Moodle-Administration. Sie können dieses Problem beheben, indem Sie das Verzeichnis admin in Ihrer Moodle-Installation umbenennen und den neuen Namen hier eingeben (z.B. <em>moodleadmin</em>). Mit dieser Änderung werden alle Admin-Links korrigiert.';
|
||||
$string['pathssubadmindir'] = 'Einige Webserver benutzen /admin als speziellen Link, um auf Einstellungsseiten oder Ähnliches zu verweisen. Unglücklicherweise kollidiert dies mit dem Verzeichnis für die Moodle-Administration. Sie können dieses Problem beheben, indem Sie das Verzeichnis admin in Ihrer Moodle-Installation umbenennen und den neuen Namen hier eingeben (z.B. <em>moodleadmin</em>). Mit dieser Änderung werden alle Admin-Links korrigiert.';
|
||||
$string['pathssubdataroot'] = '<p>Sie benötigen einen Platz, wo Moodle hochgeladene Dateien abspeichern kann. </p><p>Dieses Verzeichnis muss Lese- und Schreibrechte für das Nutzerkonto besitzen, mit dem Ihr Webservers läuft (üblicherweise \'nobody\', \'apache\' oder \'www-data).</p><p> Außerdem sollte das Verzeichnis nicht direkt aus dem Internet erreichbar sein. </p><p>Das Intallationsskript wird versuchen, ein solches Verzeichnis zu erstellen, falls es nicht existiert.</p>';
|
||||
$string['pathssubdirroot'] = '<p>Vollständiger Pfad der Moodle-Installation.</p>';
|
||||
$string['pathssubwwwroot'] = '<p>Webadresse, die ein Nutzer im Browser eingibt, um auf Moodle zuzugreifen.</p><p> Es ist nicht möglich, über unterschiedliche Adressen auf Moodle zuzugreifen. Sollte Ihre Website mehrere öffentliche Adressen verwenden, so müssen Sie eine Adresse festlegen und für die übrigen Adressen dauerhafte Weiterleitungen dorthin einrichten.</p>
|
||||
|
||||
@@ -45,6 +45,6 @@ $string['downloadedfilecheckfailed'] = 'Αποτυχία ελέγχου αρχε
|
||||
$string['invalidmd5'] = 'Η μεταβλητή ελέγχου ήταν λανθασμένη - δοκιμάστε ξανά';
|
||||
$string['missingrequiredfield'] = 'Κάποιο απαιτούμενο πεδίο λείπει';
|
||||
$string['remotedownloaderror'] = '<p>Η λήψη του στοιχείου λογισμικού στον εξυπηρετητή σας απέτυχε. Παρακαλούμε επαληθεύστε τις ρυθμίσεις του διακομιστή μεσολάβησης (proxy)· η επέκταση PHP cURL συνιστάται θερμά.</p><br /><p>Πρέπει να κατεβάσετε το αρχείο <a href="{$a->url}">{$a->url}</a> χειροκίνητα, να το αντιγράψετε στο «{$a->dest}» στον εξυπηρετητή σας και να το αποσυμπιέσετε εκεί.</p>';
|
||||
$string['wrongdestpath'] = 'Λανθασμένη διαδρομή προορισμού (πλήρες όνομα).';
|
||||
$string['wrongdestpath'] = 'Λανθασμένο μονοπάτι προορισμού.';
|
||||
$string['wrongsourcebase'] = 'Λανθασμένη βάση πηγής URL.';
|
||||
$string['wrongzipfilename'] = 'Λανθασμένo όνομα αρχείου ZIP.';
|
||||
|
||||
@@ -70,12 +70,12 @@ $string['pathsroparentdataroot'] = 'Ο γονικός φάκελος ({$a->paren
|
||||
$string['pathssubadmindir'] = 'Κάποιοι λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin ως ειδική διεύθυνση URL για την πρόσβαση σε κάποιο πίνακα ελέγχου ή κάτι τέτοιο. Δυστυχώς αυτό έρχεται σε αντίθεση με την τυπική τοποθεσία των σελίδων διαχείρισης (admin) του Moodle. Αυτό μπορεί να διορθωθεί με την μετονομασία του admin φακέλου στην εγκατάστασή σας, και βάζοντας αυτό το καινούργιο όνομα εδώ. Για παράδειγμα: <em>moodleadmin</em>. Αυτό θα διορθώσει όλους τους συνδέσμους με το admin στην διεύθυνσή τους σε όλη την εγκατάσταση του Moodle σας.';
|
||||
$string['pathssubdataroot'] = '<p>Ένας φάκελος όπου το Moodle θα αποθηκεύει όλα τα ανεβασμένα από τους χρήστες αρχεία.</p> <p>Αυτος ο φάκελος θα πρέπει να είναι αναγνώσιμος ΚΑΙ ΕΓΓΡΑΨΙΜΟΣ από τον χρήστη του εξυπηρετητή ιστού (συνήθως «nobody» ή «apache»).</p> <p>Δεν πρέπει να είναι προσβάσιμος κατευθείαν από τον ιστό.</p> <p>Αν ο φάκελος δεν υπάρχει, η διαδικασία εγκατάστασης θα προσπαθήσει να τον δημιουργήσει.</p>';
|
||||
$string['pathssubdirroot'] = '<p>Η πλήρης διαδρομή του φακέλου που περιέχει τα αρχεία κώδικα του Moodle.</p>';
|
||||
$string['pathssubwwwroot'] = '<p>Η πλήρης διεύθυνση (ιστού) από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.</p>
|
||||
$string['pathssubwwwroot'] = '<p>Η πλήρης διεύθυνση από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.</p>
|
||||
<p>Δεν είναι δυνατόν να έχετε πρόβαση στο Moodle χρησιμοποιώντας πολλαπλές διευθύνσεις. Εάν ο ιστότοπος θα είναι προσβάσιμος μέσω πολλαπλών διευθύνσεων τότε επιλέξτε την ευκολότερη και εγκαταστήστε μια μόνιμη ανακατεύθυνση για καθεμία από τις άλλες διευθύνσεις.</p>
|
||||
<p>Εάν ο ιστότοπός σας είναι προσβάσιμος τόσο από το Διαδίκτυο όσο και από ένα εσωτερικό δίκτυο (που συχνά λέγεται intranet) τότε χρησιμοποιήστε εδώ την δημόσια διεύθυνση.</p>
|
||||
<p>Αν η τρέχουσα διεύθυνση δεν είναι σωστή, παρακαλούμε αλλάξτε την URL διεύθυνση στην γραμμή διευθύνσεων του περιηγητή σας και επανεκκινήστε την εγκατάσταση.</p>';
|
||||
$string['pathsunsecuredataroot'] = 'Η τοποθεσία του Φάκελου Δεδομένων δεν είναι ασφαλής';
|
||||
$string['pathswrongadmindir'] = 'Ο Φάκελος Admin δεν υπάρχει';
|
||||
$string['pathswrongadmindir'] = 'Ο φάκελος Admin δεν υπάρχει';
|
||||
$string['phpextension'] = 'Επέκταση {$a} της PHP';
|
||||
$string['phpversion'] = 'Έκδοση της PHP';
|
||||
$string['phpversionhelp'] = 'p>Το Moodle απαιτεί η έκδοση της PHP να είναι τουλάχιστον 5.6.5 ή 7.1 (η 7.0.x έχει κάποιους περιορισμούς στη μηχανή).</p>
|
||||
|
||||
@@ -31,4 +31,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'es';
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Español para la Empresa';
|
||||
|
||||
@@ -31,4 +31,5 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'he';
|
||||
$string['thisdirection'] = 'rtl';
|
||||
$string['thislanguage'] = 'עברית בתי־ספר';
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['clianswerno'] = 'ל';
|
||||
$string['cliansweryes'] = 'כ';
|
||||
$string['cliincorrectvalueretry'] = 'ערך לא תקין, נסו שוב בבקשה';
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['parentlanguage'] = 'ja';
|
||||
$string['thislanguage'] = 'Workplace準拠の日本語';
|
||||
@@ -30,4 +30,4 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['thislanguage'] = 'myanma bhasa';
|
||||
$string['thislanguage'] = 'ဗမာစာ';
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['thislanguage'] = 'Afaan Oromoo';
|
||||
+12
-10
@@ -60,7 +60,7 @@ $string['allowindexingexceptlogin'] = 'Everywhere except login and signup pages'
|
||||
$string['allowindexingnowhere'] = 'Nowhere';
|
||||
$string['allowusermailcharset'] = 'Allow user to select character set';
|
||||
$string['allowframembedding'] = 'Allow frame embedding';
|
||||
$string['allowframembedding_help'] = 'If enabled, this site may be embedded in a frame in a remote system, as recommended when using the \'Publish as LTI tool\' enrolment plugin. Otherwise, it is recommended to leave frame embedding disabled for security reasons.<br />Please, note also that for the mobile app this setting is ignored and frame embedding is always allowed.';
|
||||
$string['allowframembedding_help'] = 'If enabled, this site may be embedded in a frame in a remote system, as recommended when using the \'Publish as LTI tool\' enrolment plugin. Otherwise, it is recommended to leave frame embedding disabled for security reasons. Please note that for the mobile app this setting is ignored and frame embedding is always allowed.';
|
||||
$string['allowguestmymoodle'] = 'Allow guest access to Dashboard';
|
||||
$string['allowobjectembed'] = 'Allow EMBED and OBJECT tags';
|
||||
$string['allowthemechangeonurl'] = 'Allow theme changes in the URL';
|
||||
@@ -183,15 +183,15 @@ $string['configcourseswithsummarieslimit'] = 'The maximum number of courses to d
|
||||
$string['configcronclionly'] = 'Running the cron from a web browser can expose privileged information to anonymous users. Thus it is recommended to only run the cron from the command line or set a cron password for remote access.';
|
||||
$string['configcronremotepassword'] = 'This means that the cron.php script cannot be run from a web browser without supplying the password using the following form of URL:<pre> https://site.example.com/admin/cron.php?password=opensesame </pre>If this is left empty, no password is required.';
|
||||
$string['configcurlcache'] = 'Time-to-live for cURL cache, in seconds.';
|
||||
$string['configcustommenuitems'] = 'You can configure a custom menu here to be shown by themes. Each line consists of some menu text, a link URL (optional), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. Lines starting with a hyphen will appear as menu items in the previous top level menu, and dividers can be used by adding a line of one or more # characters where desired. For example:
|
||||
$string['configcustommenuitems'] = 'A custom menu may be configured here. Enter each menu item on a new line with format: menu text, a link URL (optional, not for a top menu item with sub-items), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. Lines starting with a hyphen will appear as menu items in the previous top level menu and ### makes a divider. For example:
|
||||
<pre>
|
||||
Moodle community|https://moodle.org
|
||||
-Moodle free support|https://moodle.org/support
|
||||
-Moodle Docs|https://docs.moodle.org|Moodle Docs
|
||||
-German Moodle Docs|https://docs.moodle.org/de|Documentation in German|de
|
||||
Courses
|
||||
-All courses|/course/
|
||||
-Course search|/course/search.php
|
||||
-###
|
||||
-Moodle development|https://moodle.org/development
|
||||
Moodle.com|https://moodle.com/
|
||||
-FAQ|https://someurl.xyz/faq
|
||||
-Preguntas más frecuentes|https://someurl.xyz/pmf||es
|
||||
Mobile app|https://someurl.xyz/app|Download our app
|
||||
</pre>';
|
||||
$string['configcustomusermenuitems'] = 'You can configure the contents of the user menu (with the exception of the log out link, which is automatically added). Each line is separated by pipe characters and consists of 1) a string in "langstringname, componentname" form or as plain text, 2) a URL, and 3) an icon either as a pix icon (in the folder pix with the structure [subfoldername]/[iconname], e.g. i/publish) or as a URL. Dividers can be used by adding a line of one or more # characters where desired.';
|
||||
$string['configdbsessions'] = 'If enabled, this setting will use the database to store information about current sessions. Note that changing this setting now will log out all current users (including you). If you are using MySQL please make sure that \'max_allowed_packet\' in my.cnf (or my.ini) is at least 4M. Other session drivers can be configured directly in config.php, see config-dist.php for more information. This option disappears if you specify session driver in config.php file.';
|
||||
@@ -230,7 +230,7 @@ $string['configenablerssfeedsdisabled2'] = 'RSS feeds are currently disabled at
|
||||
$string['configenablesafebrowserintegration'] = 'This adds the choice \'Require Safe Exam Browser\' to the \'Browser security\' field on the quiz settings form. See https://www.safeexambrowser.org/ for more information.';
|
||||
$string['configenablestats'] = 'If you choose \'yes\' here, Moodle\'s cronjob will process the logs and gather some statistics. Depending on the amount of traffic on your site, this can take awhile. If you enable this, you will be able to see some interesting graphs and statistics about each of your courses, or on a sitewide basis.';
|
||||
$string['configenabletrusttext'] = 'By default Moodle will always thoroughly clean text that comes from users to remove any possible bad scripts, media etc that could be a security risk. The Trusted Content system is a way of giving particular users that you trust the ability to include these advanced features in their content without interference. To enable this system, you need to first enable this setting, and then grant the Trusted Content permission to a specific Moodle role. Texts created or uploaded by such users will be marked as trusted and will not be cleaned before display.';
|
||||
$string['configenablewebservices'] = 'Web services enable other systems to log in to this Moodle and perform operations. For extra security this feature should be disabled unless you are really using it.';
|
||||
$string['configenablewebservices'] = 'Web services enable other systems, such as the Moodle app, to log in to the site and perform operations. For extra security, the setting should be disabled if you are not using the app, or an external tool/service that requires integration via web services.';
|
||||
$string['configenablewsdocumentation'] = 'Enable auto-generation of web services documentation. A user can access to his own documentation on his security keys page {$a}. It displays the documentation for the enabled protocols only.';
|
||||
$string['configerrorlevel'] = 'Choose the amount of PHP warnings that you want to be displayed. Normal is usually the best choice.';
|
||||
$string['configexportlookahead'] = 'Days to look ahead during export';
|
||||
@@ -319,6 +319,7 @@ $string['configrequestedstudentname'] = 'Word for student used in requested cour
|
||||
$string['configrequestedstudentsname'] = 'Word for students used in requested courses';
|
||||
$string['configrequestedteachername'] = 'Word for teacher used in requested courses';
|
||||
$string['configrequestedteachersname'] = 'Word for teachers used in requested courses';
|
||||
$string['configreverseproxyignore'] = 'If your server is behind multiple reverse proxies that append to the X-Forwarded-For header then you will need to specify a comma separated list of ip addresses or subnets of the reverse proxies to be ignored in order to find the users correct IP address.';
|
||||
$string['configuserquota'] = 'The maximum number of bytes that a user can store in their own private file area. {$a->bytes} bytes == {$a->displaysize}';
|
||||
$string['configsectioninterface'] = 'Interface';
|
||||
$string['configsectionmail'] = 'Mail';
|
||||
@@ -1043,6 +1044,7 @@ $string['restorernewroleid'] = 'Restorers\' role in courses';
|
||||
$string['restorernewroleid_help'] = 'If the user does not already have the permission to manage the newly restored course, the user is automatically assigned this role and enrolled if necessary. Select "None" if you do not want restorers to be able to manage every restored course.';
|
||||
$string['resultfilter'] = 'Filter by result';
|
||||
$string['reverseproxy'] = 'Reverse proxy';
|
||||
$string['reverseproxyignore'] = 'Ignore reverse proxies';
|
||||
$string['riskconfig'] = 'Users could change site configuration and behaviour';
|
||||
$string['riskconfigshort'] = 'Configuration risk';
|
||||
$string['riskdataloss'] = 'Users could destroy large amounts of content or information';
|
||||
@@ -1421,4 +1423,4 @@ $string['configloginhttps'] = 'Turning this on will make Moodle use a secure htt
|
||||
$string['loginhttps'] = 'Use HTTPS for logins';
|
||||
// Deprecated since Moodle 3.7.
|
||||
$string['allowblockstodock'] = 'Allow blocks to use the dock';
|
||||
$string['configallowblockstodock'] = 'If enabled and supported by the selected theme users can choose to move blocks to a special dock.';
|
||||
$string['configallowblockstodock'] = 'If enabled and supported by the selected theme users can choose to move blocks to a special dock.';
|
||||
|
||||
+1
-1
@@ -246,7 +246,7 @@ $string['criteria_5_help'] = 'Allows a badge to be awarded to users who have com
|
||||
$string['criteria_6'] = 'Profile completion';
|
||||
$string['criteria_6_help'] = 'Allows a badge to be awarded to users for completing certain fields in their profile. You can select from default and custom profile fields that are available to users. ';
|
||||
$string['criteria_7'] = 'Awarded badges';
|
||||
$string['criteria_7_help'] = 'Allows a badge to be awarded to users based on the other badges thay have earned.';
|
||||
$string['criteria_7_help'] = 'Allows a badge to be awarded to users based on other badges they have earned.';
|
||||
$string['criteria_8'] = 'Cohort membership';
|
||||
$string['criteria_8_help'] = 'Allows a badge to be awarded to users based on cohort membership.';
|
||||
$string['criteria_9'] = 'Competencies';
|
||||
|
||||
+10
-5
@@ -516,7 +516,7 @@ $string['displayonpage'] = 'Display on page';
|
||||
$string['dndcourse'] = 'You can drag and drop this course to alter its sorting or to move it to another category.';
|
||||
$string['dndenabled_inbox'] = 'You can drag and drop files here to add them.';
|
||||
$string['dndnotsupported'] = 'Drag and drop upload not supported';
|
||||
$string['dndnotsupported_help'] = 'Your browser does not support drag and drop upload.<br />This feature is available in all recent versions of Chrome, Firefox and Safari, as well as Internet Explorer v10 and above.';
|
||||
$string['dndnotsupported_help'] = 'Your browser does not support drag and drop upload. This feature is available in all recent versions of Chrome, Firefox and Safari, as well as Internet Explorer v10 and above.';
|
||||
$string['dndnotsupported_insentence'] = 'drag and drop not supported';
|
||||
$string['dnduploadwithoutcontent'] = 'This upload does not have any content';
|
||||
$string['dndworkingfiletextlink'] = 'Drag and drop files, text or links onto course sections to upload them';
|
||||
@@ -1229,14 +1229,18 @@ $string['moddoesnotsupporttype'] = 'Module {$a->modname} does not support upload
|
||||
$string['modhide'] = 'Hide';
|
||||
$string['modshow'] = 'Show';
|
||||
$string['modvisible'] = 'Availability';
|
||||
$string['modvisible_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).<br><br>
|
||||
$string['modvisible_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).
|
||||
|
||||
If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).';
|
||||
$string['modvisiblewithstealth'] = 'Availability';
|
||||
$string['modvisiblewithstealth_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).<br><br>
|
||||
If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).<br><br>
|
||||
$string['modvisiblewithstealth_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).
|
||||
|
||||
If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).
|
||||
|
||||
If the course contains many activities or resources, the course page may be simplified by setting the availability to \'Make available but not shown on course page\'. In this case, a link to the activity or resource must be provided from elsewhere, such as from a page resource. The activity would still be listed in the gradebook and other reports.';
|
||||
$string['modvisiblehiddensection'] = 'Availability';
|
||||
$string['modvisiblehiddensection_help'] = 'If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).<br><br>
|
||||
$string['modvisiblehiddensection_help'] = 'If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).
|
||||
|
||||
If the course contains many activities or resources, the course page may be simplified by setting the availability to \'Make available but not shown on course page\'. In this case, a link to the activity or resource must be provided from elsewhere, such as from a page resource. The activity would still be listed in the gradebook and other reports.';
|
||||
$string['moodlelogo'] = 'Moodle logo';
|
||||
$string['month'] = 'Month';
|
||||
@@ -1808,6 +1812,7 @@ $string['shortnameuser'] = 'User short name';
|
||||
$string['shortsitename'] = 'Short name for site (eg single word)';
|
||||
$string['show'] = 'Show';
|
||||
$string['showactions'] = 'Show actions';
|
||||
$string['showadvancededitor'] = 'Advanced';
|
||||
$string['showadvancedsettings'] = 'Show advanced settings';
|
||||
$string['showall'] = 'Show all {$a}';
|
||||
$string['showallcourses'] = 'Show all courses';
|
||||
|
||||
@@ -283,7 +283,7 @@ $string['questiondoesnotexist'] = 'This question does not exist';
|
||||
$string['questionname'] = 'Question name';
|
||||
$string['questionno'] = 'Question {$a}';
|
||||
$string['questionsaveerror'] = 'Errors occur during saving question - ({$a})';
|
||||
$string['questionsinuse'] = '(* Questions marked by an asterisk are already in use in some quizzes. These questions will not be deleted from these quizzes but only from the category list.)';
|
||||
$string['questionsinuse'] = '(* Questions marked with an asterisk are used somewhere, for example in a quiz. Therefore, if you proceed, these questions will not really be deleted, they will just be hidden.)';
|
||||
$string['questionsmovedto'] = 'Questions still in use moved to "{$a}" in the parent course category.';
|
||||
$string['questionsrescuedfrom'] = 'Questions saved from context {$a}.';
|
||||
$string['questionsrescuedfrominfo'] = 'These questions (some of which may be hidden) were saved when context {$a} was deleted because they are still used by some quizzes or other activities.';
|
||||
|
||||
+102
-26
@@ -27,7 +27,7 @@ $string['africa/abidjan'] = 'Africa/Abidjan';
|
||||
$string['africa/accra'] = 'Africa/Accra';
|
||||
$string['africa/addis_ababa'] = 'Africa/Addis_Ababa';
|
||||
$string['africa/algiers'] = 'Africa/Algiers';
|
||||
$string['africa/asmera'] = 'Africa/Asmera';
|
||||
$string['africa/asmara'] = 'Africa/Asmara';
|
||||
$string['africa/bamako'] = 'Africa/Bamako';
|
||||
$string['africa/bangui'] = 'Africa/Bangui';
|
||||
$string['africa/banjul'] = 'Africa/Banjul';
|
||||
@@ -48,6 +48,7 @@ $string['africa/freetown'] = 'Africa/Freetown';
|
||||
$string['africa/gaborone'] = 'Africa/Gaborone';
|
||||
$string['africa/harare'] = 'Africa/Harare';
|
||||
$string['africa/johannesburg'] = 'Africa/Johannesburg';
|
||||
$string['africa/juba'] = 'Africa/Juba';
|
||||
$string['africa/kampala'] = 'Africa/Kampala';
|
||||
$string['africa/khartoum'] = 'Africa/Khartoum';
|
||||
$string['africa/kigali'] = 'Africa/Kigali';
|
||||
@@ -71,32 +72,35 @@ $string['africa/nouakchott'] = 'Africa/Nouakchott';
|
||||
$string['africa/ouagadougou'] = 'Africa/Ouagadougou';
|
||||
$string['africa/porto-novo'] = 'Africa/Porto-Novo';
|
||||
$string['africa/sao_tome'] = 'Africa/Sao_Tome';
|
||||
$string['africa/timbuktu'] = 'Africa/Timbuktu';
|
||||
$string['africa/tripoli'] = 'Africa/Tripoli';
|
||||
$string['africa/tunis'] = 'Africa/Tunis';
|
||||
$string['africa/windhoek'] = 'Africa/Windhoek';
|
||||
$string['america/adak'] = 'America/Adak';
|
||||
$string['america/anguilla'] = 'America/Anguilla';
|
||||
$string['america/anchorage'] = 'America/Anchorage';
|
||||
$string['america/anguilla'] = 'America/Anguilla';
|
||||
$string['america/antigua'] = 'America/Antigua';
|
||||
$string['america/araguaina'] = 'America/Araguaina';
|
||||
$string['america/argentina/buenos_aires'] = 'America/Argentina/Buenos_Aires';
|
||||
$string['america/argentina/catamarca'] = 'America/Argentina/Catamarca';
|
||||
$string['america/argentina/comodrivadavia'] = 'America/Argentina/ComodRivadavia';
|
||||
$string['america/argentina/cordoba'] = 'America/Argentina/Cordoba';
|
||||
$string['america/argentina/jujuy'] = 'America/Argentina/Jujuy';
|
||||
$string['america/argentina/la_rioja'] = 'America/Argentina/La_Rioja';
|
||||
$string['america/argentina/mendoza'] = 'America/Argentina/Mendoza';
|
||||
$string['america/argentina/rio_gallegos'] = 'America/Argentina/Rio_Gallegos';
|
||||
$string['america/argentina/salta'] = 'America/Argentina/Salta';
|
||||
$string['america/argentina/san_juan'] = 'America/Argentina/San_Juan';
|
||||
$string['america/argentina/san_luis'] = 'America/Argentina/San_Luis';
|
||||
$string['america/argentina/tucuman'] = 'America/Argentina/Tucuman';
|
||||
$string['america/argentina/ushuaia'] = 'America/Argentina/Ushuaia';
|
||||
$string['america/aruba'] = 'America/Aruba';
|
||||
$string['america/asuncion'] = 'America/Asuncion';
|
||||
$string['america/atikokan'] = 'America/Atikokan';
|
||||
$string['america/bahia'] = 'America/Bahia';
|
||||
$string['america/bahia_banderas'] = 'America/Bahia_Banderas';
|
||||
$string['america/barbados'] = 'America/Barbados';
|
||||
$string['america/belem'] = 'America/Belem';
|
||||
$string['america/belize'] = 'America/Belize';
|
||||
$string['america/blanc-sablon'] = 'America/Blanc-Sablon';
|
||||
$string['america/boa_vista'] = 'America/Boa_Vista';
|
||||
$string['america/bogota'] = 'America/Bogota';
|
||||
$string['america/boise'] = 'America/Boise';
|
||||
@@ -106,7 +110,10 @@ $string['america/cancun'] = 'America/Cancun';
|
||||
$string['america/caracas'] = 'America/Caracas';
|
||||
$string['america/cayenne'] = 'America/Cayenne';
|
||||
$string['america/cayman'] = 'America/Cayman';
|
||||
$string['america/chicago'] = 'America/Chicago';
|
||||
$string['america/chihuahua'] = 'America/Chihuahua';
|
||||
$string['america/costa_rica'] = 'America/Costa_Rica';
|
||||
$string['america/creston'] = 'America/Creston';
|
||||
$string['america/cuiaba'] = 'America/Cuiaba';
|
||||
$string['america/curacao'] = 'America/Curacao';
|
||||
$string['america/danmarkshavn'] = 'America/Danmarkshavn';
|
||||
@@ -118,6 +125,7 @@ $string['america/dominica'] = 'America/Dominica';
|
||||
$string['america/edmonton'] = 'America/Edmonton';
|
||||
$string['america/eirunepe'] = 'America/Eirunepe';
|
||||
$string['america/el_salvador'] = 'America/El_Salvador';
|
||||
$string['america/fort_nelson'] = 'America/Fort_Nelson';
|
||||
$string['america/fortaleza'] = 'America/Fortaleza';
|
||||
$string['america/glace_bay'] = 'America/Glace_Bay';
|
||||
$string['america/godthab'] = 'America/Godthab';
|
||||
@@ -131,40 +139,50 @@ $string['america/guyana'] = 'America/Guyana';
|
||||
$string['america/halifax'] = 'America/Halifax';
|
||||
$string['america/havana'] = 'America/Havana';
|
||||
$string['america/hermosillo'] = 'America/Hermosillo';
|
||||
$string['america/chicago'] = 'America/Chicago';
|
||||
$string['america/chihuahua'] = 'America/Chihuahua';
|
||||
$string['america/indiana/indianapolis'] = 'America/Indiana/Indianapolis';
|
||||
$string['america/indiana/knox'] = 'America/Indiana/Knox';
|
||||
$string['america/indiana/marengo'] = 'America/Indiana/Marengo';
|
||||
$string['america/indianapolis'] = 'America/Indianapolis';
|
||||
$string['america/indiana/petersburg'] = 'America/Indiana/Petersburg';
|
||||
$string['america/indiana/tell_city'] = 'America/Indiana/Tell_City';
|
||||
$string['america/indiana/vevay'] = 'America/Indiana/Vevay';
|
||||
$string['america/indiana/vincennes'] = 'America/Indiana/Vincennes';
|
||||
$string['america/indiana/winamac'] = 'America/Indiana/Winamac';
|
||||
$string['america/inuvik'] = 'America/Inuvik';
|
||||
$string['america/iqaluit'] = 'America/Iqaluit';
|
||||
$string['america/jamaica'] = 'America/Jamaica';
|
||||
$string['america/juneau'] = 'America/Juneau';
|
||||
$string['america/kentucky/louisville'] = 'America/Kentucky/Louisville';
|
||||
$string['america/kentucky/monticello'] = 'America/Kentucky/Monticello';
|
||||
$string['america/kralendijk'] = 'America/Kralendijk';
|
||||
$string['america/la_paz'] = 'America/La_Paz';
|
||||
$string['america/lima'] = 'America/Lima';
|
||||
$string['america/los_angeles'] = 'America/Los_Angeles';
|
||||
$string['america/louisville'] = 'America/Louisville';
|
||||
$string['america/lower_princes'] = 'America/Lower_Princes';
|
||||
$string['america/maceio'] = 'America/Maceio';
|
||||
$string['america/managua'] = 'America/Managua';
|
||||
$string['america/manaus'] = 'America/Manaus';
|
||||
$string['america/marigot'] = 'America/Marigot';
|
||||
$string['america/martinique'] = 'America/Martinique';
|
||||
$string['america/matamoros'] = 'America/Matamoros';
|
||||
$string['america/mazatlan'] = 'America/Mazatlan';
|
||||
$string['america/menominee'] = 'America/Menominee';
|
||||
$string['america/merida'] = 'America/Merida';
|
||||
$string['america/metlakatla'] = 'America/Metlakatla';
|
||||
$string['america/mexico_city'] = 'America/Mexico_City';
|
||||
$string['america/miquelon'] = 'America/Miquelon';
|
||||
$string['america/moncton'] = 'America/Moncton';
|
||||
$string['america/monterrey'] = 'America/Monterrey';
|
||||
$string['america/montevideo'] = 'America/Montevideo';
|
||||
$string['america/montreal'] = 'America/Montreal';
|
||||
$string['america/montserrat'] = 'America/Montserrat';
|
||||
$string['america/nassau'] = 'America/Nassau';
|
||||
$string['america/new_york'] = 'America/New_York';
|
||||
$string['america/nipigon'] = 'America/Nipigon';
|
||||
$string['america/nome'] = 'America/Nome';
|
||||
$string['america/noronha'] = 'America/Noronha';
|
||||
$string['america/north_dakota/beulah'] = 'America/North_Dakota/Beulah';
|
||||
$string['america/north_dakota/center'] = 'America/North_Dakota/Center';
|
||||
$string['america/north_dakota/new_salem'] = 'America/North_Dakota/New_Salem';
|
||||
$string['america/ojinaga'] = 'America/Ojinaga';
|
||||
$string['america/panama'] = 'America/Panama';
|
||||
$string['america/pangnirtung'] = 'America/Pangnirtung';
|
||||
$string['america/paramaribo'] = 'America/Paramaribo';
|
||||
@@ -173,15 +191,20 @@ $string['america/port-au-prince'] = 'America/Port-au-Prince';
|
||||
$string['america/port_of_spain'] = 'America/Port_of_Spain';
|
||||
$string['america/porto_velho'] = 'America/Porto_Velho';
|
||||
$string['america/puerto_rico'] = 'America/Puerto_Rico';
|
||||
$string['america/punta_arenas'] = 'America/Punta_Arenas';
|
||||
$string['america/rainy_river'] = 'America/Rainy_River';
|
||||
$string['america/rankin_inlet'] = 'America/Rankin_Inlet';
|
||||
$string['america/recife'] = 'America/Recife';
|
||||
$string['america/regina'] = 'America/Regina';
|
||||
$string['america/resolute'] = 'America/Resolute';
|
||||
$string['america/rio_branco'] = 'America/Rio_Branco';
|
||||
$string['america/santarem'] = 'America/Santarem';
|
||||
$string['america/santiago'] = 'America/Santiago';
|
||||
$string['america/santo_domingo'] = 'America/Santo_Domingo';
|
||||
$string['america/sao_paulo'] = 'America/Sao_Paulo';
|
||||
$string['america/scoresbysund'] = 'America/Scoresbysund';
|
||||
$string['america/sitka'] = 'America/Sitka';
|
||||
$string['america/st_barthelemy'] = 'America/St_Barthelemy';
|
||||
$string['america/st_johns'] = 'America/St_Johns';
|
||||
$string['america/st_kitts'] = 'America/St_Kitts';
|
||||
$string['america/st_lucia'] = 'America/St_Lucia';
|
||||
@@ -202,12 +225,15 @@ $string['america/yellowknife'] = 'America/Yellowknife';
|
||||
$string['antarctica/casey'] = 'Antarctica/Casey';
|
||||
$string['antarctica/davis'] = 'Antarctica/Davis';
|
||||
$string['antarctica/dumontdurville'] = 'Antarctica/DumontDUrville';
|
||||
$string['antarctica/macquarie'] = 'Antarctica/Macquarie';
|
||||
$string['antarctica/mawson'] = 'Antarctica/Mawson';
|
||||
$string['antarctica/mcmurdo'] = 'Antarctica/McMurdo';
|
||||
$string['antarctica/palmer'] = 'Antarctica/Palmer';
|
||||
$string['antarctica/rothera'] = 'Antarctica/Rothera';
|
||||
$string['antarctica/syowa'] = 'Antarctica/Syowa';
|
||||
$string['antarctica/troll'] = 'Antarctica/Troll';
|
||||
$string['antarctica/vostok'] = 'Antarctica/Vostok';
|
||||
$string['arctic/longyearbyen'] = 'Arctic/Longyearbyen';
|
||||
$string['asia/aden'] = 'Asia/Aden';
|
||||
$string['asia/almaty'] = 'Asia/Almaty';
|
||||
$string['asia/amman'] = 'Asia/Amman';
|
||||
@@ -215,34 +241,39 @@ $string['asia/anadyr'] = 'Asia/Anadyr';
|
||||
$string['asia/aqtau'] = 'Asia/Aqtau';
|
||||
$string['asia/aqtobe'] = 'Asia/Aqtobe';
|
||||
$string['asia/ashgabat'] = 'Asia/Ashgabat';
|
||||
$string['asia/atyrau'] = 'Asia/Atyrau';
|
||||
$string['asia/baghdad'] = 'Asia/Baghdad';
|
||||
$string['asia/bahrain'] = 'Asia/Bahrain';
|
||||
$string['asia/baku'] = 'Asia/Baku';
|
||||
$string['asia/bangkok'] = 'Asia/Bangkok';
|
||||
$string['asia/barnaul'] = 'Asia/Barnaul';
|
||||
$string['asia/beirut'] = 'Asia/Beirut';
|
||||
$string['asia/bishkek'] = 'Asia/Bishkek';
|
||||
$string['asia/brunei'] = 'Asia/Brunei';
|
||||
$string['asia/calcutta'] = 'Asia/Calcutta';
|
||||
$string['asia/chita'] = 'Asia/Chita';
|
||||
$string['asia/choibalsan'] = 'Asia/Choibalsan';
|
||||
$string['asia/colombo'] = 'Asia/Colombo';
|
||||
$string['asia/damascus'] = 'Asia/Damascus';
|
||||
$string['asia/dhaka'] = 'Asia/Dhaka';
|
||||
$string['asia/dili'] = 'Asia/Dili';
|
||||
$string['asia/dubai'] = 'Asia/Dubai';
|
||||
$string['asia/dushanbe'] = 'Asia/Dushanbe';
|
||||
$string['asia/famagusta'] = 'Asia/Famagusta';
|
||||
$string['asia/gaza'] = 'Asia/Gaza';
|
||||
$string['asia/harbin'] = 'Asia/Harbin';
|
||||
$string['asia/hebron'] = 'Asia/Hebron';
|
||||
$string['asia/ho_chi_minh'] = 'Asia/Ho_Chi_Minh';
|
||||
$string['asia/hong_kong'] = 'Asia/Hong_Kong';
|
||||
$string['asia/hovd'] = 'Asia/Hovd';
|
||||
$string['asia/choibalsan'] = 'Asia/Choibalsan';
|
||||
$string['asia/chongqing'] = 'Asia/Chongqing';
|
||||
$string['asia/irkutsk'] = 'Asia/Irkutsk';
|
||||
$string['asia/jakarta'] = 'Asia/Jakarta';
|
||||
$string['asia/jayapura'] = 'Asia/Jayapura';
|
||||
$string['asia/jerusalem'] = 'Asia/Jerusalem';
|
||||
$string['asia/kabul'] = 'Asia/Kabul';
|
||||
$string['asia/kamchatka'] = 'Asia/Kamchatka';
|
||||
$string['asia/karachi'] = 'Asia/Karachi';
|
||||
$string['asia/kashgar'] = 'Asia/Kashgar';
|
||||
$string['asia/katmandu'] = 'Asia/Katmandu';
|
||||
$string['asia/kathmandu'] = 'Asia/Kathmandu';
|
||||
$string['asia/khandyga'] = 'Asia/Khandyga';
|
||||
$string['asia/kolkata'] = 'Asia/Kolkata';
|
||||
$string['asia/krasnoyarsk'] = 'Asia/Krasnoyarsk';
|
||||
$string['asia/kuala_lumpur'] = 'Asia/Kuala_Lumpur';
|
||||
$string['asia/kuching'] = 'Asia/Kuching';
|
||||
@@ -253,6 +284,7 @@ $string['asia/makassar'] = 'Asia/Makassar';
|
||||
$string['asia/manila'] = 'Asia/Manila';
|
||||
$string['asia/muscat'] = 'Asia/Muscat';
|
||||
$string['asia/nicosia'] = 'Asia/Nicosia';
|
||||
$string['asia/novokuznetsk'] = 'Asia/Novokuznetsk';
|
||||
$string['asia/novosibirsk'] = 'Asia/Novosibirsk';
|
||||
$string['asia/omsk'] = 'Asia/Omsk';
|
||||
$string['asia/oral'] = 'Asia/Oral';
|
||||
@@ -260,42 +292,47 @@ $string['asia/phnom_penh'] = 'Asia/Phnom_Penh';
|
||||
$string['asia/pontianak'] = 'Asia/Pontianak';
|
||||
$string['asia/pyongyang'] = 'Asia/Pyongyang';
|
||||
$string['asia/qatar'] = 'Asia/Qatar';
|
||||
$string['asia/qostanay'] = 'Asia/Qostanay';
|
||||
$string['asia/qyzylorda'] = 'Asia/Qyzylorda';
|
||||
$string['asia/rangoon'] = 'Asia/Rangoon';
|
||||
$string['asia/riyadh'] = 'Asia/Riyadh';
|
||||
$string['asia/saigon'] = 'Asia/Saigon';
|
||||
$string['asia/sakhalin'] = 'Asia/Sakhalin';
|
||||
$string['asia/samarkand'] = 'Asia/Samarkand';
|
||||
$string['asia/seoul'] = 'Asia/Seoul';
|
||||
$string['asia/shanghai'] = 'Asia/Shanghai';
|
||||
$string['asia/singapore'] = 'Asia/Singapore';
|
||||
$string['asia/srednekolymsk'] = 'Asia/Srednekolymsk';
|
||||
$string['asia/taipei'] = 'Asia/Taipei';
|
||||
$string['asia/tashkent'] = 'Asia/Tashkent';
|
||||
$string['asia/tbilisi'] = 'Asia/Tbilisi';
|
||||
$string['asia/tehran'] = 'Asia/Tehran';
|
||||
$string['asia/thimphu'] = 'Asia/Thimphu';
|
||||
$string['asia/tokyo'] = 'Asia/Tokyo';
|
||||
$string['asia/tomsk'] = 'Asia/Tomsk';
|
||||
$string['asia/ulaanbaatar'] = 'Asia/Ulaanbaatar';
|
||||
$string['asia/urumqi'] = 'Asia/Urumqi';
|
||||
$string['asia/ust-nera'] = 'Asia/Ust-Nera';
|
||||
$string['asia/vientiane'] = 'Asia/Vientiane';
|
||||
$string['asia/vladivostok'] = 'Asia/Vladivostok';
|
||||
$string['asia/yakutsk'] = 'Asia/Yakutsk';
|
||||
$string['asia/yangon'] = 'Asia/Yangon';
|
||||
$string['asia/yekaterinburg'] = 'Asia/Yekaterinburg';
|
||||
$string['asia/yerevan'] = 'Asia/Yerevan';
|
||||
$string['atlantic/azores'] = 'Atlantic/Azores';
|
||||
$string['atlantic/bermuda'] = 'Atlantic/Bermuda';
|
||||
$string['atlantic/canary'] = 'Atlantic/Canary';
|
||||
$string['atlantic/cape_verde'] = 'Atlantic/Cape_Verde';
|
||||
$string['atlantic/faeroe'] = 'Atlantic/Faeroe';
|
||||
$string['atlantic/faroe'] = 'Atlantic/Faroe';
|
||||
$string['atlantic/madeira'] = 'Atlantic/Madeira';
|
||||
$string['atlantic/reykjavik'] = 'Atlantic/Reykjavik';
|
||||
$string['atlantic/south_georgia'] = 'Atlantic/South_Georgia';
|
||||
$string['atlantic/stanley'] = 'Atlantic/Stanley';
|
||||
$string['atlantic/st_helena'] = 'Atlantic/St_Helena';
|
||||
$string['atlantic/stanley'] = 'Atlantic/Stanley';
|
||||
$string['australia/adelaide'] = 'Australia/Adelaide';
|
||||
$string['australia/brisbane'] = 'Australia/Brisbane';
|
||||
$string['australia/broken_hill'] = 'Australia/Broken_Hill';
|
||||
$string['australia/currie'] = 'Australia/Currie';
|
||||
$string['australia/darwin'] = 'Australia/Darwin';
|
||||
$string['australia/eucla'] = 'Australia/Eucla';
|
||||
$string['australia/hobart'] = 'Australia/Hobart';
|
||||
$string['australia/lindeman'] = 'Australia/Lindeman';
|
||||
$string['australia/lord_howe'] = 'Australia/Lord_Howe';
|
||||
@@ -304,51 +341,69 @@ $string['australia/perth'] = 'Australia/Perth';
|
||||
$string['australia/sydney'] = 'Australia/Sydney';
|
||||
$string['europe/amsterdam'] = 'Europe/Amsterdam';
|
||||
$string['europe/andorra'] = 'Europe/Andorra';
|
||||
$string['europe/astrakhan'] = 'Europe/Astrakhan';
|
||||
$string['europe/athens'] = 'Europe/Athens';
|
||||
$string['europe/belfast'] = 'Europe/Belfast';
|
||||
$string['europe/belgrade'] = 'Europe/Belgrade';
|
||||
$string['europe/berlin'] = 'Europe/Berlin';
|
||||
$string['europe/bratislava'] = 'Europe/Bratislava';
|
||||
$string['europe/brussels'] = 'Europe/Brussels';
|
||||
$string['europe/budapest'] = 'Europe/Budapest';
|
||||
$string['europe/bucharest'] = 'Europe/Bucharest';
|
||||
$string['europe/budapest'] = 'Europe/Budapest';
|
||||
$string['europe/busingen'] = 'Europe/Busingen';
|
||||
$string['europe/chisinau'] = 'Europe/Chisinau';
|
||||
$string['europe/copenhagen'] = 'Europe/Copenhagen';
|
||||
$string['europe/dublin'] = 'Europe/Dublin';
|
||||
$string['europe/gibraltar'] = 'Europe/Gibraltar';
|
||||
$string['europe/guernsey'] = 'Europe/Guernsey';
|
||||
$string['europe/helsinki'] = 'Europe/Helsinki';
|
||||
$string['europe/chisinau'] = 'Europe/Chisinau';
|
||||
$string['europe/isle_of_man'] = 'Europe/Isle_of_Man';
|
||||
$string['europe/istanbul'] = 'Europe/Istanbul';
|
||||
$string['europe/jersey'] = 'Europe/Jersey';
|
||||
$string['europe/kaliningrad'] = 'Europe/Kaliningrad';
|
||||
$string['europe/kiev'] = 'Europe/Kiev';
|
||||
$string['europe/kirov'] = 'Europe/Kirov';
|
||||
$string['europe/lisbon'] = 'Europe/Lisbon';
|
||||
$string['europe/ljubljana'] = 'Europe/Ljubljana';
|
||||
$string['europe/london'] = 'Europe/London';
|
||||
$string['europe/luxembourg'] = 'Europe/Luxembourg';
|
||||
$string['europe/madrid'] = 'Europe/Madrid';
|
||||
$string['europe/malta'] = 'Europe/Malta';
|
||||
$string['europe/mariehamn'] = 'Europe/Mariehamn';
|
||||
$string['europe/minsk'] = 'Europe/Minsk';
|
||||
$string['europe/monaco'] = 'Europe/Monaco';
|
||||
$string['europe/moscow'] = 'Europe/Moscow';
|
||||
$string['europe/oslo'] = 'Europe/Oslo';
|
||||
$string['europe/paris'] = 'Europe/Paris';
|
||||
$string['europe/podgorica'] = 'Europe/Podgorica';
|
||||
$string['europe/prague'] = 'Europe/Prague';
|
||||
$string['europe/riga'] = 'Europe/Riga';
|
||||
$string['europe/rome'] = 'Europe/Rome';
|
||||
$string['europe/samara'] = 'Europe/Samara';
|
||||
$string['europe/san_marino'] = 'Europe/San_Marino';
|
||||
$string['europe/sarajevo'] = 'Europe/Sarajevo';
|
||||
$string['europe/saratov'] = 'Europe/Saratov';
|
||||
$string['europe/simferopol'] = 'Europe/Simferopol';
|
||||
$string['europe/skopje'] = 'Europe/Skopje';
|
||||
$string['europe/sofia'] = 'Europe/Sofia';
|
||||
$string['europe/stockholm'] = 'Europe/Stockholm';
|
||||
$string['europe/tallinn'] = 'Europe/Tallinn';
|
||||
$string['europe/tirane'] = 'Europe/Tirane';
|
||||
$string['europe/ulyanovsk'] = 'Europe/Ulyanovsk';
|
||||
$string['europe/uzhgorod'] = 'Europe/Uzhgorod';
|
||||
$string['europe/vaduz'] = 'Europe/Vaduz';
|
||||
$string['europe/vatican'] = 'Europe/Vatican';
|
||||
$string['europe/vienna'] = 'Europe/Vienna';
|
||||
$string['europe/vilnius'] = 'Europe/Vilnius';
|
||||
$string['europe/volgograd'] = 'Europe/Volgograd';
|
||||
$string['europe/warsaw'] = 'Europe/Warsaw';
|
||||
$string['europe/zagreb'] = 'Europe/Zagreb';
|
||||
$string['europe/zaporozhye'] = 'Europe/Zaporozhye';
|
||||
$string['europe/zurich'] = 'Europe/Zurich';
|
||||
$string['indian/antananarivo'] = 'Indian/Antananarivo';
|
||||
$string['indian/comoro'] = 'Indian/Comoro';
|
||||
$string['indian/chagos'] = 'Indian/Chagos';
|
||||
$string['indian/christmas'] = 'Indian/Christmas';
|
||||
$string['indian/cocos'] = 'Indian/Cocos';
|
||||
$string['indian/comoro'] = 'Indian/Comoro';
|
||||
$string['indian/kerguelen'] = 'Indian/Kerguelen';
|
||||
$string['indian/mahe'] = 'Indian/Mahe';
|
||||
$string['indian/maldives'] = 'Indian/Maldives';
|
||||
@@ -357,6 +412,9 @@ $string['indian/mayotte'] = 'Indian/Mayotte';
|
||||
$string['indian/reunion'] = 'Indian/Reunion';
|
||||
$string['pacific/apia'] = 'Pacific/Apia';
|
||||
$string['pacific/auckland'] = 'Pacific/Auckland';
|
||||
$string['pacific/bougainville'] = 'Pacific/Bougainville';
|
||||
$string['pacific/chatham'] = 'Pacific/Chatham';
|
||||
$string['pacific/chuuk'] = 'Pacific/Chuuk';
|
||||
$string['pacific/easter'] = 'Pacific/Easter';
|
||||
$string['pacific/efate'] = 'Pacific/Efate';
|
||||
$string['pacific/enderbury'] = 'Pacific/Enderbury';
|
||||
@@ -368,7 +426,6 @@ $string['pacific/gambier'] = 'Pacific/Gambier';
|
||||
$string['pacific/guadalcanal'] = 'Pacific/Guadalcanal';
|
||||
$string['pacific/guam'] = 'Pacific/Guam';
|
||||
$string['pacific/honolulu'] = 'Pacific/Honolulu';
|
||||
$string['pacific/chatham'] = 'Pacific/Chatham';
|
||||
$string['pacific/kiritimati'] = 'Pacific/Kiritimati';
|
||||
$string['pacific/kosrae'] = 'Pacific/Kosrae';
|
||||
$string['pacific/kwajalein'] = 'Pacific/Kwajalein';
|
||||
@@ -382,14 +439,33 @@ $string['pacific/noumea'] = 'Pacific/Noumea';
|
||||
$string['pacific/pago_pago'] = 'Pacific/Pago_Pago';
|
||||
$string['pacific/palau'] = 'Pacific/Palau';
|
||||
$string['pacific/pitcairn'] = 'Pacific/Pitcairn';
|
||||
$string['pacific/ponape'] = 'Pacific/Ponape';
|
||||
$string['pacific/pohnpei'] = 'Pacific/Pohnpei';
|
||||
$string['pacific/port_moresby'] = 'Pacific/Port_Moresby';
|
||||
$string['pacific/rarotonga'] = 'Pacific/Rarotonga';
|
||||
$string['pacific/saipan'] = 'Pacific/Saipan';
|
||||
$string['pacific/tahiti'] = 'Pacific/Tahiti';
|
||||
$string['pacific/tarawa'] = 'Pacific/Tarawa';
|
||||
$string['pacific/tongatapu'] = 'Pacific/Tongatapu';
|
||||
$string['pacific/truk'] = 'Pacific/Truk';
|
||||
$string['pacific/wake'] = 'Pacific/Wake';
|
||||
$string['pacific/wallis'] = 'Pacific/Wallis';
|
||||
$string['utc'] = 'UTC';
|
||||
// The following identifiers have been previous removed from TimeDateZone::listIdentifiers and are no longer used.
|
||||
// Deprecated since Moodle 3.9.
|
||||
$string['africa/asmera'] = 'Africa/Asmera';
|
||||
$string['africa/timbuktu'] = 'Africa/Timbuktu';
|
||||
$string['america/argentina/comodrivadavia'] = 'America/Argentina/ComodRivadavia';
|
||||
$string['america/indianapolis'] = 'America/Indianapolis';
|
||||
$string['america/louisville'] = 'America/Louisville';
|
||||
$string['america/montreal'] = 'America/Montreal';
|
||||
$string['asia/calcutta'] = 'Asia/Calcutta';
|
||||
$string['asia/chongqing'] = 'Asia/Chongqing';
|
||||
$string['asia/harbin'] = 'Asia/Harbin';
|
||||
$string['asia/kashgar'] = 'Asia/Kashgar';
|
||||
$string['asia/katmandu'] = 'Asia/Katmandu';
|
||||
$string['asia/rangoon'] = 'Asia/Rangoon';
|
||||
$string['asia/saigon'] = 'Asia/Saigon';
|
||||
$string['atlantic/faeroe'] = 'Atlantic/Faeroe';
|
||||
$string['europe/belfast'] = 'Europe/Belfast';
|
||||
$string['pacific/ponape'] = 'Pacific/Ponape';
|
||||
$string['pacific/truk'] = 'Pacific/Truk';
|
||||
$string['pacific/yap'] = 'Pacific/Yap';
|
||||
|
||||
@@ -20,6 +20,12 @@ class ADODB_postgres8 extends ADODB_postgres7
|
||||
{
|
||||
var $databaseType = 'postgres8';
|
||||
|
||||
// From PostgreSQL 8.0 onwards, the adsrc column used in earlier versions to
|
||||
// retrieve the default value is obsolete and should not be used (see #562).
|
||||
var $metaDefaultsSQL = "SELECT d.adnum as num, pg_get_expr(d.adbin, d.adrelid) as def
|
||||
FROM pg_attrdef d, pg_class c
|
||||
WHERE d.adrelid=c.oid AND c.relname='%s'
|
||||
ORDER BY d.adnum";
|
||||
|
||||
/**
|
||||
* Retrieve last inserted ID
|
||||
|
||||
@@ -33,5 +33,6 @@ Our changes:
|
||||
* MDL-58546 replaced each() with foreach for PHP 7.2 compatibility.
|
||||
pull request upstream: https://github.com/ADOdb/ADOdb/pull/373
|
||||
* MDL-65920 solved PHP 7.2 deprecations; create_function() and each().
|
||||
* MDL-67414 Fix to make the library PostgreSQL 12.x compliant (upstream: a4876f100602c2ce4).
|
||||
|
||||
skodak, iarenaza, moodler, stronk7, abgreeve, lameze, ankitagarwal, marinaglancy
|
||||
skodak, iarenaza, moodler, stronk7, abgreeve, lameze, ankitagarwal, marinaglancy, matteo
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -114,7 +114,7 @@ function($, log, str, templates, notification, LoadingIcon) {
|
||||
});
|
||||
var context = $.extend({items: items}, options, state);
|
||||
// Render the template.
|
||||
return templates.render('core/form_autocomplete_selection', context)
|
||||
return templates.render('core/form_autocomplete_selection_items', context)
|
||||
.then(function(html, js) {
|
||||
// Add it to the page.
|
||||
templates.replaceNodeContents(newSelection, html, js);
|
||||
|
||||
+10
-6
@@ -503,10 +503,13 @@ function badges_bake($hash, $badgeid, $userid = 0, $pathhash = false) {
|
||||
$contents = $file->get_content();
|
||||
|
||||
$filehandler = new PNG_MetaDataHandler($contents);
|
||||
$assertion = new moodle_url('/badges/assertion.php', array('b' => $hash));
|
||||
if ($filehandler->check_chunks("tEXt", "openbadges")) {
|
||||
// Add assertion URL tExt chunk.
|
||||
$newcontents = $filehandler->add_chunks("tEXt", "openbadges", $assertion->out(false));
|
||||
// For now, the site backpack OB version will be used as default.
|
||||
$obversion = badges_open_badges_backpack_api();
|
||||
$assertion = new core_badges_assertion($hash, $obversion);
|
||||
$assertionjson = json_encode($assertion->get_badge_assertion());
|
||||
if ($filehandler->check_chunks("iTXt", "openbadges")) {
|
||||
// Add assertion URL iTXt chunk.
|
||||
$newcontents = $filehandler->add_chunks("iTXt", "openbadges", $assertionjson);
|
||||
$fileinfo = array(
|
||||
'contextid' => $user_context->id,
|
||||
'component' => 'badges',
|
||||
@@ -868,7 +871,7 @@ function badges_get_default_issuer() {
|
||||
global $CFG, $SITE;
|
||||
|
||||
$issuer = array();
|
||||
$issuerurl = new moodle_url('/badges/issuer.php');
|
||||
$issuerurl = new moodle_url('/');
|
||||
$issuer['name'] = $CFG->badges_defaultissuername;
|
||||
if (empty($issuer['name'])) {
|
||||
$issuer['name'] = $SITE->fullname ? $SITE->fullname : $SITE->shortname;
|
||||
@@ -876,7 +879,8 @@ function badges_get_default_issuer() {
|
||||
$issuer['url'] = $issuerurl->out(false);
|
||||
$issuer['email'] = $CFG->badges_defaultissuercontact;
|
||||
$issuer['@context'] = OPEN_BADGES_V2_CONTEXT;
|
||||
$issuer['id'] = $issuerurl->out(false);
|
||||
$issuerid = new moodle_url('/badges/issuer_json.php');
|
||||
$issuer['id'] = $issuerid->out(false);
|
||||
$issuer['type'] = OPEN_BADGES_V2_TYPE_ISSUER;
|
||||
return $issuer;
|
||||
}
|
||||
|
||||
@@ -338,20 +338,11 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
|
||||
if (!$timeout) {
|
||||
$timeout = self::get_timeout();
|
||||
}
|
||||
if ($microsleep) {
|
||||
// Will sleep 1/10th of a second by default for self::get_timeout() seconds.
|
||||
$loops = $timeout * 10;
|
||||
} else {
|
||||
// Will sleep for self::get_timeout() seconds.
|
||||
$loops = $timeout;
|
||||
}
|
||||
|
||||
// DOM will never change on non-javascript case; do not wait or try again.
|
||||
if (!$this->running_javascript()) {
|
||||
$loops = 1;
|
||||
}
|
||||
$start = microtime(true);
|
||||
$end = $start + $timeout;
|
||||
|
||||
for ($i = 0; $i < $loops; $i++) {
|
||||
do {
|
||||
// We catch the exception thrown by the step definition to execute it again.
|
||||
try {
|
||||
// We don't check with !== because most of the time closures will return
|
||||
@@ -367,14 +358,13 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
if ($microsleep) {
|
||||
usleep(100000);
|
||||
} else {
|
||||
sleep(1);
|
||||
}
|
||||
if (!$this->running_javascript()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
|
||||
} while (microtime(true) < $end);
|
||||
|
||||
// Using coding_exception as is a development issue if no exception has been provided.
|
||||
if (!$exception) {
|
||||
|
||||
@@ -90,31 +90,54 @@ class behat_context_helper {
|
||||
* @return behat_base
|
||||
*/
|
||||
public static function get($classname) {
|
||||
if (self::$environment->hasContextClass($classname)) {
|
||||
return self::$environment->getContext($classname);
|
||||
$definedclassname = self::get_theme_override($classname);
|
||||
if ($definedclassname) {
|
||||
return self::$environment->getContext($definedclassname);
|
||||
}
|
||||
|
||||
// Just fall back on getContext to ensure that we throw the correct exception.
|
||||
return self::$environment->getContext($classname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context for the specified component or subsystem.
|
||||
*
|
||||
* @param string $component The component or subsystem to find the context for
|
||||
* @return behat_base|null
|
||||
*/
|
||||
public static function get_component_context(string $component): ?behat_base {
|
||||
$component = str_replace('core_', '', $component);
|
||||
|
||||
if ($classname = self::get_theme_override("behat_{$component}")) {
|
||||
return self::get($classname);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for any theme override of the specified class name.
|
||||
*
|
||||
* @param string $classname
|
||||
* @return string|null
|
||||
*/
|
||||
protected static function get_theme_override(string $classname): ?string {
|
||||
$suitename = self::$environment->getSuite()->getName();
|
||||
// If default suite, then get the default theme name.
|
||||
if ($suitename == 'default') {
|
||||
$suitename = theme_config::DEFAULT_THEME;
|
||||
}
|
||||
$overridencontextname = 'behat_theme_'.$suitename.'_'.$classname;
|
||||
|
||||
// If contexts has not been checked before and doesn't exist then just use core one.
|
||||
if (!isset(self::$nonexistingcontexts[$overridencontextname])) {
|
||||
try {
|
||||
$subcontext = self::$environment->getContext($overridencontextname);
|
||||
|
||||
return $subcontext;
|
||||
} catch (Behat\Behat\Context\Exception\ContextNotFoundException $e) {
|
||||
// If context not found then it's not overridden.
|
||||
self::$nonexistingcontexts[$overridencontextname] = 1;
|
||||
}
|
||||
$overrideclassname = "behat_theme_{$suitename}_{$classname}";
|
||||
if (self::$environment->hasContextClass($overrideclassname)) {
|
||||
return $overrideclassname;
|
||||
}
|
||||
|
||||
// Get the actual context.
|
||||
return self::$environment->getContext($classname);
|
||||
if (self::$environment->hasContextClass($classname)) {
|
||||
return $classname;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,8 +42,21 @@ define('ANY_VERSION', 'any');
|
||||
* Collection of components related methods.
|
||||
*/
|
||||
class core_component {
|
||||
/** @var array list of ignored directories - watch out for auth/db exception */
|
||||
protected static $ignoreddirs = array('CVS'=>true, '_vti_cnf'=>true, 'simpletest'=>true, 'db'=>true, 'yui'=>true, 'tests'=>true, 'classes'=>true, 'fonts'=>true);
|
||||
/** @var array list of ignored directories in plugin type roots - watch out for auth/db exception */
|
||||
protected static $ignoreddirs = [
|
||||
'CVS' => true,
|
||||
'_vti_cnf' => true,
|
||||
'amd' => true,
|
||||
'classes' => true,
|
||||
'db' => true,
|
||||
'fonts' => true,
|
||||
'lang' => true,
|
||||
'pix' => true,
|
||||
'simpletest' => true,
|
||||
'templates' => true,
|
||||
'tests' => true,
|
||||
'yui' => true,
|
||||
];
|
||||
/** @var array list plugin types that support subplugins, do not add more here unless absolutely necessary */
|
||||
protected static $supportsubplugins = array('mod', 'editor', 'tool', 'local');
|
||||
|
||||
|
||||
@@ -224,4 +224,25 @@ final class ip_utils {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is an ip in a given list of subnets?
|
||||
*
|
||||
* @param string $ip - the IP to test against the list
|
||||
* @param string $list - the list of IP subnets
|
||||
* @param string $delim a delimiter of the list
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_ip_in_subnet_list($ip, $list, $delim = "\n") {
|
||||
$list = explode($delim, $list);
|
||||
foreach ($list as $line) {
|
||||
$tokens = explode('#', $line);
|
||||
$subnet = trim($tokens[0]);
|
||||
if (address_in_subnet($ip, $subnet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -331,15 +331,14 @@ class manager {
|
||||
// Trigger event for sending a message or notification - we need to do this before marking as read!
|
||||
self::trigger_message_events($eventdata, $savemessage);
|
||||
|
||||
if ($eventdata->notification or empty($CFG->messaging)) {
|
||||
// If they have deselected all processors and its a notification mark it read. The user doesn't want to be bothered.
|
||||
// The same goes if the messaging is completely disabled.
|
||||
if ($eventdata->notification) {
|
||||
$savemessage->timeread = null;
|
||||
\core_message\api::mark_notification_as_read($savemessage);
|
||||
} else {
|
||||
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
|
||||
}
|
||||
if ($eventdata->notification) {
|
||||
// If they have deselected all processors and it's a notification mark it read. The user doesn't want to be
|
||||
// bothered.
|
||||
$savemessage->timeread = null;
|
||||
\core_message\api::mark_notification_as_read($savemessage);
|
||||
} else if (empty($CFG->messaging)) {
|
||||
// If it's a message and messaging is disabled mark it read.
|
||||
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
|
||||
}
|
||||
|
||||
return $savemessage->id;
|
||||
@@ -383,15 +382,9 @@ class manager {
|
||||
// Trigger event for sending a message or notification - we need to do this before marking as read!
|
||||
self::trigger_message_events($eventdata, $savemessage);
|
||||
|
||||
if (empty($CFG->messaging)) {
|
||||
// If they have deselected all processors and its a notification mark it read. The user doesn't want to be bothered.
|
||||
// The same goes if the messaging is completely disabled.
|
||||
if ($eventdata->notification) {
|
||||
$savemessage->timeread = null;
|
||||
\core_message\api::mark_notification_as_read($savemessage);
|
||||
} else {
|
||||
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
|
||||
}
|
||||
if (!$eventdata->notification && empty($CFG->messaging)) {
|
||||
// If it's a message and messaging is disabled mark it read.
|
||||
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
|
||||
}
|
||||
|
||||
return $savemessage->id;
|
||||
|
||||
@@ -292,7 +292,27 @@ class manager {
|
||||
|
||||
// Set configuration.
|
||||
session_name($sessionname);
|
||||
session_set_cookie_params(0, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $cookiesecure, $CFG->cookiehttponly);
|
||||
|
||||
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
|
||||
$sessionoptions = [
|
||||
'lifetime' => 0,
|
||||
'path' => $CFG->sessioncookiepath,
|
||||
'domain' => $CFG->sessioncookiedomain,
|
||||
'secure' => $cookiesecure,
|
||||
'httponly' => $CFG->cookiehttponly,
|
||||
];
|
||||
|
||||
if (self::should_use_samesite_none()) {
|
||||
// If $samesite is empty, we don't want there to be any SameSite attribute.
|
||||
$sessionoptions['samesite'] = 'None';
|
||||
}
|
||||
|
||||
session_set_cookie_params($sessionoptions);
|
||||
} else {
|
||||
// Once PHP 7.3 becomes our minimum, drop this in favour of the alternative call to session_set_cookie_params above,
|
||||
// as that does not require a hack to work with same site settings on cookies.
|
||||
session_set_cookie_params(0, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $cookiesecure, $CFG->cookiehttponly);
|
||||
}
|
||||
ini_set('session.use_trans_sid', '0');
|
||||
ini_set('session.use_only_cookies', '1');
|
||||
ini_set('session.hash_function', '0'); // For now MD5 - we do not have room for sha-1 in sessions table.
|
||||
@@ -452,6 +472,8 @@ class manager {
|
||||
if ($timedout) {
|
||||
$_SESSION['SESSION']->has_timed_out = true;
|
||||
}
|
||||
|
||||
self::append_samesite_cookie_attribute();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -519,6 +541,61 @@ class manager {
|
||||
|
||||
// Setup $USER object.
|
||||
self::set_user($user);
|
||||
self::append_samesite_cookie_attribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a valid setting for the SameSite cookie attribute.
|
||||
*
|
||||
* @return string The desired setting for the SameSite attribute on the cookie. Empty string indicates the SameSite attribute
|
||||
* should not be set at all.
|
||||
*/
|
||||
private static function should_use_samesite_none(): bool {
|
||||
// We only want None or no attribute at this point. When we have cookie handling compatible with Lax,
|
||||
// we can look at checking a setting.
|
||||
|
||||
// Browser support for none is not consistent yet. There are known issues with Safari, and IE11.
|
||||
// Things are stablising, however as they're not stable yet we will deal specifically with the version of chrome
|
||||
// that introduces a default of lax, setting it to none for the current version of chrome (2 releases before the change).
|
||||
// We also check you are using secure cookies and HTTPS because if you are not running over HTTPS
|
||||
// then setting SameSite=None will cause your session cookie to be rejected.
|
||||
if (\core_useragent::is_chrome() && \core_useragent::check_chrome_version('78') && is_moodle_cookie_secure()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally append the SameSite attribute to the session cookie if necessary.
|
||||
*
|
||||
* Contains a hack for versions of PHP lower than 7.3 as there is no API built into PHP cookie API
|
||||
* for adding the SameSite setting.
|
||||
*
|
||||
* This won't change the Set-Cookie headers if:
|
||||
* - PHP 7.3 or higher is being used. That already adds the SameSite attribute without any hacks.
|
||||
* - If the samesite setting is empty.
|
||||
* - If the samesite setting is None but the browser is not compatible with that setting.
|
||||
*/
|
||||
private static function append_samesite_cookie_attribute() {
|
||||
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
|
||||
// This hack is only necessary if we weren't able to set the samesite flag via the session_set_cookie_params API.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self::should_use_samesite_none()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cookies = headers_list();
|
||||
header_remove('Set-Cookie');
|
||||
$setcookiesession = 'Set-Cookie: ' . session_name() . '=';
|
||||
|
||||
foreach ($cookies as $cookie) {
|
||||
if (strpos($cookie, $setcookiesession) === 0) {
|
||||
$cookie .= '; SameSite=None';
|
||||
}
|
||||
header($cookie, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,6 +632,8 @@ class manager {
|
||||
self::add_session_record($_SESSION['USER']->id); // Do not use $USER here because it may not be set up yet.
|
||||
session_write_close();
|
||||
self::$sessionactive = false;
|
||||
|
||||
self::append_samesite_cookie_attribute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -163,6 +163,9 @@ class database_logger implements task_logger {
|
||||
return;
|
||||
}
|
||||
|
||||
$DB->delete_records_list('task_log', 'id', $logids);
|
||||
$chunks = array_chunk($logids, 1000);
|
||||
foreach ($chunks as $chunk) {
|
||||
$DB->delete_records_list('task_log', 'id', $chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class file_temp_cleanup_task extends scheduled_task {
|
||||
// Now loop through again and remove old files and directories.
|
||||
for ($iter->rewind(); $iter->valid(); $iter->next()) {
|
||||
$node = $iter->getRealPath();
|
||||
if (!is_readable($node)) {
|
||||
if (!isset($modifieddateobject[$node]) || !is_readable($node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user