Compare commits
285 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| becbdd847d | |||
| 6ac3dd457c | |||
| cd97da9c5c | |||
| 759b2670a0 | |||
| 3f90e29e39 | |||
| 257a8126ad | |||
| d32320beac | |||
| 1352a23354 | |||
| 46a8a3bb75 | |||
| 79d1331384 | |||
| cd72578917 | |||
| 72e9f115ab | |||
| 01011e49dd | |||
| fcf7d12a4b | |||
| f44d6ba340 | |||
| 15632be78d | |||
| 53a0fbecd2 | |||
| 832261f49b | |||
| 2378fc0117 | |||
| cd754d3b44 | |||
| 8307ce8f18 | |||
| 4225940caa | |||
| 2ce1ed7247 | |||
| f21c892997 | |||
| 0b8ab4fcef | |||
| 8ec49b09e5 | |||
| fd9ab3efbd | |||
| acdca038df | |||
| dd6f0debcc | |||
| 8f93e88387 | |||
| 17fccfcf64 | |||
| 0cdb9169cb | |||
| a110b34a5a | |||
| 252d0faac1 | |||
| 1802410629 | |||
| 89cba33e91 | |||
| b86162544d | |||
| 2135ff7c19 | |||
| d0e63f5a60 | |||
| ec65857de0 | |||
| d34d35d2b6 | |||
| 0742fb7b44 | |||
| 0e7caf93b5 | |||
| e876654d1f | |||
| a11e590324 | |||
| 5ff8f06f64 | |||
| 8a1c8f8bb3 | |||
| 671849b2db | |||
| 8341244903 | |||
| 02d251294c | |||
| b490d511d6 | |||
| 2d08d7d2c0 | |||
| 016d123034 | |||
| 2e4c5f9c12 | |||
| e7b463af6d | |||
| 314c9671fc | |||
| b8c4c975e0 | |||
| f3952dc29f | |||
| 71841556aa | |||
| 575fabe57a | |||
| 5cf3b78855 | |||
| a84b1f1307 | |||
| c435b7896f | |||
| e740fa9c3b | |||
| 243eb04a85 | |||
| 88c757cef0 | |||
| 8f06e62409 | |||
| 0eda72ec4f | |||
| 68ff5f0ce0 | |||
| deb5150786 | |||
| 15521655a3 | |||
| 3a2703c9f5 | |||
| f48d31f0d4 | |||
| 38da2c3a61 | |||
| 583b655e37 | |||
| 28f06c0f27 | |||
| 4e1e916ca6 | |||
| 0c2426d207 | |||
| 3f17ea00e7 | |||
| 565fe67086 | |||
| 97f67db36d | |||
| e2b085c81b | |||
| 91bb1805d9 | |||
| 4d36e008dd | |||
| e57d9506af | |||
| 779cd5b40c | |||
| 98fd15d75b | |||
| 552ec1b547 | |||
| 977cbaf239 | |||
| a68be3c7fa | |||
| a123645de3 | |||
| 29191eeff2 | |||
| b9701a8bb8 | |||
| 1fe901e1ab | |||
| 24bc7e9a19 | |||
| c352ec94a8 | |||
| 91c7b05b05 | |||
| a9e12e1d84 | |||
| 33eaae5569 | |||
| aaedf21a31 | |||
| 658c7e9ef5 | |||
| 7ef51203c6 | |||
| 6591971e8a | |||
| 58bc68b0bc | |||
| 93c53ea726 | |||
| 73eec5d12d | |||
| ee36b4146f | |||
| 6180b175d4 | |||
| e083dae38e | |||
| 42be9c33eb | |||
| 8ba4d8be17 | |||
| 78910334ff | |||
| 6af53fa8c0 | |||
| d0b8656cb5 | |||
| 9c93fbe3a4 | |||
| a97f8d6720 | |||
| 7ceb1466e9 | |||
| 5d0b1f0ed3 | |||
| 180bf41216 | |||
| 509578453a | |||
| 8be7ac509a | |||
| fcfd012b6a | |||
| a778af133e | |||
| 1ff07992ec | |||
| 8cbcbc094c | |||
| a35c9aab6d | |||
| bef4181788 | |||
| abcbc42139 | |||
| f65577ef3a | |||
| fdc7349577 | |||
| 0ee24af3cd | |||
| 815419ad12 | |||
| b92f5e00aa | |||
| 54263aa1f6 | |||
| 100fad08fe | |||
| 14f87ce4b5 | |||
| b4b650f9cd | |||
| efc6d19ac2 | |||
| a887e577a4 | |||
| 5b9f243378 | |||
| 1900cadd4f | |||
| f55fd1b49c | |||
| 575358c0f0 | |||
| 83a1703746 | |||
| 5c74434dfa | |||
| 72e2a0dfb5 | |||
| 8c30413ba8 | |||
| ce2a901414 | |||
| 811fc31904 | |||
| 25efc9e7aa | |||
| c29ba27942 | |||
| 125065e488 | |||
| 613ba34b07 | |||
| 975ef5c540 | |||
| 1db7e78c8b | |||
| 37fa9f51e9 | |||
| 4eed9bd261 | |||
| ec6c3cd9a0 | |||
| 133b7b700d | |||
| c269c67830 | |||
| 8d09620c14 | |||
| 94327ba15f | |||
| 8e1353f39d | |||
| 342c6367d0 | |||
| fe6c455b51 | |||
| 777025b298 | |||
| 1545abb21d | |||
| d70b73345c | |||
| fbc97ebdcd | |||
| 95b4682d3c | |||
| 27f7c54d58 | |||
| 459da610c6 | |||
| 930a0d2944 | |||
| e881dee5b4 | |||
| f525194ea2 | |||
| d18f60bd3f | |||
| 01643574c5 | |||
| 0268bbd07b | |||
| 4f5d221749 | |||
| 8ca4a0087d | |||
| 357ab40ff4 | |||
| a0518068fb | |||
| 5ef68db33a | |||
| 2914d47171 | |||
| e79b14e2a9 | |||
| b97ed6d75a | |||
| f4d830d7e4 | |||
| 2974880afe | |||
| 4ed21af7df | |||
| e1d80935a3 | |||
| f40424cd25 | |||
| 47f85d5da1 | |||
| ac0444bff4 | |||
| bb7955546c | |||
| 0fd522dd1f | |||
| a09f258f70 | |||
| b193122b29 | |||
| 10d39a1feb | |||
| d51a14792b | |||
| 074307ebba | |||
| aeacebf383 | |||
| 51c22d1e3f | |||
| e5bf98ab9d | |||
| 1b1758caa2 | |||
| a71341c693 | |||
| b21541294a | |||
| 806a667b3a | |||
| 7311810970 | |||
| c8773b698a | |||
| e446e2b6a9 | |||
| 6a6344e268 | |||
| bcdee74ae9 | |||
| dacd86c23c | |||
| bb6c03a252 | |||
| b37a074180 | |||
| 64e570d0ab | |||
| 0a4af5f771 | |||
| d288aea421 | |||
| a9edf3962a | |||
| 6087c2a835 | |||
| 6fd68977ac | |||
| 94f6eefb86 | |||
| d03da85cef | |||
| 3e789e5d6d | |||
| b16eb4c432 | |||
| f533978709 | |||
| 53846820df | |||
| 65c8839157 | |||
| 0561f8c5b5 | |||
| 8684cd6a76 | |||
| fa10357f57 | |||
| d463e0d8f6 | |||
| 54b614ca7e | |||
| 9f7d92de62 | |||
| 4125c3c470 | |||
| 258cdfaa6a | |||
| 8c2792cb5d | |||
| 25d4bc7ffc | |||
| d98b39a597 | |||
| 191badf5ad | |||
| c4ba598a0b | |||
| f77ea5bffa | |||
| 3d11b25cce | |||
| 8a55673463 | |||
| 230f7a2d1b | |||
| 87344d03e1 | |||
| e237e83dfb | |||
| aa392ce73a | |||
| 6220f712ab | |||
| 714b88a1b8 | |||
| bbadf7a02c | |||
| 57b97b29b7 | |||
| 6fe4eb2a86 | |||
| 8a0274423d | |||
| ddd80a5d2c | |||
| 50bf83fede | |||
| cafbfc6076 | |||
| 2b22716dc2 | |||
| 3498aeaf1e | |||
| c59d4f9612 | |||
| e3ce532831 | |||
| 87e0d39e19 | |||
| 90aceb5e6c | |||
| 7d1996fb3a | |||
| cb9583c21c | |||
| 633c6d7e80 | |||
| 76ed3885a9 | |||
| f4456f6afe | |||
| 21384101e1 | |||
| 61cedbd56e | |||
| 376e57d267 | |||
| 9de11ea641 | |||
| d793ac8e5e | |||
| e5e8bc4b22 | |||
| 911fafd9a9 | |||
| 739b551fa8 | |||
| a9ce394b63 | |||
| a8c9e82653 | |||
| f8351de05e | |||
| 34f352ded2 | |||
| a287546036 | |||
| 2eb859a839 | |||
| 0448a7b267 | |||
| 2571dcf012 | |||
| 23f0472514 |
@@ -13,14 +13,14 @@ env:
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
@@ -54,11 +54,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
php: 7.3
|
||||
extensions:
|
||||
db: mysqli
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
php: 8.0
|
||||
db: pgsql
|
||||
extensions: xmlrpc-beta
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
postgresql password: test
|
||||
|
||||
- name: Configuring git vars
|
||||
uses: rlespinasse/github-slug-action@v3.x
|
||||
uses: rlespinasse/github-slug-action@v4
|
||||
|
||||
- name: Setting up PHP ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
@@ -96,7 +96,7 @@ jobs:
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
|
||||
@@ -52,3 +52,4 @@ moodle-plugin-ci.phar
|
||||
.stylelintignore
|
||||
/jsdoc
|
||||
.phpcs.xml
|
||||
jsconfig.json
|
||||
|
||||
@@ -233,6 +233,7 @@ const getOwningComponentDirectory = checkPath => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
fetchComponentData,
|
||||
getAmdSrcGlobList,
|
||||
getComponentFromPath,
|
||||
getComponentPaths,
|
||||
|
||||
@@ -47,6 +47,9 @@ module.exports = grunt => {
|
||||
// Load ESLint.
|
||||
require('./eslint')(grunt);
|
||||
|
||||
// Load jsconfig.
|
||||
require('./jsconfig')(grunt);
|
||||
|
||||
// Load JSDoc.
|
||||
require('./jsdoc')(grunt);
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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/>.
|
||||
/* jshint node: true, browser: false */
|
||||
/* eslint-env node */
|
||||
|
||||
/**
|
||||
* @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
const configuration = {
|
||||
compilerOptions: {
|
||||
baseUrl: ".",
|
||||
paths: {
|
||||
},
|
||||
target: "es2015",
|
||||
allowSyntheticDefaultImports: false,
|
||||
},
|
||||
exclude: [
|
||||
"node_modules",
|
||||
],
|
||||
include: [],
|
||||
};
|
||||
|
||||
module.exports = (grunt) => {
|
||||
const handler = () => {
|
||||
const jsconfigData = Object.assign({}, configuration);
|
||||
|
||||
const path = require('path');
|
||||
const {fetchComponentData} = require(path.join(process.cwd(), '.grunt', 'components.js'));
|
||||
|
||||
const componentData = fetchComponentData().components;
|
||||
for (const [thisPath, component] of Object.entries(componentData)) {
|
||||
jsconfigData.compilerOptions.paths[`${component}/*`] = [`${thisPath}/amd/src/*`];
|
||||
jsconfigData.include.push(`${thisPath}/amd/src/**/*`);
|
||||
}
|
||||
|
||||
grunt.file.write('jsconfig.json', JSON.stringify(jsconfigData, null, " ") + "\n");
|
||||
};
|
||||
grunt.registerTask('jsconfig', 'Generate a jsconfig configuration compatible with the LSP', handler);
|
||||
};
|
||||
@@ -3781,11 +3781,6 @@
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
|
||||
@@ -59,9 +59,8 @@ class mnet_simple_host_form extends moodleform {
|
||||
$wwwroot = 'http://'.$wwwroot;
|
||||
}
|
||||
if ($host = $DB->get_record('mnet_host', array('wwwroot' => $wwwroot))) {
|
||||
global $CFG;
|
||||
return array('wwwroot' => get_string('hostexists', 'mnet',
|
||||
new moodle_url('/admin/mnet/peers.php', array('hostid' => $host->id))));
|
||||
$str = get_string('hostexists', 'mnet', (new moodle_url('/admin/mnet/peers.php', ['hostid' => $host->id]))->out());
|
||||
return array('wwwroot' => $str);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ class accessibility {
|
||||
/**
|
||||
* This function runs one specified check on the html item
|
||||
*
|
||||
* @param string $html The html string to be analysed; might be NULL.
|
||||
* @param string|null $html The html string to be analysed; might be NULL.
|
||||
* @param int $contentid The content area ID
|
||||
* @param int $errid The error ID
|
||||
* @param string $check The check name to run
|
||||
@@ -333,7 +333,7 @@ class accessibility {
|
||||
* @throws \dml_exception
|
||||
*/
|
||||
public static function run_one_check(
|
||||
string $html = null,
|
||||
?string $html,
|
||||
int $contentid,
|
||||
int $errid,
|
||||
string $check,
|
||||
|
||||
@@ -36,7 +36,7 @@ Useful for uploading custom langstrings to AMOS or importing or syncing them to
|
||||
Options:
|
||||
-l, --lang Comma seperated language ids to export, default: all
|
||||
-c, --components Comma seperated components to export, default: all
|
||||
-t, --target Target to copy the zip files to, default: $CFG->tempdir/customlang
|
||||
-t, --target Target directory to copy the zip files to, default: $CFG->tempdir/customlang
|
||||
-o, --overwrite Overwrite existing files in the target folder.
|
||||
Note: If the target is not set, the files are always overwritten!
|
||||
-h, --help Print out this help
|
||||
@@ -73,9 +73,10 @@ if ($options['help']) {
|
||||
echo $usage;
|
||||
die;
|
||||
}
|
||||
if (!file_exists($options['target'])) {
|
||||
mkdir($options['target'], 0777, true);
|
||||
}
|
||||
|
||||
// Ensure target directory exists.
|
||||
$options['target'] = rtrim($options['target'], '/') . '/';
|
||||
check_dir_exists($options['target']);
|
||||
|
||||
cli_writeln(get_string('cliexportheading', 'tool_customlang'));
|
||||
$langs = [];
|
||||
@@ -90,7 +91,7 @@ foreach ($langs as $lang) {
|
||||
$filename = $options['target'] . get_string('exportzipfilename', 'tool_customlang', ['lang' => $lang]);
|
||||
// If the file exists and we are not using the temp folder it requires an ovewrite.
|
||||
if ($options['target'] != $dafaulttarget && file_exists($filename) && !$options['overwrite']) {
|
||||
cli_problem(get_string('cliexportfileexists', 'tool_customlang', $lang));
|
||||
cli_problem(get_string('cliexportfileexists', 'tool_customlang', ['lang' => $lang]));
|
||||
continue;
|
||||
}
|
||||
cli_heading(get_string('cliexportstartexport', 'tool_customlang', $lang));
|
||||
|
||||
@@ -160,6 +160,16 @@ foreach ($langfiles as $lng => $files) {
|
||||
|
||||
cli_heading(get_string('clifiles', 'tool_customlang', $lng));
|
||||
|
||||
// If we intend to check in any changes, we must first check them out.
|
||||
if ($checkin) {
|
||||
cli_writeln(get_string('checkout', 'tool_customlang'));
|
||||
|
||||
$progressbar = new progress_bar();
|
||||
$progressbar->create();
|
||||
|
||||
tool_customlang_utils::checkout($lng, $progressbar);
|
||||
}
|
||||
|
||||
foreach ($files as $file) {
|
||||
// Generate a valid stored_file from this file.
|
||||
$record = (object)[
|
||||
|
||||
@@ -50,6 +50,7 @@ $string['customlang:export'] = 'Export local translation';
|
||||
$string['customlang:view'] = 'View local translation';
|
||||
$string['export'] = 'Export custom strings';
|
||||
$string['exportfilter'] = 'Select component(s) to export';
|
||||
$string['exportzipfilename'] = 'customlang-export-{$a->lang}.zip';
|
||||
$string['filter'] = 'Filter strings';
|
||||
$string['filtercomponent'] = 'Show strings of these components';
|
||||
$string['filtercustomized'] = 'Customised only';
|
||||
|
||||
@@ -89,7 +89,9 @@ class tool_customlang_utils {
|
||||
* @param progress_bar $progressbar optionally, the given progress bar can be updated
|
||||
*/
|
||||
public static function checkout($lang, progress_bar $progressbar = null) {
|
||||
global $DB;
|
||||
global $DB, $CFG;
|
||||
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
|
||||
// For behat executions we are going to load only a few components in the
|
||||
// language customisation structures. Using the whole "en" langpack is
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_httpsreplace\tests;
|
||||
|
||||
namespace tool_httpsreplace;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
@@ -124,6 +124,12 @@ class controller {
|
||||
}
|
||||
|
||||
if ($rm1 or $rm2) {
|
||||
// Set the default site language to en if the deleted language pack is the default site language.
|
||||
if ($CFG->lang === $lang) {
|
||||
set_config('lang', 'en');
|
||||
// Fix the user's current language to the default site language.
|
||||
fix_current_language($CFG->lang);
|
||||
}
|
||||
$this->info[] = get_string('langpackremoved', 'tool_langimport', $lang);
|
||||
event\langpack_removed::event_with_langcode($lang)->trigger();
|
||||
return true;
|
||||
|
||||
@@ -77,9 +77,10 @@
|
||||
ucw.registerEvents('[data-region="user-competency-status"]');
|
||||
ucw.on('status-changed', infoReloader.reload.bind(infoReloader));
|
||||
ucw.on('error-occured', infoReloader.reload.bind(infoReloader));
|
||||
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{#cangrade}}
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}', '', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{/cangrade}}
|
||||
});
|
||||
{{/js}}
|
||||
{{/usercompetency}}
|
||||
|
||||
@@ -95,13 +95,14 @@
|
||||
{{#js}}
|
||||
require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info'], function($, mod, info) {
|
||||
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
var competencyElement = $('[data-region-id="{{uniqid}}"]');
|
||||
|
||||
var displayuser = ('{{displayuser}}' == 'true') ? true : false;
|
||||
var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', displayuser);
|
||||
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{#cangrade}}
|
||||
var inlineGrader = new mod('#rate_{{uniqid}}', '{{competency.scaleid}}', '{{competency.competency.id}}', '{{user.id}}', '', '{{course.id}}', '{{#str}}chooserating, tool_lp{{/str}}');
|
||||
inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader));
|
||||
{{/cangrade}}
|
||||
});
|
||||
|
||||
{{/js}}
|
||||
|
||||
+6
-11
@@ -14,24 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_handler_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_handler_info;
|
||||
use tool_moodlenet\local\import_strategy;
|
||||
use tool_moodlenet\local\import_strategy_file;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_handler_info_testcase, providing test cases for the import_handler_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_handler_info_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_handler_registry class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_handler_registry;
|
||||
use tool_moodlenet\local\import_handler_info;
|
||||
@@ -31,10 +23,13 @@ use tool_moodlenet\local\import_strategy_link;
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_handler_registry_testcase, providing test cases for the import_handler_registry class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_handler_registry_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,24 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_info;
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_info_testcase, providing test cases for the import_info class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_info_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the import_processor class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\import_handler_registry;
|
||||
use tool_moodlenet\local\import_processor;
|
||||
@@ -31,10 +23,13 @@ use tool_moodlenet\local\import_strategy_link;
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_import_processor_testcase, providing test cases for the import_processor class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class import_processor_test extends \advanced_testcase {
|
||||
|
||||
+6
-11
@@ -14,24 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
/**
|
||||
* Unit tests for the remote_resource class.
|
||||
* Class tool_moodlenet_remote_resource_testcase, providing test cases for the remote_resource class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
|
||||
use tool_moodlenet\local\remote_resource;
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_remote_resource_testcase, providing test cases for the remote_resource class.
|
||||
*/
|
||||
class remote_resource_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
+5
-10
@@ -14,23 +14,18 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace tool_moodlenet\local;
|
||||
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
/**
|
||||
* Unit tests for the url class.
|
||||
* Class tool_moodlenet_url_testcase, providing test cases for the url class.
|
||||
*
|
||||
* @package tool_moodlenet
|
||||
* @category test
|
||||
* @copyright 2020 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_moodlenet\local\tests;
|
||||
|
||||
use tool_moodlenet\local\url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class tool_moodlenet_url_testcase, providing test cases for the url class.
|
||||
*/
|
||||
class url_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
@@ -134,7 +134,6 @@ Feature: Basic OAuth2 functionality
|
||||
And I set the following fields to these values:
|
||||
| Name | Testing service modified |
|
||||
And I press "Save changes"
|
||||
And I should see "Could not discover service endpoints"
|
||||
And I should see "Testing service modified"
|
||||
And I click on "Delete" "link" in the "Testing service modified" "table_row"
|
||||
And I should see "Are you sure you want to delete the identity issuer \"Testing service modified\"?"
|
||||
@@ -239,13 +238,12 @@ Feature: Basic OAuth2 functionality
|
||||
And I press "Save changes"
|
||||
And "Do not allow login" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Allow services" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Service discovery successful" "icon" should exist in the "Valid custom" "table_row"
|
||||
And I should see "-" in the "Valid custom" "table_row"
|
||||
And I click on "Edit" "link" in the "Valid custom service" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Name | Invalid custom service |
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
And I press "Save changes"
|
||||
Then I should see "Could not discover end points for identity issuer: Invalid custom service"
|
||||
And I should see "-" in the "Invalid custom service" "table_row"
|
||||
And I click on "Delete" "link" in the "Invalid custom service" "table_row"
|
||||
And I should see "Are you sure you want to delete the identity issuer \"Invalid custom service\"?"
|
||||
@@ -281,13 +279,12 @@ Feature: Basic OAuth2 functionality
|
||||
And I press "Save changes"
|
||||
And "Do not allow login" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Allow services" "icon" should exist in the "Valid custom" "table_row"
|
||||
And "Service discovery successful" "icon" should exist in the "Valid custom" "table_row"
|
||||
And I should see "-" in the "Valid custom" "table_row"
|
||||
And I click on "Edit" "link" in the "Valid custom service" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Name | Invalid custom service |
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
And I press "Save changes"
|
||||
Then I should see "Could not discover end points for identity issuer: Invalid custom service"
|
||||
And I should see "-" in the "Invalid custom service" "table_row"
|
||||
And I click on "Edit" "link" in the "Invalid custom service" "table_row"
|
||||
And I set the following fields to these values:
|
||||
@@ -351,9 +348,12 @@ Feature: Basic OAuth2 functionality
|
||||
And I should see "Custom display name" in the "Empty custom service" "table_row"
|
||||
And "Not configured" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And "Do not allow services" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And I click on "Edit" "link" in the "Empty custom service" "table_row"
|
||||
And I click on "Configure endpoints" "link" in the "Empty custom service" "table_row"
|
||||
And I press "Create new endpoint for issuer \"Empty custom service\""
|
||||
And I set the following fields to these values:
|
||||
| Service base URL | https://accounts.google.com |
|
||||
| Name | userinfo_endpoint |
|
||||
| URL | https://example.com/userinfo |
|
||||
And I press "Save changes"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And "Allow login" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And "Do not allow services" "icon" should exist in the "Empty custom service" "table_row"
|
||||
|
||||
@@ -14,17 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the analysis class.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
namespace core_analytics;
|
||||
|
||||
/**
|
||||
* Unit tests for the analysis class.
|
||||
@@ -33,18 +23,19 @@ require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_analysis_testcase extends advanced_testcase {
|
||||
class analysis_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test fill_firstanalyses_cache.
|
||||
* @return null
|
||||
*/
|
||||
public function test_fill_firstanalyses_cache() {
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
$this->resetAfterTest();
|
||||
|
||||
$modelid = 1;
|
||||
|
||||
$params = ['startdate' => (new DateTimeImmutable('-5 seconds'))->getTimestamp()];
|
||||
$params = ['startdate' => (new \DateTimeImmutable('-5 seconds'))->getTimestamp()];
|
||||
$course1 = $this->getDataGenerator()->create_course($params);
|
||||
$course2 = $this->getDataGenerator()->create_course($params);
|
||||
$analysable1 = new \core_analytics\course($course1);
|
||||
@@ -72,7 +63,7 @@ class analytics_analysis_testcase extends advanced_testcase {
|
||||
$this->assertEquals($earliest, $firstanalyses[$modelid . '_' . $course1->id]);
|
||||
|
||||
// Upcoming periodic time-splitting methods can read and process the cached data.
|
||||
$seconds = new test_timesplitting_upcoming_seconds();
|
||||
$seconds = new \test_timesplitting_upcoming_seconds();
|
||||
$seconds->set_modelid($modelid);
|
||||
$seconds->set_analysable($analysable1);
|
||||
|
||||
|
||||
@@ -14,18 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the calculation info cache.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
namespace core_analytics;
|
||||
|
||||
/**
|
||||
* Unit tests for the calculation info cache.
|
||||
@@ -34,7 +23,7 @@ require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_calculation_info_testcase extends advanced_testcase {
|
||||
class calculation_info_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* test_calculation_info description
|
||||
@@ -47,12 +36,14 @@ class analytics_calculation_info_testcase extends advanced_testcase {
|
||||
* @return null
|
||||
*/
|
||||
public function test_calculation_info_add_pull($info1, $info2, $info3, $info4) {
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
$this->resetAfterTest();
|
||||
|
||||
$atimesplitting = new \core\analytics\time_splitting\quarters();
|
||||
|
||||
$indicator1 = new test_indicator_min();
|
||||
$indicator2 = new test_indicator_max();
|
||||
$indicator1 = new \test_indicator_min();
|
||||
$indicator2 = new \test_indicator_max();
|
||||
|
||||
$calculationinfo = new \core_analytics\calculation_info();
|
||||
$calculationinfo->add_shared(111, [111 => $info1]);
|
||||
|
||||
@@ -14,15 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the dataset manager.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
namespace core_analytics;
|
||||
|
||||
/**
|
||||
* Unit tests for the dataset manager.
|
||||
@@ -31,7 +23,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class dataset_manager_testcase extends advanced_testcase {
|
||||
class dataset_manager_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* setUp
|
||||
|
||||
@@ -14,13 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the indicator API.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2019 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -35,7 +29,7 @@ require_once(__DIR__ . '/fixtures/test_indicator_min.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_indicator_testcase extends advanced_testcase {
|
||||
class indicator_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* test_validate_calculated_value
|
||||
@@ -79,7 +73,7 @@ class analytics_indicator_testcase extends advanced_testcase {
|
||||
->onlyMethods(['calculate_sample'])
|
||||
->getMock();
|
||||
$indicatormock->method('calculate_sample')->willReturn($willreturn);
|
||||
$this->expectException(coding_exception::class);
|
||||
$this->expectException(\coding_exception::class);
|
||||
list($values, $unused) = $indicatormock->calculate([1], 'notrelevanthere');
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/fixtures/test_indicator_max.php');
|
||||
@@ -39,7 +41,7 @@ require_once(__DIR__ . '/fixtures/test_analysis.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_model_testcase extends advanced_testcase {
|
||||
class model_test extends \advanced_testcase {
|
||||
|
||||
public function setUp(): void {
|
||||
|
||||
@@ -183,7 +185,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$statictarget = new test_static_target_shortname();
|
||||
$statictarget = new \test_static_target_shortname();
|
||||
$indicators['test_indicator_max'] = \core_analytics\manager::get_indicator('test_indicator_max');
|
||||
$model = \core_analytics\model::create($statictarget, $indicators, '\core\analytics\time_splitting\quarters');
|
||||
$modelobj = $model->get_model_obj();
|
||||
@@ -301,11 +303,11 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$courses[$analysable->get_id()] = $course;
|
||||
}
|
||||
|
||||
$target = new test_target_course_level_shortname();
|
||||
$target = new \test_target_course_level_shortname();
|
||||
$analyser = new \core\analytics\analyser\courses(1, $target, [], [], []);
|
||||
|
||||
$result = new \core_analytics\local\analysis\result_array(1, false, []);
|
||||
$analysis = new test_analysis($analyser, false, $result);
|
||||
$analysis = new \test_analysis($analyser, false, $result);
|
||||
|
||||
// Each analysable element takes 0.5 secs minimum (test_analysis), so the max (and likely) number of analysable
|
||||
// elements that will be processed is 2.
|
||||
@@ -342,7 +344,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
|
||||
// Training and prediction data do not get mixed.
|
||||
$result = new \core_analytics\local\analysis\result_array(1, false, []);
|
||||
$analysis = new test_analysis($analyser, false, $result);
|
||||
$analysis = new \test_analysis($analyser, false, $result);
|
||||
$analysis->run();
|
||||
$params = array('modelid' => 1, 'action' => 'training');
|
||||
$this->assertLessThanOrEqual(2, $DB->count_records('analytics_used_analysables', $params));
|
||||
@@ -402,7 +404,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
$this->model->update(true, [], false);
|
||||
$this->assertFalse($this->model->can_export_configuration());
|
||||
|
||||
$statictarget = new test_static_target_shortname();
|
||||
$statictarget = new \test_static_target_shortname();
|
||||
$indicators['test_indicator_max'] = \core_analytics\manager::get_indicator('test_indicator_max');
|
||||
$model = \core_analytics\model::create($statictarget, $indicators, '\\core\\analytics\\time_splitting\\quarters');
|
||||
$this->assertFalse($model->can_export_configuration());
|
||||
@@ -418,7 +420,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
|
||||
$modelconfig = new \core_analytics\model_config($this->model);
|
||||
|
||||
$method = new ReflectionMethod('\\core_analytics\\model_config', 'export_model_data');
|
||||
$method = new \ReflectionMethod('\\core_analytics\\model_config', 'export_model_data');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$modeldata = $method->invoke($modelconfig);
|
||||
@@ -566,7 +568,7 @@ class analytics_model_testcase extends advanced_testcase {
|
||||
private function add_fake_log() {
|
||||
global $DB, $USER;
|
||||
|
||||
$log = new stdClass();
|
||||
$log = new \stdClass();
|
||||
$log->modelid = $this->modelobj->id;
|
||||
$log->version = $this->modelobj->version;
|
||||
$log->target = $this->modelobj->target;
|
||||
|
||||
@@ -14,13 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for prediction actions.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -34,7 +28,7 @@ require_once(__DIR__ . '/fixtures/test_target_shortname.php');
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_prediction_actions_testcase extends advanced_testcase {
|
||||
class prediction_actions_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Common startup tasks
|
||||
|
||||
@@ -14,21 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for evaluation, training and prediction.
|
||||
*
|
||||
* NOTE: in order to execute this test using a separate server for the
|
||||
* python ML backend you need to define these variables in your config.php file:
|
||||
*
|
||||
* define('TEST_MLBACKEND_PYTHON_HOST', '127.0.0.1');
|
||||
* define('TEST_MLBACKEND_PYTHON_PORT', 5000);
|
||||
* define('TEST_MLBACKEND_PYTHON_USERNAME', 'default');
|
||||
* define('TEST_MLBACKEND_PYTHON_PASSWORD', 'sshhhh');
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -48,11 +34,19 @@ require_once(__DIR__ . '/../../course/lib.php');
|
||||
/**
|
||||
* Unit tests for evaluation, training and prediction.
|
||||
*
|
||||
* NOTE: in order to execute this test using a separate server for the
|
||||
* python ML backend you need to define these variables in your config.php file:
|
||||
*
|
||||
* define('TEST_MLBACKEND_PYTHON_HOST', '127.0.0.1');
|
||||
* define('TEST_MLBACKEND_PYTHON_PORT', 5000);
|
||||
* define('TEST_MLBACKEND_PYTHON_USERNAME', 'default');
|
||||
* define('TEST_MLBACKEND_PYTHON_PASSWORD', 'sshhhh');
|
||||
*
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
class prediction_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Purge all the mlbackend outputs.
|
||||
@@ -746,7 +740,7 @@ class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
$samples,
|
||||
$ranges
|
||||
);
|
||||
$dataset = phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
$dataset = \phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
'\core_analytics\analysis');
|
||||
$this->assertArrayHasKey('123-0', $dataset);
|
||||
$this->assertArrayHasKey('123-1', $dataset);
|
||||
@@ -770,7 +764,7 @@ class core_analytics_prediction_testcase extends advanced_testcase {
|
||||
$samples,
|
||||
$ranges
|
||||
);
|
||||
$dataset = phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
$dataset = \phpunit_util::call_internal_method($analysis, 'calculate_indicators', $params,
|
||||
'\core_analytics\analysis');
|
||||
$this->assertArrayNotHasKey('123-0', $dataset);
|
||||
$this->assertArrayNotHasKey('123-1', $dataset);
|
||||
|
||||
@@ -14,14 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Provides the {@link analytics_stats_testcase} class.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @category test
|
||||
* @copyright 2019 David Mudrák <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -31,10 +24,12 @@ require_once(__DIR__ . '/fixtures/test_target_shortname.php');
|
||||
/**
|
||||
* Unit tests for the analytics stats.
|
||||
*
|
||||
* @package core_analytics
|
||||
* @category test
|
||||
* @copyright 2019 David Mudrák <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class analytics_stats_testcase extends advanced_testcase {
|
||||
class stats_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Set up the test environment.
|
||||
|
||||
@@ -14,30 +14,26 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core time splitting methods.
|
||||
*
|
||||
* @package core
|
||||
* @category analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace core_analytics;
|
||||
|
||||
use test_timesplitting_seconds;
|
||||
use test_timesplitting_upcoming_seconds;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_seconds.php');
|
||||
require_once(__DIR__ . '/../../analytics/tests/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_seconds.php');
|
||||
require_once(__DIR__ . '/fixtures/test_timesplitting_upcoming_seconds.php');
|
||||
require_once(__DIR__ . '/../../lib/enrollib.php');
|
||||
|
||||
/**
|
||||
* Unit tests for core time splitting methods.
|
||||
*
|
||||
* @package core
|
||||
* @category analytics
|
||||
* @category test
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
class time_splittings_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* setUp
|
||||
@@ -214,7 +210,7 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
|
||||
// We now use an ongoing course not yet ready to generate predictions.
|
||||
|
||||
$threedaysago = new DateTime('-3 days');
|
||||
$threedaysago = new \DateTime('-3 days');
|
||||
$params = array(
|
||||
'startdate' => $threedaysago->getTimestamp(),
|
||||
);
|
||||
@@ -229,7 +225,7 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
|
||||
// We now use a ready-to-predict ongoing course.
|
||||
|
||||
$onemonthago = new DateTime('-30 days');
|
||||
$onemonthago = new \DateTime('-30 days');
|
||||
$params = array(
|
||||
'startdate' => $onemonthago->getTimestamp(),
|
||||
);
|
||||
@@ -284,10 +280,10 @@ class core_analytics_time_splittings_testcase extends advanced_testcase {
|
||||
|
||||
// We now check how new ranges get added as time passes.
|
||||
|
||||
$fewsecsago = new DateTime('-5 seconds');
|
||||
$fewsecsago = new \DateTime('-5 seconds');
|
||||
$params = array(
|
||||
'startdate' => $fewsecsago->getTimestamp(),
|
||||
'enddate' => (new DateTimeImmutable('+1 year'))->getTimestamp(),
|
||||
'enddate' => (new \DateTimeImmutable('+1 year'))->getTimestamp(),
|
||||
);
|
||||
$course = $this->getDataGenerator()->create_course($params);
|
||||
$analysable = new \core_analytics\course($course);
|
||||
+4
-9
@@ -866,11 +866,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
if (!empty($users)) {
|
||||
print_string('userentriestoupdate', 'auth_ldap', count($users));
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$xcount = 0;
|
||||
$maxxcount = 100;
|
||||
|
||||
foreach ($users as $user) {
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
echo "\t"; print_string('auth_dbupdatinguser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id));
|
||||
$userinfo = $this->get_userinfo($user->username);
|
||||
if (!$this->update_user_record($user->username, $updatekeys, true,
|
||||
@@ -878,12 +875,11 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
echo ' - '.get_string('skipped');
|
||||
}
|
||||
echo "\n";
|
||||
$xcount++;
|
||||
|
||||
// Update system roles, if needed.
|
||||
$this->sync_roles($user);
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
unset($users); // free mem
|
||||
}
|
||||
} else { // end do updates
|
||||
@@ -903,8 +899,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
if (!empty($add_users)) {
|
||||
print_string('userentriestoadd', 'auth_ldap', count($add_users));
|
||||
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
foreach ($add_users as $user) {
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
$user = $this->get_userinfo_asobj($user->username);
|
||||
|
||||
// Prep a few params
|
||||
@@ -939,9 +935,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
// Add roles if needed.
|
||||
$this->sync_roles($euser);
|
||||
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
$transaction->allow_commit();
|
||||
unset($add_users); // free mem
|
||||
} else {
|
||||
print_string('nouserstobeadded', 'auth_ldap');
|
||||
|
||||
@@ -482,13 +482,13 @@ class tree extends tree_node {
|
||||
*
|
||||
* @param bool $not True if there is a NOT in effect
|
||||
* @param info $info Information about location of condition tree
|
||||
* @param result $result Result object if this is a student display, else null
|
||||
* @param result|null $result Result object if this is a student display, else null
|
||||
* @param bool $root True if this is the root item
|
||||
* @param bool $hidden Staff display; true if this tree has show=false (from parent)
|
||||
* @return string|renderable Information to render
|
||||
*/
|
||||
protected function get_full_information_recursive(
|
||||
$not, info $info, result $result = null, $root, $hidden = false) {
|
||||
$not, info $info, ?result $result, $root, $hidden = false) {
|
||||
// Get list of children - either full list, or those which are shown.
|
||||
$children = $this->children;
|
||||
$staff = true;
|
||||
|
||||
@@ -49,7 +49,7 @@ class frontend extends \core_availability\frontend {
|
||||
|
||||
protected function get_javascript_strings() {
|
||||
return array('ajaxerror', 'direction_before', 'direction_from', 'direction_until',
|
||||
'direction_label');
|
||||
'direction_label', 'error_dateconflict');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,7 @@ $string['direction_from'] = 'from';
|
||||
$string['direction_label'] = 'Direction';
|
||||
$string['direction_until'] = 'until';
|
||||
$string['description'] = 'Prevent access until (or from) a specified date and time.';
|
||||
$string['error_dateconflict'] = 'Conflicts with other date restrictions';
|
||||
$string['full_from'] = 'It is after <strong>{$a}</strong>';
|
||||
$string['full_from_date'] = 'It is on or after <strong>{$a}</strong>';
|
||||
$string['full_until'] = 'It is before <strong>{$a}</strong>';
|
||||
|
||||
+79
@@ -142,5 +142,84 @@ M.availability_date.form.fillValue = function(value, node) {
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
*/
|
||||
M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, currentNode) {
|
||||
var shouldSkip = false;
|
||||
tree.forEach(function(node) {
|
||||
if (shouldSkip) {
|
||||
return;
|
||||
}
|
||||
if (node.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then return.
|
||||
if (node.t === parseInt(currentNode.getData('time'), 10)
|
||||
&& currentNode.one('select[name=direction]').get('value') == node.d) {
|
||||
shouldSkip = true;
|
||||
return;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check current node.
|
||||
*
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} currentNode The curent node.
|
||||
*
|
||||
* @return {boolean} error Return true if the date is conflict.
|
||||
*/
|
||||
M.availability_date.form.checkConditionDate = function(currentNode) {
|
||||
var error = false;
|
||||
if (M.core_availability.form.rootList.getValue().op === '&') {
|
||||
var jsValue = M.core_availability.form.rootList.getValue().c;
|
||||
var arrayDateNode = M.availability_date.form.convertTreeDateValue(jsValue, [], currentNode);
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
arrayDateNode.forEach(function(checkNode) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
var error = M.availability_date.form.checkConditionDate(node);
|
||||
if (error) {
|
||||
errors.push('availability_date:error_dateconflict');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event", "io", "moodle-core_availability-form"]});
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-availability_date-form",function(o,e){M.availability_date=M.availability_date||{},M.availability_date.form=o.Object(M.core_availability.plugin),M.availability_date.form.initInner=function(e,a){this.html=e,this.defaultTime=a},M.availability_date.form.getNode=function(e){var t,i,a='<span class="col-form-label pr-3">'+M.util.get_string("direction_before","availability_date")+'</span> <span class="availability-group"><label><span class="accesshide">'+M.util.get_string("direction_label","availability_date")+' </span><select name="direction" class="custom-select"><option value=">=">'+M.util.get_string("direction_from","availability_date")+'</option><option value="<">'+M.util.get_string("direction_until","availability_date")+"</option></select></label></span> "+this.html,n=o.Node.create("<span>"+a+"</span>");return e.t!==undefined?(n.setData("time",e.t),n.all("select:not([name=direction])").each(function(e){e.set("disabled",!0)}),a=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=fromtime&time="+e.t,o.io(a,{on:{success:function(e,a){var t,i,l=o.JSON.parse(a.responseText);for(t in l)(i=n.one("select[name=x\\["+t+"\\]]")).set("value",""+l[t]),i.set("disabled",!1)},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})):n.setData("time",this.defaultTime),e.d!==undefined&&n.one("select[name=direction]").set("value",e.d),M.availability_date.form.addedEvents||(M.availability_date.form.addedEvents=!0,(a=o.one(".availability-field")).delegate("change",function(){M.core_availability.form.update()},".availability_date select[name=direction]"),a.delegate("change",function(){M.availability_date.form.updateTime(this.ancestor("span.availability_date"))},".availability_date select:not([name=direction])")),n.one("a[href=#]")&&(M.form.dateselector.init_single_date_selector(n),t=n.one("select[name=x\\[year\\]]"),i=t.set,t.set=function(e,a){i.call(t,e,a),"selectedIndex"===e&&setTimeout(function(){M.availability_date.form.updateTime(n)},0)}),n},M.availability_date.form.updateTime=function(t){var e=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=totime&year="+t.one("select[name=x\\[year\\]]").get("value")+"&month="+t.one("select[name=x\\[month\\]]").get("value")+"&day="+t.one("select[name=x\\[day\\]]").get("value")+"&hour="+t.one("select[name=x\\[hour\\]]").get("value")+"&minute="+t.one("select[name=x\\[minute\\]]").get("value");o.io(e,{on:{success:function(e,a){t.setData("time",a.responseText),M.core_availability.form.update()},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})},M.availability_date.form.fillValue=function(e,a){e.d=a.one("select[name=direction]").get("value"),e.t=parseInt(a.getData("time"),10)}},"@VERSION@",{requires:["base","node","event","io","moodle-core_availability-form"]});
|
||||
YUI.add("moodle-availability_date-form",function(o,e){M.availability_date=M.availability_date||{},M.availability_date.form=o.Object(M.core_availability.plugin),M.availability_date.form.initInner=function(e,a){this.html=e,this.defaultTime=a},M.availability_date.form.getNode=function(e){var t,i,a='<span class="col-form-label pr-3">'+M.util.get_string("direction_before","availability_date")+'</span> <span class="availability-group"><label><span class="accesshide">'+M.util.get_string("direction_label","availability_date")+' </span><select name="direction" class="custom-select"><option value=">=">'+M.util.get_string("direction_from","availability_date")+'</option><option value="<">'+M.util.get_string("direction_until","availability_date")+"</option></select></label></span> "+this.html,n=o.Node.create("<span>"+a+"</span>");return e.t!==undefined?(n.setData("time",e.t),n.all("select:not([name=direction])").each(function(e){e.set("disabled",!0)}),a=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=fromtime&time="+e.t,o.io(a,{on:{success:function(e,a){var t,i,l=o.JSON.parse(a.responseText);for(t in l)(i=n.one("select[name=x\\["+t+"\\]]")).set("value",""+l[t]),i.set("disabled",!1)},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})):n.setData("time",this.defaultTime),e.d!==undefined&&n.one("select[name=direction]").set("value",e.d),M.availability_date.form.addedEvents||(M.availability_date.form.addedEvents=!0,(a=o.one(".availability-field")).delegate("change",function(){M.core_availability.form.update()},".availability_date select[name=direction]"),a.delegate("change",function(){M.availability_date.form.updateTime(this.ancestor("span.availability_date"))},".availability_date select:not([name=direction])")),n.one("a[href=#]")&&(M.form.dateselector.init_single_date_selector(n),t=n.one("select[name=x\\[year\\]]"),i=t.set,t.set=function(e,a){i.call(t,e,a),"selectedIndex"===e&&setTimeout(function(){M.availability_date.form.updateTime(n)},0)}),n},M.availability_date.form.updateTime=function(t){var e=M.cfg.wwwroot+"/availability/condition/date/ajax.php?action=totime&year="+t.one("select[name=x\\[year\\]]").get("value")+"&month="+t.one("select[name=x\\[month\\]]").get("value")+"&day="+t.one("select[name=x\\[day\\]]").get("value")+"&hour="+t.one("select[name=x\\[hour\\]]").get("value")+"&minute="+t.one("select[name=x\\[minute\\]]").get("value");o.io(e,{on:{success:function(e,a){t.setData("time",a.responseText),M.core_availability.form.update()},failure:function(){window.alert(M.util.get_string("ajaxerror","availability_date"))}}})},M.availability_date.form.fillValue=function(e,a){e.d=a.one("select[name=direction]").get("value"),e.t=parseInt(a.getData("time"),10)},M.availability_date.form.convertTreeDateValue=function(e,a,t){var i=!1;return e.forEach(function(e){i||("date"===e.type?e.t!==parseInt(t.getData("time"),10)||t.one("select[name=direction]").get("value")!=e.d?a.push(e):i=!0:e.type===undefined&&M.availability_date.form.convertTreeDateValue(e.c,a,t))}),a},M.availability_date.form.checkConditionDate=function(e){var a,t,i,l=!1;return"&"===M.core_availability.form.rootList.getValue().op?(a=M.core_availability.form.rootList.getValue().c,a=M.availability_date.form.convertTreeDateValue(a,[],e),t=e.one("select[name=direction]").get("value"),i=parseInt(e.getData("time"),10),a.forEach(function(e){return"<"===e.d?">="===t&&i>=e.t&&(l=!0):"<"===t&&i<=e.t&&(l=!0),l})):e.one("div > .badge-warning")&&e.one("div > .badge-warning").remove(),l},M.availability_date.form.fillErrors=function(e,a){M.availability_date.form.checkConditionDate(a)&&e.push("availability_date:error_dateconflict")}},"@VERSION@",{requires:["base","node","event","io","moodle-core_availability-form"]});
|
||||
availability/condition/date/yui/build/moodle-availability_date-form/moodle-availability_date-form.js
Vendored
+79
@@ -142,5 +142,84 @@ M.availability_date.form.fillValue = function(value, node) {
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
*/
|
||||
M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, currentNode) {
|
||||
var shouldSkip = false;
|
||||
tree.forEach(function(node) {
|
||||
if (shouldSkip) {
|
||||
return;
|
||||
}
|
||||
if (node.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then return.
|
||||
if (node.t === parseInt(currentNode.getData('time'), 10)
|
||||
&& currentNode.one('select[name=direction]').get('value') == node.d) {
|
||||
shouldSkip = true;
|
||||
return;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check current node.
|
||||
*
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} currentNode The curent node.
|
||||
*
|
||||
* @return {boolean} error Return true if the date is conflict.
|
||||
*/
|
||||
M.availability_date.form.checkConditionDate = function(currentNode) {
|
||||
var error = false;
|
||||
if (M.core_availability.form.rootList.getValue().op === '&') {
|
||||
var jsValue = M.core_availability.form.rootList.getValue().c;
|
||||
var arrayDateNode = M.availability_date.form.convertTreeDateValue(jsValue, [], currentNode);
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
arrayDateNode.forEach(function(checkNode) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
var error = M.availability_date.form.checkConditionDate(node);
|
||||
if (error) {
|
||||
errors.push('availability_date:error_dateconflict');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}, '@VERSION@', {"requires": ["base", "node", "event", "io", "moodle-core_availability-form"]});
|
||||
|
||||
@@ -139,3 +139,82 @@ M.availability_date.form.fillValue = function(value, node) {
|
||||
value.d = node.one('select[name=direction]').get('value');
|
||||
value.t = parseInt(node.getData('time'), 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* List out Date node value in an array node.
|
||||
*
|
||||
* This will go through all array node and list from earlier date node to current date node.
|
||||
*
|
||||
* @method convertTreeDateValue
|
||||
* @param {array} tree Tree node to convert
|
||||
* @param {array} arrayDateNode
|
||||
* @param {array} currentNode current node.
|
||||
*
|
||||
* @return {array} arrayDateNode
|
||||
*/
|
||||
M.availability_date.form.convertTreeDateValue = function(tree, arrayDateNode, currentNode) {
|
||||
var shouldSkip = false;
|
||||
tree.forEach(function(node) {
|
||||
if (shouldSkip) {
|
||||
return;
|
||||
}
|
||||
if (node.type === 'date') {
|
||||
// We go through all tree node, if we meet the current node then return.
|
||||
if (node.t === parseInt(currentNode.getData('time'), 10)
|
||||
&& currentNode.one('select[name=direction]').get('value') == node.d) {
|
||||
shouldSkip = true;
|
||||
return;
|
||||
}
|
||||
arrayDateNode.push(node);
|
||||
} else if (node.type === undefined) {
|
||||
M.availability_date.form.convertTreeDateValue(node.c, arrayDateNode, currentNode);
|
||||
}
|
||||
});
|
||||
return arrayDateNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check current node.
|
||||
*
|
||||
* This will check current date node with all date node in tree node.
|
||||
*
|
||||
* @method checkConditionDate
|
||||
* @param {array} currentNode The curent node.
|
||||
*
|
||||
* @return {boolean} error Return true if the date is conflict.
|
||||
*/
|
||||
M.availability_date.form.checkConditionDate = function(currentNode) {
|
||||
var error = false;
|
||||
if (M.core_availability.form.rootList.getValue().op === '&') {
|
||||
var jsValue = M.core_availability.form.rootList.getValue().c;
|
||||
var arrayDateNode = M.availability_date.form.convertTreeDateValue(jsValue, [], currentNode);
|
||||
var currentNodeDirection = currentNode.one('select[name=direction]').get('value');
|
||||
var currentNodeTime = parseInt(currentNode.getData('time'), 10);
|
||||
arrayDateNode.forEach(function(checkNode) {
|
||||
// Validate if the date is conflict.
|
||||
if (checkNode.d === '<') {
|
||||
if (currentNodeDirection === '>=' && currentNodeTime >= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
} else {
|
||||
if (currentNodeDirection === '<' && currentNodeTime <= checkNode.t) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
return error;
|
||||
});
|
||||
return error;
|
||||
} else {
|
||||
if (currentNode.one('div > .badge-warning')) {
|
||||
currentNode.one('div > .badge-warning').remove();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
M.availability_date.form.fillErrors = function(errors, node) {
|
||||
var error = M.availability_date.form.checkConditionDate(node);
|
||||
if (error) {
|
||||
errors.push('availability_date:error_dateconflict');
|
||||
}
|
||||
};
|
||||
|
||||
Vendored
+15
-1
@@ -971,7 +971,21 @@ M.core_availability.Item.prototype.fillErrors = function(errors) {
|
||||
// If any errors were added, add the marker to this item.
|
||||
var errorLabel = this.node.one('> .badge-warning');
|
||||
if (errors.length !== before && !errorLabel.get('firstChild')) {
|
||||
errorLabel.appendChild(document.createTextNode(M.util.get_string('invalid', 'availability')));
|
||||
var errorString = '';
|
||||
// Fetch the last error code from the array of errors and split using the ':' delimiter.
|
||||
var langString = errors[errors.length - 1].split(':');
|
||||
var component = langString[0];
|
||||
var identifier = langString[1];
|
||||
// If get_string can't find the string, it will return the string in this format.
|
||||
var undefinedString = '[[' + identifier + ',' + component + ']]';
|
||||
// Get the lang string.
|
||||
errorString = M.util.get_string(identifier, component);
|
||||
if (errorString === undefinedString) {
|
||||
// Use a generic invalid input message when the error lang string cannot be loaded.
|
||||
errorString = M.util.get_string('invalid', 'availability');
|
||||
}
|
||||
// Show the error string.
|
||||
errorLabel.appendChild(document.createTextNode(errorString));
|
||||
} else if (errors.length === before && errorLabel.get('firstChild')) {
|
||||
errorLabel.get('firstChild').remove();
|
||||
}
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+15
-1
@@ -971,7 +971,21 @@ M.core_availability.Item.prototype.fillErrors = function(errors) {
|
||||
// If any errors were added, add the marker to this item.
|
||||
var errorLabel = this.node.one('> .badge-warning');
|
||||
if (errors.length !== before && !errorLabel.get('firstChild')) {
|
||||
errorLabel.appendChild(document.createTextNode(M.util.get_string('invalid', 'availability')));
|
||||
var errorString = '';
|
||||
// Fetch the last error code from the array of errors and split using the ':' delimiter.
|
||||
var langString = errors[errors.length - 1].split(':');
|
||||
var component = langString[0];
|
||||
var identifier = langString[1];
|
||||
// If get_string can't find the string, it will return the string in this format.
|
||||
var undefinedString = '[[' + identifier + ',' + component + ']]';
|
||||
// Get the lang string.
|
||||
errorString = M.util.get_string(identifier, component);
|
||||
if (errorString === undefinedString) {
|
||||
// Use a generic invalid input message when the error lang string cannot be loaded.
|
||||
errorString = M.util.get_string('invalid', 'availability');
|
||||
}
|
||||
// Show the error string.
|
||||
errorLabel.appendChild(document.createTextNode(errorString));
|
||||
} else if (errors.length === before && errorLabel.get('firstChild')) {
|
||||
errorLabel.get('firstChild').remove();
|
||||
}
|
||||
|
||||
Vendored
+15
-1
@@ -969,7 +969,21 @@ M.core_availability.Item.prototype.fillErrors = function(errors) {
|
||||
// If any errors were added, add the marker to this item.
|
||||
var errorLabel = this.node.one('> .badge-warning');
|
||||
if (errors.length !== before && !errorLabel.get('firstChild')) {
|
||||
errorLabel.appendChild(document.createTextNode(M.util.get_string('invalid', 'availability')));
|
||||
var errorString = '';
|
||||
// Fetch the last error code from the array of errors and split using the ':' delimiter.
|
||||
var langString = errors[errors.length - 1].split(':');
|
||||
var component = langString[0];
|
||||
var identifier = langString[1];
|
||||
// If get_string can't find the string, it will return the string in this format.
|
||||
var undefinedString = '[[' + identifier + ',' + component + ']]';
|
||||
// Get the lang string.
|
||||
errorString = M.util.get_string(identifier, component);
|
||||
if (errorString === undefinedString) {
|
||||
// Use a generic invalid input message when the error lang string cannot be loaded.
|
||||
errorString = M.util.get_string('invalid', 'availability');
|
||||
}
|
||||
// Show the error string.
|
||||
errorLabel.appendChild(document.createTextNode(errorString));
|
||||
} else if (errors.length === before && errorLabel.get('firstChild')) {
|
||||
errorLabel.get('firstChild').remove();
|
||||
}
|
||||
|
||||
@@ -4239,7 +4239,8 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
|
||||
// Look for the parent contextid
|
||||
if (!$data->parentcontextid = $this->get_mappingid('context', $data->parentcontextid)) {
|
||||
throw new restore_step_exception('restore_block_missing_parent_ctx', $data->parentcontextid);
|
||||
// Parent contextid does not exist, ignore this block.
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: it would be nice to use standard plugin supports instead of this instance_allow_multiple()
|
||||
@@ -4285,14 +4286,17 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
$params['subpagepattern'] = $data->subpagepattern;
|
||||
}
|
||||
|
||||
$exists = $DB->record_exists_sql("SELECT bi.id
|
||||
$existingblock = $DB->get_records_sql("SELECT bi.id
|
||||
FROM {block_instances} bi
|
||||
JOIN {block} b ON b.name = bi.blockname
|
||||
WHERE bi.blockname = :blockname
|
||||
AND $contextsql
|
||||
AND bi.pagetypepattern $pagetypepatternsql
|
||||
AND $subpagepatternsql", $params);
|
||||
if ($exists) {
|
||||
if (!empty($existingblock)) {
|
||||
// Save the context mapping in case something else is linking to this block's context.
|
||||
$newcontext = context_block::instance(reset($existingblock)->id);
|
||||
$this->set_mapping('context', $oldcontextid, $newcontext->id);
|
||||
// There is at least one very similar block visible on the page where we
|
||||
// are trying to restore the block. In these circumstances the block API
|
||||
// would not allow the user to add another instance of the block, so we
|
||||
@@ -4311,6 +4315,9 @@ class restore_block_instance_structure_step extends restore_structure_step {
|
||||
if ($birecs = $DB->get_records('block_instances', $params)) {
|
||||
foreach($birecs as $birec) {
|
||||
if ($birec->configdata == $data->configdata) {
|
||||
// Save the context mapping in case something else is linking to this block's context.
|
||||
$newcontext = context_block::instance($birec->id);
|
||||
$this->set_mapping('context', $oldcontextid, $newcontext->id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5296,7 +5303,8 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($info->oldfile->repositorytype === 'local' or $info->oldfile->repositorytype === 'coursefiles') {
|
||||
if ($info->oldfile->repositorytype === 'local' || $info->oldfile->repositorytype === 'coursefiles'
|
||||
|| $info->oldfile->repositorytype === 'contentbank') {
|
||||
// Aliases to Server files and Legacy course files may refer to a file
|
||||
// contained in the backup file or to some existing file (if we are on the
|
||||
// same site).
|
||||
@@ -5459,7 +5467,8 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
|
||||
// Both Server files and Legacy course files repositories have a single
|
||||
// instance at the system context to use. Let us try to find it.
|
||||
if ($info->oldfile->repositorytype === 'local' or $info->oldfile->repositorytype === 'coursefiles') {
|
||||
if ($info->oldfile->repositorytype === 'local' || $info->oldfile->repositorytype === 'coursefiles'
|
||||
|| $info->oldfile->repositorytype === 'contentbank') {
|
||||
$sql = "SELECT ri.id
|
||||
FROM {repository} r
|
||||
JOIN {repository_instances} ri ON ri.typeid = r.id
|
||||
|
||||
@@ -145,9 +145,11 @@ abstract class convert_helper {
|
||||
$firstchars = fread($handle, 200);
|
||||
$status = fclose($handle);
|
||||
|
||||
if (strpos($firstchars,'<?xml version="1.0" encoding="UTF-8"?>') !== false and
|
||||
strpos($firstchars,'<moodle_backup>') !== false and
|
||||
strpos($firstchars,'<information>') !== false) {
|
||||
// Look for expected XML elements (case-insensitive to account for encoding attribute).
|
||||
if (stripos($firstchars, '<?xml version="1.0" encoding="UTF-8"?>') !== false &&
|
||||
strpos($firstchars, '<moodle_backup>') !== false &&
|
||||
strpos($firstchars, '<information>') !== false) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -643,7 +643,7 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
|
||||
}
|
||||
$output .= $renderer->get_samesite_notification();
|
||||
$output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
|
||||
$output .= $renderer->continue_button($restorerul);
|
||||
$output .= $renderer->continue_button($restorerul, 'get');
|
||||
$output .= $renderer->box_end();
|
||||
|
||||
return $output;
|
||||
|
||||
@@ -553,7 +553,8 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a continue button
|
||||
* Displays a continue button, overriding core renderer method of the same in order
|
||||
* to override submission method of the button form
|
||||
*
|
||||
* @param string|moodle_url $url
|
||||
* @param string $method
|
||||
@@ -566,7 +567,6 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
if ($method != 'post') {
|
||||
$method = 'get';
|
||||
}
|
||||
$url->param('sesskey', sesskey());
|
||||
$button = new single_button($url, get_string('continue'), $method, true);
|
||||
$button->class = 'continuebutton';
|
||||
return $this->render($button);
|
||||
|
||||
@@ -1161,8 +1161,10 @@ class restore_ui_stage_complete extends restore_ui_stage_process {
|
||||
$html .= $renderer->notification(get_string('restorefileweremissing', 'backup'), 'notifyproblem');
|
||||
}
|
||||
$html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
|
||||
$html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
|
||||
'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
|
||||
|
||||
$courseurl = course_get_url($this->get_ui()->get_controller()->get_courseid());
|
||||
$html .= $renderer->continue_button($courseurl, 'get');
|
||||
|
||||
$html .= $renderer->box_end();
|
||||
|
||||
return $html;
|
||||
|
||||
@@ -21,7 +21,7 @@ Feature: Restore Moodle 2 course backups with different user data settings
|
||||
| data | Test database name | n | C1 | data1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Text input" field to "Test database name" database and I fill the form with:
|
||||
And I add a "Short text" field to "Test database name" database and I fill the form with:
|
||||
| Field name | Test field name |
|
||||
| Field description | Test field description |
|
||||
And I follow "Templates"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace block_accessreview\tests;
|
||||
namespace block_accessreview;
|
||||
|
||||
use ReflectionClass;
|
||||
use advanced_testcase;
|
||||
|
||||
@@ -36,7 +36,7 @@ class moodle1_block_html_handler extends moodle1_block_handler {
|
||||
$contextid = $this->converter->get_contextid(CONTEXT_BLOCK, $olddata['id']);
|
||||
$decodeddata = base64_decode($olddata['configdata']);
|
||||
list($updated, $configdata) = upgrade_fix_serialized_objects($decodeddata);
|
||||
$configdata = unserialize($configdata);
|
||||
$configdata = unserialize_object($configdata);
|
||||
|
||||
// get a fresh new file manager for this instance
|
||||
$this->fileman = $this->converter->get_file_manager($contextid, 'block_html');
|
||||
@@ -44,7 +44,7 @@ class moodle1_block_html_handler extends moodle1_block_handler {
|
||||
// convert course files embedded in the block content
|
||||
$this->fileman->filearea = 'content';
|
||||
$this->fileman->itemid = 0;
|
||||
$configdata->text = moodle1_converter::migrate_referenced_files($configdata->text, $this->fileman);
|
||||
$configdata->text = moodle1_converter::migrate_referenced_files($configdata->text ?? '', $this->fileman);
|
||||
$configdata->format = FORMAT_HTML;
|
||||
|
||||
return base64_encode(serialize($configdata));
|
||||
|
||||
@@ -83,7 +83,8 @@ class content extends \core_search\base_block {
|
||||
|
||||
$context = \context::instance_by_id($document->get('contextid'));
|
||||
|
||||
$files = $fs->get_area_files($context->id, 'block_html', 'content');
|
||||
$files = $fs->get_area_files($context->id, 'block_html', 'content',
|
||||
false, 'itemid, filepath, filename', false);
|
||||
foreach ($files as $file) {
|
||||
$document->add_stored_file($file);
|
||||
}
|
||||
|
||||
@@ -137,11 +137,9 @@ class search_content_test extends \advanced_testcase {
|
||||
$this->assertCount(0, $doc->get_files());
|
||||
$area->attach_files($doc);
|
||||
$files = $doc->get_files();
|
||||
$this->assertCount(2, $files);
|
||||
// The directory entry should NOT be provided for indexing.
|
||||
$this->assertCount(1, $files);
|
||||
foreach ($files as $file) {
|
||||
if ($file->is_directory()) {
|
||||
continue;
|
||||
}
|
||||
$this->assertEquals('file.txt', $file->get_filename());
|
||||
$this->assertEquals('File content', $file->get_content());
|
||||
}
|
||||
|
||||
Vendored
+7
-5
@@ -358,17 +358,19 @@ class cachestore_file extends cache_store implements cache_is_key_aware, cache_i
|
||||
if (!$handle = fopen($file, 'rb')) {
|
||||
return false;
|
||||
}
|
||||
// Lock it up!
|
||||
// We don't care if this succeeds or not, on some systems it will, on some it won't, meah either way.
|
||||
flock($handle, LOCK_SH);
|
||||
|
||||
// Note: There is no need to perform any file locking here.
|
||||
// The cache file is only ever written to in the `write_file` function, where it does so by writing to a temp
|
||||
// file and performing an atomic rename of that file. The target file is never locked, so there is no benefit to
|
||||
// obtaining a lock (shared or exclusive) here.
|
||||
|
||||
$data = '';
|
||||
// Read the data in 1Mb chunks. Small caches will not loop more than once. We don't use filesize as it may
|
||||
// be cached with a different value than what we need to read from the file.
|
||||
do {
|
||||
$data .= fread($handle, 1048576);
|
||||
} while (!feof($handle));
|
||||
// Unlock it.
|
||||
flock($handle, LOCK_UN);
|
||||
|
||||
// Return it unserialised.
|
||||
return $this->prep_data_after_read($data);
|
||||
}
|
||||
|
||||
@@ -180,8 +180,13 @@ class container {
|
||||
$course = new \stdClass();
|
||||
$course->id = $dbrow->courseid;
|
||||
$completion = new \completion_info($course);
|
||||
|
||||
return (bool) !$completion->is_enabled($cm);
|
||||
if ($completion->is_enabled($cm)) {
|
||||
// Check if the event is completed, then in this case we do not need to complete it.
|
||||
// Make sure we're using a cm_info object.
|
||||
$completiondata = $completion->get_data($cm);
|
||||
return intval($completiondata->completionstate) === COMPLETION_COMPLETE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -118,16 +118,16 @@ class event implements event_interface {
|
||||
* @param int $id The event's ID in the database.
|
||||
* @param string $name The event's name.
|
||||
* @param description_interface $description The event's description.
|
||||
* @param proxy_interface $category The category associated with the event.
|
||||
* @param proxy_interface $course The course associated with the event.
|
||||
* @param proxy_interface $group The group associated with the event.
|
||||
* @param proxy_interface $user The user associated with the event.
|
||||
* @param event_collection_interface $repeats Collection of repeat events.
|
||||
* @param proxy_interface $coursemodule The course module that created the event.
|
||||
* @param proxy_interface|null $category The category associated with the event.
|
||||
* @param proxy_interface|null $course The course associated with the event.
|
||||
* @param proxy_interface|null $group The group associated with the event.
|
||||
* @param proxy_interface|null $user The user associated with the event.
|
||||
* @param event_collection_interface|null $repeats Collection of repeat events.
|
||||
* @param proxy_interface|null $coursemodule The course module that created the event.
|
||||
* @param string $type The event's type.
|
||||
* @param times_interface $times The times associated with the event.
|
||||
* @param bool $visible The event's visibility. True for visible, false for invisible.
|
||||
* @param proxy_interface $subscription The event's subscription.
|
||||
* @param proxy_interface|null $subscription The event's subscription.
|
||||
* @param string $location The event's location.
|
||||
* @param string $component The event's component.
|
||||
*/
|
||||
@@ -135,12 +135,12 @@ class event implements event_interface {
|
||||
$id,
|
||||
$name,
|
||||
description_interface $description,
|
||||
proxy_interface $category = null,
|
||||
proxy_interface $course = null,
|
||||
proxy_interface $group = null,
|
||||
proxy_interface $user = null,
|
||||
event_collection_interface $repeats = null,
|
||||
proxy_interface $coursemodule = null,
|
||||
?proxy_interface $category,
|
||||
?proxy_interface $course,
|
||||
?proxy_interface $group,
|
||||
?proxy_interface $user,
|
||||
?event_collection_interface $repeats,
|
||||
?proxy_interface $coursemodule,
|
||||
$type,
|
||||
times_interface $times,
|
||||
$visible,
|
||||
|
||||
@@ -5,6 +5,8 @@ require_once('../config.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
require_once($CFG->libdir.'/bennu/bennu.inc.php');
|
||||
|
||||
raise_memory_limit(MEMORY_HUGE);
|
||||
|
||||
$userid = optional_param('userid', 0, PARAM_INT);
|
||||
$username = optional_param('username', '', PARAM_TEXT);
|
||||
$authtoken = required_param('authtoken', PARAM_ALPHANUM);
|
||||
|
||||
@@ -63,13 +63,13 @@
|
||||
<div class="commands float-sm-right">
|
||||
{{#canedit}}
|
||||
{{#candelete}}
|
||||
<a href="{{deleteurl}}" data-action="delete">
|
||||
{{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}
|
||||
<a href="{{deleteurl}}" data-action="delete" aria-label="{{#str}}delete{{/str}}" title="{{#str}}delete{{/str}}">
|
||||
{{#pix}}t/delete, core{{/pix}}
|
||||
</a>
|
||||
{{/candelete}}
|
||||
{{^isactionevent}}
|
||||
<a href="{{editurl}}" data-action="edit">
|
||||
{{#pix}}t/edit, core, {{#str}}edit{{/str}}{{/pix}}
|
||||
<a href="{{editurl}}" data-action="edit" aria-label="{{#str}}edit{{/str}}" title="{{#str}}edit{{/str}}">
|
||||
{{#pix}}t/edit, core{{/pix}}
|
||||
</a>
|
||||
{{/isactionevent}}
|
||||
{{/canedit}}
|
||||
|
||||
@@ -136,16 +136,39 @@ class behat_calendar extends behat_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a specific date in the calendar.
|
||||
* Navigate to a specific month in the calendar.
|
||||
*
|
||||
* @Given /^I view the calendar for "(?P<month>\d+)" "(?P<year>\d+)"$/
|
||||
* @param int $month the month selected as a number
|
||||
* @param int $year the four digit year
|
||||
*/
|
||||
public function i_view_the_calendar_for($month, $year) {
|
||||
$time = make_timestamp($year, $month, 1);
|
||||
$this->execute('behat_general::i_visit', ['/calendar/view.php?view=month&course=1&time='.$time]);
|
||||
$this->view_the_calendar('month', 1, $month, $year);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a specific date in the calendar.
|
||||
*
|
||||
* @Given /^I view the calendar for "(?P<day>\d+)" "(?P<month>\d+)" "(?P<year>\d+)"$/
|
||||
* @param int $day the day selected as a number
|
||||
* @param int $month the month selected as a number
|
||||
* @param int $year the four digit year
|
||||
*/
|
||||
public function i_view_the_calendar_day_view(int $day, int $month, int $year) {
|
||||
$this->view_the_calendar('day', $day, $month, $year);
|
||||
}
|
||||
|
||||
/**
|
||||
* View the correct calendar view with specific day
|
||||
*
|
||||
* @param string $type type of calendar view: month or day
|
||||
* @param int $day the day selected as a number
|
||||
* @param int $month the month selected as a number
|
||||
* @param int $year the four digit year
|
||||
*/
|
||||
private function view_the_calendar(string $type, int $day, int $month, int $year) {
|
||||
$time = make_timestamp($year, $month, $day);
|
||||
$this->execute('behat_general::i_visit', ['/calendar/view.php?view=' . $type . '&course=1&time=' . $time]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,3 +74,19 @@ Feature: Import and edit calendar events
|
||||
And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
|
||||
And I press "Add"
|
||||
And I should see "Site events"
|
||||
|
||||
Scenario: Import iCalendar file with parameter.
|
||||
Given I log in as "admin"
|
||||
And I view the calendar for "7" "2022"
|
||||
And I press "Manage subscriptions"
|
||||
And I set the following fields to these values:
|
||||
| Calendar name | Test Import |
|
||||
| Import from | Calendar file (.ics) |
|
||||
| Type of event | User |
|
||||
And I upload "calendar/tests/fixtures/import_with_parameters.ics" file to "Calendar file (.ics)" filemanager
|
||||
And I press "Add"
|
||||
When I view the calendar for "1" "7" "2022"
|
||||
Then I should see "First event"
|
||||
And I should see "Description of the first event"
|
||||
And I should see "Second event"
|
||||
And I should see "Description of the second event"
|
||||
|
||||
@@ -23,6 +23,7 @@ use core_calendar\local\event\factories\event_factory;
|
||||
use core_calendar\local\event\factories\event_factory_interface;
|
||||
use core_calendar\local\event\mappers\event_mapper;
|
||||
use core_calendar\local\event\mappers\event_mapper_interface;
|
||||
use core_completion\api;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -366,6 +367,41 @@ class container_test extends \advanced_testcase {
|
||||
$this->assertNull($factory->create_instance($event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that completed activities events do not show.
|
||||
* @covers \core_calendar\local\event::init
|
||||
*/
|
||||
public function test_event_factory_with_completed_module_related_event() {
|
||||
global $CFG, $DB;
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course);
|
||||
// Create an assign activity with a time set.
|
||||
$time = time();
|
||||
$assign = $this->getDataGenerator()->create_module(
|
||||
'assign', ['course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL]);
|
||||
|
||||
// Create the event but set it to tomorrow.
|
||||
$CFG->enablecompletion = true;
|
||||
api::update_completion_date_event($assign->cmid, 'assign', $assign,
|
||||
$time + DAYSECS);
|
||||
|
||||
$this->setUser($user);
|
||||
// Check that we get should be completed event.
|
||||
$this->assertCount(1, \core_calendar\local\event\container::get_event_vault()->get_events());
|
||||
// Then Complete the activity.
|
||||
$completion = new \completion_info($course);
|
||||
$cmassign = get_coursemodule_from_id('assign', $assign->cmid);
|
||||
// This should trigger another call to the update_completion_date_event.
|
||||
$completion->update_state($cmassign, COMPLETION_COMPLETE, $user->id);
|
||||
// Check that we do not see the event anymore.
|
||||
$this->assertCount(0, \core_calendar\local\event\container::get_event_vault()->get_events());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that the event factory only returns an event if the logged in user
|
||||
* is enrolled in the course.
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
BEGIN:VCALENDAR
|
||||
METHOD:PUBLISH
|
||||
PRODID:-//Huong Nguyen/NONSGML Moodle//EN
|
||||
VERSION:2.0
|
||||
BEGIN:VEVENT
|
||||
UID:special_import_moodle_1
|
||||
SUMMARY:First event
|
||||
DESCRIPTION:Description of the first event\n
|
||||
CLASS:PUBLIC
|
||||
LAST-MODIFIED:20220728T034015Z
|
||||
LOCATION:Vietnam
|
||||
DTSTAMP:20220728T034031Z
|
||||
DTSTART:20220701T070000Z
|
||||
DTEND:20220701T070000Z
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:special_import_moodle_2
|
||||
SUMMARY:Second event
|
||||
DESCRIPTION;ALTREP="http://moodle.com/":Description of the second event\n
|
||||
CLASS:PUBLIC
|
||||
LAST-MODIFIED:20220728T034021Z
|
||||
LOCATION:Vietnam
|
||||
DTSTAMP:20220728T034031Z
|
||||
DTSTART:20220701T080000Z
|
||||
DTEND:20220701T080000Z
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
+5
-5
@@ -12,13 +12,13 @@
|
||||
],
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "9.5.*",
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"behat/mink": "~1.8",
|
||||
"mikey179/vfsstream": "1.6.*",
|
||||
"behat/mink": "^1.10.0",
|
||||
"friends-of-behat/mink-extension": "dev-master",
|
||||
"behat/mink-goutte-driver": "~1.2",
|
||||
"behat/mink-goutte-driver": "^1.3",
|
||||
"symfony/process": "^4.0 || ^5.0",
|
||||
"behat/behat": "3.10.*",
|
||||
"oleg-andreyev/mink-phpwebdriver": "^1.0"
|
||||
"behat/behat": "3.11.*",
|
||||
"oleg-andreyev/mink-phpwebdriver": "^1.0.1"
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-0": {
|
||||
|
||||
Generated
+413
-657
File diff suppressed because it is too large
Load Diff
@@ -409,6 +409,9 @@ $CFG->admin = 'admin';
|
||||
// Print to footer (works with the default theme)
|
||||
// define('MDL_PERFTOFOOT', true);
|
||||
//
|
||||
// Print additional data to log of included files
|
||||
// define('MDL_PERFINC', true);
|
||||
//
|
||||
// Enable earlier profiling that causes more code to be covered
|
||||
// on every request (db connections, config load, other inits...).
|
||||
// Requires extra configuration to be defined in config.php like:
|
||||
|
||||
@@ -58,9 +58,9 @@ class bankcontent implements renderable, templatable {
|
||||
*
|
||||
* @param \core_contentbank\content[] $contents Array of content bank contents.
|
||||
* @param array $toolbar List of content bank toolbar options.
|
||||
* @param \context $context Optional context to check (default null)
|
||||
* @param \context|null $context Optional context to check (default null)
|
||||
*/
|
||||
public function __construct(array $contents, array $toolbar, \context $context = null) {
|
||||
public function __construct(array $contents, array $toolbar, ?\context $context) {
|
||||
$this->contents = $contents;
|
||||
$this->toolbar = $toolbar;
|
||||
$this->context = $context;
|
||||
|
||||
Vendored
+1
-1
@@ -5,6 +5,6 @@ define("core_course/repository",["exports","core/ajax"],(function(_exports,_ajax
|
||||
* @module core_course/repository
|
||||
* @copyright 2018 Ryan Wyllie <ryan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};var _default={getEnrolledCoursesByTimelineClassification:function(classification,limit,offset,sort){var args={classification:classification};void 0!==limit&&(args.limit=limit),void 0!==offset&&(args.offset=offset),void 0!==sort&&(args.sort=sort);var request={methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:args};return _ajax.default.call([request])[0]},getLastAccessedCourses:function(userid,limit,offset,sort){var args={};void 0!==userid&&(args.userid=userid),void 0!==limit&&(args.limit=limit),void 0!==offset&&(args.offset=offset),void 0!==sort&&(args.sort=sort);var request={methodname:"core_course_get_recent_courses",args:args};return _ajax.default.call([request])[0]},getUsersFromCourseModuleID:function(cmid,groupID){var request={methodname:"core_course_get_enrolled_users_by_cmid",args:{cmid:cmid,groupid:groupID}};return _ajax.default.call([request])[0]},toggleManualCompletion:function(cmid,completed){var request={methodname:"core_completion_update_activity_completion_status_manually",args:{cmid:cmid,completed:completed}};return _ajax.default.call([request])[0]}};return _exports.default=_default,_exports.default}));
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};var _default={getEnrolledCoursesByTimelineClassification:function(classification,limit,offset,sort){var args={classification:classification};void 0!==limit&&(args.limit=limit),void 0!==offset&&(args.offset=offset),void 0!==sort&&(args.sort=sort);var request={methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:args};return _ajax.default.call([request])[0]},getLastAccessedCourses:function(userid,limit,offset,sort){var args={};void 0!==userid&&(args.userid=userid),void 0!==limit&&(args.limit=limit),void 0!==offset&&(args.offset=offset),void 0!==sort&&(args.sort=sort);var request={methodname:"core_course_get_recent_courses",args:args};return _ajax.default.call([request])[0]},getUsersFromCourseModuleID:function(cmid,groupID){var onlyActive=arguments.length>2&&void 0!==arguments[2]&&arguments[2],request={methodname:"core_course_get_enrolled_users_by_cmid",args:{cmid:cmid,groupid:groupID,onlyactive:onlyActive}};return _ajax.default.call([request])[0]},toggleManualCompletion:function(cmid,completed){var request={methodname:"core_completion_update_activity_completion_status_manually",args:{cmid:cmid,completed:completed}};return _ajax.default.call([request])[0]}};return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=repository.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -100,14 +100,16 @@ const getLastAccessedCourses = (userid, limit, offset, sort) => {
|
||||
*
|
||||
* @param {Number} cmid Course Module from which the users will be obtained
|
||||
* @param {Number} groupID Group ID from which the users will be obtained
|
||||
* @param {Boolean} onlyActive Whether to fetch only the active enrolled users or all enrolled users in the course.
|
||||
* @returns {Promise} Promise containing a list of users
|
||||
*/
|
||||
const getEnrolledUsersFromCourseModuleID = (cmid, groupID) => {
|
||||
const getEnrolledUsersFromCourseModuleID = (cmid, groupID, onlyActive = false) => {
|
||||
var request = {
|
||||
methodname: 'core_course_get_enrolled_users_by_cmid',
|
||||
args: {
|
||||
cmid: cmid,
|
||||
groupid: groupID,
|
||||
onlyactive: onlyActive,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -4103,6 +4103,8 @@ class core_course_external extends external_api {
|
||||
return new external_function_parameters([
|
||||
'cmid' => new external_value(PARAM_INT, 'id of the course module', VALUE_REQUIRED),
|
||||
'groupid' => new external_value(PARAM_INT, 'id of the group', VALUE_DEFAULT, 0),
|
||||
'onlyactive' => new external_value(PARAM_BOOL, 'whether to return only active users or all.',
|
||||
VALUE_DEFAULT, false),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -4111,26 +4113,25 @@ class core_course_external extends external_api {
|
||||
*
|
||||
* @param int $cmid Course Module id from which the users will be obtained
|
||||
* @param int $groupid Group id from which the users will be obtained
|
||||
* @param bool $onlyactive Whether to return only the active enrolled users or all enrolled users in the course.
|
||||
* @return array List of users
|
||||
* @throws invalid_parameter_exception
|
||||
*/
|
||||
public static function get_enrolled_users_by_cmid(int $cmid, int $groupid = 0) {
|
||||
public static function get_enrolled_users_by_cmid(int $cmid, int $groupid = 0, bool $onlyactive = false) {
|
||||
global $PAGE;
|
||||
$warnings = [];
|
||||
|
||||
[
|
||||
'cmid' => $cmid,
|
||||
'groupid' => $groupid,
|
||||
] = self::validate_parameters(self::get_enrolled_users_by_cmid_parameters(), [
|
||||
self::validate_parameters(self::get_enrolled_users_by_cmid_parameters(), [
|
||||
'cmid' => $cmid,
|
||||
'groupid' => $groupid,
|
||||
'onlyactive' => $onlyactive,
|
||||
]);
|
||||
|
||||
list($course, $cm) = get_course_and_cm_from_cmid($cmid);
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
self::validate_context($coursecontext);
|
||||
|
||||
$enrolledusers = get_enrolled_users($coursecontext, '', $groupid);
|
||||
$enrolledusers = get_enrolled_users($coursecontext, '', $groupid, 'u.*', null, 0, 0, $onlyactive);
|
||||
|
||||
$users = array_map(function ($user) use ($PAGE) {
|
||||
$user->fullname = fullname($user);
|
||||
|
||||
@@ -212,6 +212,7 @@ abstract class moodleform_mod extends moodleform {
|
||||
$this->_features->showdescription = plugin_supports('mod', $this->_modname, FEATURE_SHOW_DESCRIPTION, false);
|
||||
$this->_features->gradecat = ($this->_features->outcomes or $this->_features->hasgrades);
|
||||
$this->_features->advancedgrading = plugin_supports('mod', $this->_modname, FEATURE_ADVANCED_GRADING, false);
|
||||
$this->_features->hasnoview = plugin_supports('mod', $this->_modname, FEATURE_NO_VIEW_LINK, false);
|
||||
$this->_features->canrescale = (component_callback_exists('mod_' . $this->_modname, 'rescale_activity_grades') !== false);
|
||||
}
|
||||
|
||||
@@ -386,11 +387,10 @@ abstract class moodleform_mod extends moodleform {
|
||||
// form verification
|
||||
function validation($data, $files) {
|
||||
global $COURSE, $DB, $CFG;
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
$mform =& $this->_form;
|
||||
|
||||
$errors = array();
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
if ($mform->elementExists('name')) {
|
||||
$name = trim($data['name']);
|
||||
@@ -574,7 +574,10 @@ abstract class moodleform_mod extends moodleform {
|
||||
$mform->addElement('header', 'modstandardelshdr', get_string('modstandardels', 'form'));
|
||||
|
||||
$section = get_fast_modinfo($COURSE)->get_section_info($this->_section);
|
||||
$allowstealth = !empty($CFG->allowstealth) && $this->courseformat->allow_stealth_module_visibility($this->_cm, $section);
|
||||
$allowstealth =
|
||||
!empty($CFG->allowstealth) &&
|
||||
$this->courseformat->allow_stealth_module_visibility($this->_cm, $section) &&
|
||||
!$this->_features->hasnoview;
|
||||
if ($allowstealth && $section->visible) {
|
||||
$modvisiblelabel = 'modvisiblewithstealth';
|
||||
} else if ($section->visible) {
|
||||
|
||||
@@ -14,13 +14,10 @@ Feature: View subfolders in a course in-line
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Folder" to section "3" and I fill the form with:
|
||||
| Name | Test folder |
|
||||
| Display folder contents | On a separate page |
|
||||
| Show subfolders expanded | |
|
||||
And I am on the "Test folder" "folder activity" page
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | display | showexpanded |
|
||||
| folder | C1 | Test folder | 0 | 0 |
|
||||
And I am on the "Test folder" "folder activity" page logged in as "teacher1"
|
||||
And I press "Edit"
|
||||
And I press "Create folder"
|
||||
And I set the field "New folder name" to "Test subfolder 1"
|
||||
|
||||
@@ -3500,6 +3500,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
|
||||
$user1 = self::getDataGenerator()->create_user();
|
||||
$user2 = self::getDataGenerator()->create_user();
|
||||
$user3 = self::getDataGenerator()->create_user();
|
||||
|
||||
$user1picture = new user_picture($user1);
|
||||
$user1picture->size = 1;
|
||||
@@ -3509,6 +3510,10 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
$user2picture->size = 1;
|
||||
$user2->profileimage = $user2picture->get_url($PAGE)->out(false);
|
||||
|
||||
$user3picture = new user_picture($user3);
|
||||
$user3picture->size = 1;
|
||||
$user3->profileimage = $user3picture->get_url($PAGE)->out(false);
|
||||
|
||||
// Set the first created user to the test user.
|
||||
self::setUser($user1);
|
||||
|
||||
@@ -3523,6 +3528,8 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
// Following lines enrol and assign default role id to the users.
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course1->id);
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course1->id);
|
||||
// Enrol a suspended user in the course.
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course1->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
|
||||
|
||||
// Create what we expect to be returned when querying the course module.
|
||||
$expectedusers = array(
|
||||
@@ -3544,11 +3551,42 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
|
||||
'lastname' => $user2->lastname,
|
||||
'profileimage' => $user2->profileimage,
|
||||
];
|
||||
$expectedusers['users'][2] = [
|
||||
'id' => $user3->id,
|
||||
'fullname' => fullname($user3),
|
||||
'firstname' => $user3->firstname,
|
||||
'lastname' => $user3->lastname,
|
||||
'profileimage' => $user3->profileimage,
|
||||
];
|
||||
|
||||
// Test getting the users in a given context.
|
||||
$users = core_course_external::get_enrolled_users_by_cmid($forum1->cmid);
|
||||
$users = external_api::clean_returnvalue(core_course_external::get_enrolled_users_by_cmid_returns(), $users);
|
||||
|
||||
$this->assertEquals(3, count($users['users']));
|
||||
$this->assertEquals($expectedusers, $users);
|
||||
|
||||
// Test getting only the active users in a given context.
|
||||
$users = core_course_external::get_enrolled_users_by_cmid($forum1->cmid, 0, true);
|
||||
$users = external_api::clean_returnvalue(core_course_external::get_enrolled_users_by_cmid_returns(), $users);
|
||||
|
||||
$expectedusers['users'] = [
|
||||
[
|
||||
'id' => $user1->id,
|
||||
'fullname' => fullname($user1),
|
||||
'firstname' => $user1->firstname,
|
||||
'lastname' => $user1->lastname,
|
||||
'profileimage' => $user1->profileimage,
|
||||
],
|
||||
[
|
||||
'id' => $user2->id,
|
||||
'fullname' => fullname($user2),
|
||||
'firstname' => $user2->firstname,
|
||||
'lastname' => $user2->lastname,
|
||||
'profileimage' => $user2->profileimage,
|
||||
]
|
||||
];
|
||||
|
||||
$this->assertEquals(2, count($users['users']));
|
||||
$this->assertEquals($expectedusers, $users);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ use core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\contextlist;
|
||||
use core_privacy\local\request\writer;
|
||||
use core_privacy\manager;
|
||||
use Horde\Socket\Client\Exception;
|
||||
|
||||
/**
|
||||
* Class provider
|
||||
@@ -196,7 +195,7 @@ class provider implements
|
||||
$field = array_key_exists($record->fieldid, $fields) ? $fields[$record->fieldid] : null;
|
||||
$data = data_controller::create(0, $record, $field);
|
||||
self::export_customfield_data($data, array_merge($subcontext, [$record->id]));
|
||||
} catch (Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
// We store some data that we can not initialise controller for. We still need to export it.
|
||||
self::export_customfield_data_unknown($record, $field, array_merge($subcontext, [$record->id]));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@customfield @customfield_textarea @javascript @_file_upload
|
||||
# This feature has Atto-specific steps. See MDL-75913 for further details.
|
||||
@customfield @customfield_textarea @javascript @_file_upload @editor_atto
|
||||
Feature: Default value for the textarea custom field can contain images
|
||||
In order to see images on custom fields
|
||||
As a manager
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@core @core_course @core_customfield @javascript
|
||||
# This feature has Atto-specific steps. See MDL-75913 for further details.
|
||||
@core @core_course @core_customfield @javascript @editor_atto
|
||||
Feature: Teachers can edit course custom fields
|
||||
In order to have additional data on the course
|
||||
As a teacher
|
||||
|
||||
@@ -344,6 +344,9 @@ class tool_provider extends ToolProvider {
|
||||
if ($userlog->serviceurl != $serviceurl) {
|
||||
$userlog->serviceurl = $serviceurl;
|
||||
}
|
||||
if (empty($userlog->consumersecret)) {
|
||||
$userlog->consumersecret = $this->consumer->secret;
|
||||
}
|
||||
$userlog->lastaccess = time();
|
||||
$DB->update_record('enrol_lti_users', $userlog);
|
||||
} else {
|
||||
@@ -354,7 +357,7 @@ class tool_provider extends ToolProvider {
|
||||
$userlog->serviceurl = $serviceurl;
|
||||
$userlog->sourceid = $sourceid;
|
||||
$userlog->consumerkey = $this->consumer->getKey();
|
||||
$userlog->consumersecret = $tool->secret;
|
||||
$userlog->consumersecret = $this->consumer->secret;
|
||||
$userlog->lastgrade = 0;
|
||||
$userlog->lastaccess = time();
|
||||
$userlog->timecreated = time();
|
||||
|
||||
@@ -69,5 +69,47 @@ function xmldb_enrol_lti_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2021051701, 'enrol', 'lti');
|
||||
}
|
||||
|
||||
if ($oldversion < 2021051702) {
|
||||
// Update lti user information for LTI 2.0 users having the wrong consumer secret recorded.
|
||||
// This applies to any LTI 2.0 user who has launched the tool (i.e. has lastaccess) and fixes a non-functional grade sync
|
||||
// for LTI 2.0 consumers.
|
||||
$sql = "SELECT lu.id, lc.secret
|
||||
FROM {enrol_lti_users} lu
|
||||
JOIN {enrol_lti_lti2_consumer} lc
|
||||
ON (lu.consumerkey = lc.consumerkey256)
|
||||
WHERE lc.ltiversion = :ltiversion
|
||||
AND lu.consumersecret != lc.secret
|
||||
AND lu.lastaccess IS NOT NULL";
|
||||
$affectedltiusersrs = $DB->get_recordset_sql($sql, ['ltiversion' => 'LTI-2p0']);
|
||||
foreach ($affectedltiusersrs as $ltiuser) {
|
||||
$DB->set_field('enrol_lti_users', 'consumersecret', $ltiuser->secret, ['id' => $ltiuser->id]);
|
||||
}
|
||||
$affectedltiusersrs->close();
|
||||
|
||||
// Lti savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2021051702, 'enrol', 'lti');
|
||||
}
|
||||
|
||||
if ($oldversion < 2021051703) {
|
||||
// Update lti user information for any users missing a consumer secret.
|
||||
// This applies to any user who has launched the tool (i.e. has lastaccess) but who doesn't have a secret recorded.
|
||||
// This fixes a bug where enrol_lti_users records are created first during a member sync, and are missing the secret,
|
||||
// even despite having launched the tool subsequently.
|
||||
$sql = "SELECT lu.id, lc.secret
|
||||
FROM {enrol_lti_users} lu
|
||||
JOIN {enrol_lti_lti2_consumer} lc
|
||||
ON (lu.consumerkey = lc.consumerkey256)
|
||||
WHERE lu.consumersecret IS NULL
|
||||
AND lu.lastaccess IS NOT NULL";
|
||||
$affectedltiusersrs = $DB->get_recordset_sql($sql);
|
||||
foreach ($affectedltiusersrs as $ltiuser) {
|
||||
$DB->set_field('enrol_lti_users', 'consumersecret', $ltiuser->secret, ['id' => $ltiuser->id]);
|
||||
}
|
||||
$affectedltiusersrs->close();
|
||||
|
||||
// Lti savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2021051703, 'enrol', 'lti');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2021051701; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2021051703; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2021051100; // Requires this Moodle version.
|
||||
$plugin->component = 'enrol_lti'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace core_files\local\archive_writer;
|
||||
|
||||
use ZipStream\Option\Archive;
|
||||
use ZipStream\ZipStream;
|
||||
use ZipStream\Option\File as FileOptions;
|
||||
use core_files\archive_writer;
|
||||
use core_files\local\archive_writer\file_writer_interface as file_writer_interface;
|
||||
use core_files\local\archive_writer\stream_writer_interface as stream_writer_interface;
|
||||
@@ -110,8 +111,12 @@ class zip_writer extends archive_writer implements file_writer_interface, stream
|
||||
}
|
||||
|
||||
public function add_file_from_stored_file(string $name, \stored_file $file): void {
|
||||
$datetime = new \DateTime();
|
||||
$datetime->setTimestamp($file->get_timemodified());
|
||||
$fileoptions = new FileOptions();
|
||||
$fileoptions->setTime($datetime);
|
||||
$filehandle = $file->get_content_file_handle();
|
||||
$this->archive->addFileFromStream($this->sanitise_filepath($name), $filehandle);
|
||||
$this->archive->addFileFromStream($this->sanitise_filepath($name), $filehandle, $fileoptions);
|
||||
fclose($filehandle);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_files\local\archive_writer/zip_archive.
|
||||
*
|
||||
* @package core_files
|
||||
* @category test
|
||||
* @copyright 2020 Mark Nelson <mdjnelson@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
namespace core_files;
|
||||
|
||||
use advanced_testcase;
|
||||
@@ -31,7 +22,11 @@ use core_files\local\archive_writer\zip_writer;
|
||||
/**
|
||||
* Unit tests for \core_files\archive_writer.
|
||||
*
|
||||
* @coversDefaultClass \core_files\archive_writer
|
||||
* @package core_files
|
||||
* @category test
|
||||
* @copyright 2020 Mark Nelson <mdjnelson@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @covers \core_files\archive_writer
|
||||
*/
|
||||
class archive_writer_test extends advanced_testcase {
|
||||
|
||||
|
||||
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for \core_files\local\archive_writer\zip_writer.
|
||||
*
|
||||
* @package core_files
|
||||
* @category test
|
||||
* @copyright 2020 Mark Nelson <mdjnelson@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
namespace core_files\local\archive_writer;
|
||||
|
||||
use advanced_testcase;
|
||||
@@ -33,7 +24,11 @@ use ZipArchive;
|
||||
/**
|
||||
* Unit tests for \core_files\local\archive_writer\zip_writer.
|
||||
*
|
||||
* @coversDefaultClass \core_files\local\archive_writer\zip_writer
|
||||
* @package core_files
|
||||
* @category test
|
||||
* @copyright 2020 Mark Nelson <mdjnelson@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
* @covers \core_files\local\archive_writer\zip_writer
|
||||
*/
|
||||
class zip_writer_test extends advanced_testcase {
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ Feature: Render H5P content using filters
|
||||
And I wait until the page is ready
|
||||
Then ".h5p-iframe" "css_element" should not exist
|
||||
|
||||
@javascript
|
||||
# This scenario has Atto-specific steps. See MDL-75913 for further details.
|
||||
@javascript @editor_atto
|
||||
Scenario: Render a local H5P file as admin
|
||||
Given I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
@@ -83,7 +84,8 @@ Feature: Render H5P content using filters
|
||||
And I should not see "you don't have access"
|
||||
And I should see "Lorum ipsum"
|
||||
|
||||
@javascript
|
||||
# This scenario has Atto-specific steps. See MDL-75913 for further details.
|
||||
@javascript @editor_atto
|
||||
Scenario: Render a local H5P file as teacher
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
@@ -107,7 +109,8 @@ Feature: Render H5P content using filters
|
||||
Then I should see "Note that the libraries may exist in the file you uploaded, but you're not allowed to upload new libraries."
|
||||
And I should see "missing-required-library"
|
||||
|
||||
@javascript
|
||||
# This scenario has Atto-specific steps. See MDL-75913 for further details.
|
||||
@javascript @editor_atto
|
||||
Scenario: Render a local H5P file with existing libraries
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
@@ -165,7 +168,8 @@ Feature: Render H5P content using filters
|
||||
Then I should not see "missing-required-library"
|
||||
And I should see "Lorum ipsum"
|
||||
|
||||
@javascript
|
||||
# This scenario has Atto-specific steps. See MDL-75913 for further details.
|
||||
@javascript @editor_atto
|
||||
Scenario: Render local H5P file with a disabled main library
|
||||
Given I log in as "admin"
|
||||
# Upload H5P file to private files.
|
||||
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package gradingform_guide
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace gradingform_guide\grades\grader\gradingpanel\external;
|
||||
@@ -42,7 +33,7 @@ use moodle_exception;
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_guide_external_fetch_test extends advanced_testcase {
|
||||
class fetch_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package gradingform_guide
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace gradingform_guide\grades\grader\gradingpanel\external;
|
||||
@@ -42,7 +33,7 @@ use moodle_exception;
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_guide_external_store_test extends advanced_testcase {
|
||||
class store_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package gradingform_rubric
|
||||
* @category test
|
||||
* @copyright 2019 Mathew May <mathew.solutions>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace gradingform_rubric\grades\grader\gradingpanel\external;
|
||||
@@ -43,7 +34,7 @@ use moodle_exception;
|
||||
* @copyright 2019 Mathew May <mathew.solutions>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_rubric_external_fetch_test extends advanced_testcase {
|
||||
class fetch_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package gradingform_rubric
|
||||
* @category test
|
||||
* @copyright 2019 Mathew May <mathew.solutions>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace gradingform_rubric\grades\grader\gradingpanel\external;
|
||||
@@ -42,7 +33,7 @@ use moodle_exception;
|
||||
* @copyright 2019 Mathew May <mathew.solutions>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_rubric_external_store_test extends advanced_testcase {
|
||||
class store_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace tests\core_grades {
|
||||
namespace core_grades {
|
||||
|
||||
use advanced_testcase;
|
||||
use core_grades\component_gradeitems;
|
||||
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package core_grades
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace core_grades\grades\grader\gradingpanel\point\external;
|
||||
@@ -42,7 +33,7 @@ use moodle_exception;
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_point_external_fetch_test extends advanced_testcase {
|
||||
class fetch_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package core_grades
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace core_grades\grades\grader\gradingpanel\point\external;
|
||||
@@ -44,7 +35,7 @@ use grade_item;
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_point_external_store_test extends advanced_testcase {
|
||||
class store_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package core_grades
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace core_grades\grades\grader\gradingpanel\scale\external;
|
||||
@@ -42,7 +33,7 @@ use moodle_exception;
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_scale_external_fetch_test extends advanced_testcase {
|
||||
class fetch_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
+1
-10
@@ -14,15 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for core_grades\component_gradeitems;
|
||||
*
|
||||
* @package core_grades
|
||||
* @category test
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
|
||||
*/
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace core_grades\grades\grader\gradingpanel\scale\external;
|
||||
@@ -44,7 +35,7 @@ use grade_item;
|
||||
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grades_grader_gradingpanel_scale_external_store_test extends advanced_testcase {
|
||||
class store_test extends advanced_testcase {
|
||||
|
||||
public static function setupBeforeClass(): void {
|
||||
global $CFG;
|
||||
@@ -14,16 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Testing the H5P H5PFileStorage interface implementation.
|
||||
*
|
||||
* @package core_h5p
|
||||
* @category test
|
||||
* @copyright 2019 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_h5p\local\tests;
|
||||
namespace core_h5p;
|
||||
|
||||
use core_h5p\file_storage;
|
||||
use core_h5p\local\library\autoloader;
|
||||
@@ -38,11 +29,12 @@ use zip_archive;
|
||||
* Test class covering the H5PFileStorage interface implementation.
|
||||
*
|
||||
* @package core_h5p
|
||||
* @category test
|
||||
* @copyright 2019 Victor Deniz <victor@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @runTestsInSeparateProcesses
|
||||
*/
|
||||
class h5p_file_storage_test extends \advanced_testcase {
|
||||
class file_storage_test extends \advanced_testcase {
|
||||
|
||||
/** @var \core_h5p\file_storage H5P file storage instance */
|
||||
protected $h5p_file_storage;
|
||||
@@ -30,4 +30,4 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['thisdirection'] = 'ltr';
|
||||
$string['thislanguage'] = 'Breizh';
|
||||
$string['thislanguage'] = 'Brezhoneg';
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://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'] = 'es';
|
||||
$string['thislanguage'] = 'Español - Argentina';
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user