Compare commits
452 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd71612cf6 | |||
| a4874cb9c5 | |||
| 90818a22ad | |||
| 28bb2b50d6 | |||
| 28d6953d48 | |||
| c7b3edf823 | |||
| 880e150587 | |||
| 760a316679 | |||
| 525f816567 | |||
| 40b1954431 | |||
| 9f152581f0 | |||
| 1a624afb87 | |||
| f80a3bce0a | |||
| 4deb1eea56 | |||
| 77c72b0bd7 | |||
| a15df02640 | |||
| e5dd087852 | |||
| f46643fd61 | |||
| 426e58d35d | |||
| be86e18ff1 | |||
| d33aa94074 | |||
| 47fcb7c012 | |||
| 7fd65d8896 | |||
| 4ad6481a77 | |||
| 40d01acce6 | |||
| f5daf410af | |||
| 40510605e4 | |||
| b436508b24 | |||
| 98bbce7011 | |||
| 04d74da325 | |||
| 90c5358680 | |||
| 882b9d67f5 | |||
| 591ffa267d | |||
| 7c10813e02 | |||
| a099b1d893 | |||
| 39ab1182d9 | |||
| 9e5bf8d4d5 | |||
| fc2ed595d9 | |||
| 86f1bf85c4 | |||
| 4e858410ea | |||
| dd581ff3f5 | |||
| 1a70b72b41 | |||
| c7b2f34748 | |||
| ee828d828a | |||
| 499f651729 | |||
| 0a95429dce | |||
| 35ef8a9e40 | |||
| 51dae0b04e | |||
| bc41f92872 | |||
| 430b3e7043 | |||
| f6debec437 | |||
| c4d91b4e42 | |||
| 98317ff91a | |||
| 21c5f2d453 | |||
| 42ec6014c4 | |||
| 45b81544c5 | |||
| f055b84644 | |||
| 8d6e0dc416 | |||
| 0ebccd5bb4 | |||
| a22e2aa0d7 | |||
| dfea25b3d7 | |||
| 173b61bf69 | |||
| c920bb6db5 | |||
| 9899fc0a0f | |||
| d01eba812b | |||
| 811526b0a6 | |||
| fb8fa74655 | |||
| 36e2f7d5a3 | |||
| 4fa6354d89 | |||
| 7ed2a79297 | |||
| 65731963bc | |||
| 63c6f278a7 | |||
| 474ee8524a | |||
| 5956302d76 | |||
| 9121d889f5 | |||
| af0aee7d2a | |||
| 76fc2573ce | |||
| d611739b3f | |||
| f638a5bbae | |||
| 2079ba1387 | |||
| c12e3b46de | |||
| bdb1aefaad | |||
| 6c48aaf4d9 | |||
| a745135867 | |||
| 2674350a47 | |||
| 16cee3894e | |||
| 5e943bf6ba | |||
| 4d29785724 | |||
| 733b90eef0 | |||
| 00385e7580 | |||
| 3b757a24eb | |||
| c56edaa116 | |||
| 6b54bd46f2 | |||
| 31f13cd315 | |||
| a45ccc464b | |||
| 604d8c291f | |||
| c5fdf320cd | |||
| 0fd5993afb | |||
| ec56eeb9a9 | |||
| fa6c77adc7 | |||
| dca46bcab8 | |||
| cc045cc27d | |||
| 980a265718 | |||
| 6ad9dcae1c | |||
| 2ebc453c99 | |||
| 5cbd545cd3 | |||
| e988445521 | |||
| b08f86b258 | |||
| 58213db159 | |||
| c34dc466b6 | |||
| 2b7ede20b5 | |||
| 4c64f49a88 | |||
| 0baa1aa391 | |||
| a9b87fa989 | |||
| cdcfb84d18 | |||
| 52046c52b1 | |||
| 9eccbb590e | |||
| 2b7f887245 | |||
| 3dd63e8149 | |||
| 78e5dd6284 | |||
| f14dc52adc | |||
| aab571ca2c | |||
| eadfbd21e9 | |||
| b5eb437fcd | |||
| 16e5b999ce | |||
| 7d596ff339 | |||
| d02bcbb963 | |||
| c01344a0e7 | |||
| e9439d064b | |||
| f21e1443dc | |||
| 860bfb6f25 | |||
| 388c5731fa | |||
| dc93055e28 | |||
| d57db03d20 | |||
| bd5bcec3f1 | |||
| 261fe42c05 | |||
| 6f622e2393 | |||
| 00b9fe36c1 | |||
| e4b27dd81b | |||
| 5c9704b210 | |||
| f6f2dd5022 | |||
| 9fc5f273e0 | |||
| dd63b85ed4 | |||
| f164d03df5 | |||
| e32d27e1ff | |||
| 2f826724c8 | |||
| 00ccb3a314 | |||
| 88d4939f25 | |||
| e3be2fcfb6 | |||
| 3585ab5afa | |||
| b7bfc77b52 | |||
| 72d98b0dd5 | |||
| 15916a6f3b | |||
| 48256e0242 | |||
| 18013b2153 | |||
| 9da4095949 | |||
| dc399cd841 | |||
| e4a8272d9c | |||
| 6832ac123d | |||
| e892c66058 | |||
| 48637c438d | |||
| 0e64a10ecf | |||
| 0dd5b86d3f | |||
| b0f89e5b92 | |||
| c4c67cd975 | |||
| 9ae06b8dc7 | |||
| e59e39c78f | |||
| 99e20baa54 | |||
| 7c04ccfdf9 | |||
| 2f8a56eaf0 | |||
| 0a774cefb8 | |||
| 6257ac4de7 | |||
| 5f34ca7b01 | |||
| 624d027753 | |||
| b492fa8255 | |||
| 2d1c45a40e | |||
| 13000ae319 | |||
| 81dee5182b | |||
| 44ec3591c0 | |||
| 7f638dac59 | |||
| 3ad36ca4f9 | |||
| ffc0155eab | |||
| 42e3f4d696 | |||
| ff446d05f6 | |||
| a213654a08 | |||
| b7947e03ff | |||
| 2c18225da4 | |||
| 67edcbd16f | |||
| a6154a1cab | |||
| eb7a2e3070 | |||
| 29a6589b8d | |||
| 219206d83e | |||
| 7391010aac | |||
| 713048a0c9 | |||
| 9f018ab557 | |||
| 8e6aeda4ba | |||
| 8af4bb6a40 | |||
| 804ae9ad72 | |||
| 75a49ff1b2 | |||
| 3931e6fe5c | |||
| 8e195adb84 | |||
| 44ab3ba8f1 | |||
| 91de19a803 | |||
| fcbd95d16d | |||
| ccb7bb2767 | |||
| 09be924480 | |||
| 9d9a626038 | |||
| 9a3cf47a77 | |||
| 1fb8bedf50 | |||
| 92b909033e | |||
| 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 | |||
| 2a36ff8dfb | |||
| 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 | |||
| 9f7d92de62 | |||
| e237e83dfb | |||
| 3498aeaf1e | |||
| e5e8bc4b22 | |||
| 911fafd9a9 | |||
| 739b551fa8 | |||
| f8351de05e | |||
| 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
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: johanmeiring/mysql-action@tmpfs-patch
|
||||
uses: moodlehq/mysql-action@v1
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 5.7
|
||||
@@ -74,6 +74,8 @@ jobs:
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
use tmpfs: true
|
||||
tmpfs size: '1024M'
|
||||
extra conf: --skip-log-bin
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
@@ -85,7 +87,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 +98,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:
|
||||
|
||||
+2
-1
@@ -51,4 +51,5 @@ moodle-plugin-ci.phar
|
||||
.eslintignore
|
||||
.stylelintignore
|
||||
/jsdoc
|
||||
.phpcs.xml
|
||||
phpcs.xml
|
||||
jsconfig.json
|
||||
|
||||
@@ -233,6 +233,7 @@ const getOwningComponentDirectory = checkPath => {
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
fetchComponentData,
|
||||
getAmdSrcGlobList,
|
||||
getComponentFromPath,
|
||||
getComponentPaths,
|
||||
|
||||
@@ -39,7 +39,7 @@ module.exports = grunt => {
|
||||
{
|
||||
rule: {
|
||||
_attrs: {
|
||||
ref: './.phpcs.xml.dist',
|
||||
ref: './phpcs.xml.dist',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -52,7 +52,7 @@ module.exports = grunt => {
|
||||
});
|
||||
});
|
||||
|
||||
grunt.file.write('.phpcs.xml', toXML(config, {
|
||||
grunt.file.write('phpcs.xml', toXML(config, {
|
||||
header: true,
|
||||
indent: ' ',
|
||||
}) + "\n");
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
+3
-1
@@ -81,7 +81,8 @@ install:
|
||||
sudo service mysql stop
|
||||
sudo mv /var/lib/mysql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
|
||||
sudo service mysql restart
|
||||
echo -e "[mysqld]\nskip-log-bin" | sudo tee -a /etc/mysql/my.cnf
|
||||
sudo service mysql start
|
||||
fi
|
||||
- >
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
@@ -92,6 +93,7 @@ install:
|
||||
sudo mv /var/lib/postgresql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
|
||||
sudo service postgresql start 9.6
|
||||
sh -c 'until pg_isready -p 5432; do echo "Waiting for the DB to be up..."; sleep 2; done'
|
||||
fi
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
|
||||
+53
-35
@@ -1,48 +1,66 @@
|
||||
MOODLE TRADEMARKS POLICY
|
||||
========================
|
||||
|
||||
The word "Moodle" is trademarked in many countries around the world. The word
|
||||
was originally coined as an acronym: Modular Object-Oriented Dynamic Learning
|
||||
Environment. The trademark is owned by Martin Dougiamas, Founder and Director
|
||||
of Moodle.
|
||||
The Moodle Trademark
|
||||
--------------------
|
||||
|
||||
The law obligates trademark owners to police their marks and prevent the use of
|
||||
confusingly similar names by third parties. Through this policy we’d like to
|
||||
make it clear how Moodle-related projects, organisations, and people can use
|
||||
the Moodle trademark. We’d also like to be clear about how use of the word is
|
||||
restricted when used to promote commercial Moodle services. We do this to
|
||||
protect the very business model that allows us to continue developing Moodle
|
||||
for you.
|
||||
The brand and word "Moodle" has trade mark protection in many countries around
|
||||
the world. Various Moodle™ trade marks are owned by either Moodle Pty Ltd or
|
||||
one of its associated entities. The law obligates trade mark owners to police
|
||||
their trade marks and prevent the use of confusingly similar names by
|
||||
third parties.
|
||||
|
||||
Allowed uses
|
||||
------------
|
||||
We have created a more concise and thorough set of Trademark Guidelines
|
||||
(https://moodle.com/wp-content/uploads/2023/02/Moodle-Trademark-Guidelines-2023-4.pdf)
|
||||
to help you understand how to comply with Moodle's trade mark requirements.
|
||||
The Trademark Guidelines will also assist our Moodle Certified Partners and the
|
||||
community to understand some of the principles that inform Moodle's stance
|
||||
whenever potential infringement has been detected by us or our community.
|
||||
|
||||
The following uses don’t require any permission at all:
|
||||
We need to be clear about use of the word "Moodle" and how we restrict its use
|
||||
when promoting commercial Moodle™ branded services. The proper use of
|
||||
trade marks reliably assures consumers about the quality of the associated
|
||||
products or services and where they have been derived from. Because the
|
||||
Moodle LMS is made available under the open source ‘GNU General Public License'
|
||||
that permits you to modify the copyrighted software, the distribution of such
|
||||
modified software in combination with Moodle trade marks can potentially
|
||||
mislead others in the community. To be clear, the GNU GPL does not include an
|
||||
implied right or licence to use Moodle's trade marks.
|
||||
|
||||
* Referring to the software or the Moodle project.
|
||||
* Describing your own Moodle implementation (including within corporate
|
||||
settings).
|
||||
We do all this to protect the very business model that allows us to continue
|
||||
developing various Moodle software solutions for you.
|
||||
|
||||
Allowed uses of "Moodle"
|
||||
------------------------
|
||||
|
||||
The following uses don't require any permission at all:
|
||||
|
||||
* Referring to the software or the Moodle project as the "Moodle™ software"
|
||||
or the "Moodle™ project"
|
||||
* Describing your own implementation of the Moodle™ software platform
|
||||
(including within corporate settings).
|
||||
* Describing a Moodle-based community hub.
|
||||
* Describing some software you’ve made that integrates with Moodle
|
||||
(eg a Moodle integration feature on another system).
|
||||
* Describing certain software you've made that integrates with Moodle™
|
||||
branded software (e.g. a Moodle™ integration feature on another system).
|
||||
|
||||
Restricted uses
|
||||
---------------
|
||||
Restricted uses of "Moodle"
|
||||
---------------------------
|
||||
|
||||
The following uses are generally prohibited without explicit and direct
|
||||
permission being granted to you by Moodle Pty Ltd. We do this to protect the
|
||||
Moodle project from software and sites which could confuse people. Please
|
||||
contact us to ask for permission in writing.
|
||||
Moodle™ project from software and sites which could confuse people. If in
|
||||
doubt, reach out for clarification at <trademarks@moodle.com>
|
||||
|
||||
* You can’t use "Moodle" in the name of your software (including Mobile apps)
|
||||
* You can’t use "Moodle" in your company name
|
||||
* You can’t use "Moodle" in your domain name
|
||||
* You can’t use "Moodle" in advertising-related keywords (such as Adsense)
|
||||
* You can’t use "Moodle" to describe services around Moodle (such as hosting,
|
||||
training, support, consulting, course creation services, theme development,
|
||||
customisation, installation, integration and certification). This applies
|
||||
even if you do not charge for the services. Note that usually only Moodle
|
||||
Partners have this permission.
|
||||
|
||||
For information about the Moodle Partner Certification Mark as well as for how
|
||||
to contact us, please see <https://moodle.com/trademarks/>.
|
||||
* You can't use the word "Moodle" or any Moodle logos for commercial purposes
|
||||
without prior written permission from Moodle HQ.
|
||||
* You can't use "Moodle" in the name of your software (including Mobile apps).
|
||||
* You can't use "Moodle" in your company name.
|
||||
* You can't use "Moodle" in your domain name.
|
||||
* You can't use "Moodle" in advertising-related keywords (such as Adsense).
|
||||
* You can't use "Moodle" to describe services around Moodle
|
||||
(such as hosting, training, support, consulting, course creation services,
|
||||
theme development, customisation, installation, integration, analytics
|
||||
and certification) that cause consumers to be confused that you are
|
||||
associated with Moodle HQ if you are not.
|
||||
This applies even if you do not charge for the services.
|
||||
Note that usually only Moodle Partners have this permission.
|
||||
|
||||
+189
-5
@@ -3371,6 +3371,7 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -3557,6 +3558,7 @@
|
||||
<VENDOR name="oracle" version="11.2" />
|
||||
</DATABASE>
|
||||
<PHP version="7.3.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -3781,11 +3783,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" />
|
||||
@@ -3927,4 +3924,191 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.2" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@
|
||||
<div class="form-password">
|
||||
<span data-passwordunmask="wrapper" data-passwordunmaskid="{{ id }}">
|
||||
<span data-passwordunmask="editor">
|
||||
<input type="hidden"
|
||||
<input type="password"
|
||||
name="{{ name }}"
|
||||
id="{{ id }}"
|
||||
value="{{ value }}"
|
||||
data-size="{{ size }}"
|
||||
class="form-control d-inline-block"
|
||||
class="form-control d-none"
|
||||
>
|
||||
</span>
|
||||
<a href="#" data-passwordunmask="edit" title="{{ edithint }}">
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
define("tool_behat/steps",["exports","core/ajax","core/templates","core/pending"],(function(_exports,_ajax,_templates,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending);
|
||||
/**
|
||||
* Enhancements for the step definitions page.
|
||||
*
|
||||
* @module tool_behat/steps
|
||||
* @copyright 2022 Catalyst IT EU
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
var getRequiredFieldsContent=function(entityData){var _entityData$required;return null!==(_entityData$required=entityData.required)&&void 0!==_entityData$required&&_entityData$required.length?_templates.default.renderForPromise("tool_behat/steprequiredfields",{fields:entityData.required}):Promise.resolve({html:"",js:""})};_exports.init=function(){var fn,_ref;document.addEventListener("change",(fn=regeneratorRuntime.mark((function _callee(e){var entityElement,stepElement,pendingPromise,entityData,_yield$getRequiredFie,html,js,stepRequiredFields;return regeneratorRuntime.wrap((function(_context){for(;;)switch(_context.prev=_context.next){case 0:if(entityElement=e.target.closest(".entities"),stepElement=e.target.closest(".stepcontent"),entityElement&&stepElement){_context.next=4;break}return _context.abrupt("return");case 4:return pendingPromise=new _pending.default("tool_behat/steps:change"),_context.next=7,entityType=e.target.value,_ajax.default.call([{methodname:"tool_behat_get_entity_generator",args:{entitytype:entityType}}])[0];case 7:return entityData=_context.sent,_context.next=10,getRequiredFieldsContent(entityData);case 10:if(_yield$getRequiredFie=_context.sent,html=_yield$getRequiredFie.html,js=_yield$getRequiredFie.js,!(stepRequiredFields=stepElement.querySelector(".steprequiredfields"))){_context.next=19;break}return _context.next=17,_templates.default.replaceNode(stepRequiredFields,html,js);case 17:_context.next=21;break;case 19:return _context.next=21,_templates.default.appendNodeContents(stepElement,html,js);case 21:pendingPromise.resolve();case 22:case"end":return _context.stop()}var entityType}),_callee)})),_ref=function(){var self=this,args=arguments;return new Promise((function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)}))},function(_x){return _ref.apply(this,arguments)}))}}));
|
||||
|
||||
//# sourceMappingURL=steps.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"steps.min.js","sources":["../src/steps.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport Ajax from 'core/ajax';\nimport Templates from 'core/templates';\nimport PendingJS from 'core/pending';\n\n/**\n * Enhancements for the step definitions page.\n *\n * @module tool_behat/steps\n * @copyright 2022 Catalyst IT EU\n * @author Mark Johnson <mark.johnson@catalyst-eu.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Call the get_entity_generator web service function\n *\n * Takes the name of an entity generator and returns an object containing a list of the required fields.\n *\n * @param {String} entityType\n * @returns {Promise}\n */\nconst getGeneratorEntities = (entityType) => Ajax.call([{\n methodname: 'tool_behat_get_entity_generator',\n args: {entitytype: entityType}\n}])[0];\n\n/**\n * Render HTML for required fields\n *\n * Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.\n *\n * @param {String} entityData\n * @return {Promise}\n */\nconst getRequiredFieldsContent = (entityData) => {\n if (!entityData.required?.length) {\n return Promise.resolve({\n html: '',\n js: ''\n });\n }\n return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});\n};\n\nexport const init = () => {\n // When an entity is selected in the \"the following exist\" step, fetch and display the required fields.\n document.addEventListener('change', async(e) => {\n const entityElement = e.target.closest('.entities');\n const stepElement = e.target.closest('.stepcontent');\n if (!entityElement || !stepElement) {\n return;\n }\n\n const pendingPromise = new PendingJS('tool_behat/steps:change');\n\n const entityData = await getGeneratorEntities(e.target.value);\n const {html, js} = await getRequiredFieldsContent(entityData);\n\n const stepRequiredFields = stepElement.querySelector('.steprequiredfields');\n if (stepRequiredFields) {\n await Templates.replaceNode(stepRequiredFields, html, js);\n } else {\n await Templates.appendNodeContents(stepElement, html, js);\n }\n pendingPromise.resolve();\n });\n};\n"],"names":["getRequiredFieldsContent","entityData","required","_entityData$required","length","Templates","renderForPromise","fields","Promise","resolve","html","js","document","addEventListener","e","entityElement","target","closest","stepElement","pendingPromise","PendingJS","entityType","value","Ajax","call","methodname","args","entitytype","stepRequiredFields","querySelector","replaceNode","appendNodeContents"],"mappings":";;;;;;;;;IAiDMA,yBAA2B,SAACC,yEACzBA,WAAWC,0CAAXC,qBAAqBC,OAMnBC,mBAAUC,iBAAiB,gCAAiC,CAACC,OAAQN,WAAWC,WAL5EM,QAAQC,QAAQ,CACnBC,KAAM,GACNC,GAAI,oBAMI,uBAEhBC,SAASC,iBAAiB,sCAAU,iBAAMC,oNAChCC,cAAgBD,EAAEE,OAAOC,QAAQ,aACjCC,YAAcJ,EAAEE,OAAOC,QAAQ,gBAChCF,eAAkBG,kFAIjBC,eAAiB,IAAIC,iBAAU,2CAhCfC,WAkCwBP,EAAEE,OAAOM,MAlClBC,cAAKC,KAAK,CAAC,CACpDC,WAAY,kCACZC,KAAM,CAACC,WAAYN,eACnB,iBA+BUpB,0CACmBD,yBAAyBC,2DAA3CS,2BAAAA,KAAMC,yBAAAA,KAEPiB,mBAAqBV,YAAYW,cAAc,wEAE3CxB,mBAAUyB,YAAYF,mBAAoBlB,KAAMC,mEAEhDN,mBAAU0B,mBAAmBb,YAAaR,KAAMC,YAE1DQ,eAAeV,mDA3CM,IAACY"}
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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/>.
|
||||
|
||||
import Ajax from 'core/ajax';
|
||||
import Templates from 'core/templates';
|
||||
import PendingJS from 'core/pending';
|
||||
|
||||
/**
|
||||
* Enhancements for the step definitions page.
|
||||
*
|
||||
* @module tool_behat/steps
|
||||
* @copyright 2022 Catalyst IT EU
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Call the get_entity_generator web service function
|
||||
*
|
||||
* Takes the name of an entity generator and returns an object containing a list of the required fields.
|
||||
*
|
||||
* @param {String} entityType
|
||||
* @returns {Promise}
|
||||
*/
|
||||
const getGeneratorEntities = (entityType) => Ajax.call([{
|
||||
methodname: 'tool_behat_get_entity_generator',
|
||||
args: {entitytype: entityType}
|
||||
}])[0];
|
||||
|
||||
/**
|
||||
* Render HTML for required fields
|
||||
*
|
||||
* Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.
|
||||
*
|
||||
* @param {String} entityData
|
||||
* @return {Promise}
|
||||
*/
|
||||
const getRequiredFieldsContent = (entityData) => {
|
||||
if (!entityData.required?.length) {
|
||||
return Promise.resolve({
|
||||
html: '',
|
||||
js: ''
|
||||
});
|
||||
}
|
||||
return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});
|
||||
};
|
||||
|
||||
export const init = () => {
|
||||
// When an entity is selected in the "the following exist" step, fetch and display the required fields.
|
||||
document.addEventListener('change', async(e) => {
|
||||
const entityElement = e.target.closest('.entities');
|
||||
const stepElement = e.target.closest('.stepcontent');
|
||||
if (!entityElement || !stepElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pendingPromise = new PendingJS('tool_behat/steps:change');
|
||||
|
||||
const entityData = await getGeneratorEntities(e.target.value);
|
||||
const {html, js} = await getRequiredFieldsContent(entityData);
|
||||
|
||||
const stepRequiredFields = stepElement.querySelector('.steprequiredfields');
|
||||
if (stepRequiredFields) {
|
||||
await Templates.replaceNode(stepRequiredFields, html, js);
|
||||
} else {
|
||||
await Templates.appendNodeContents(stepElement, html, js);
|
||||
}
|
||||
pendingPromise.resolve();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Return data about an entity generator.
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_behat\external;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/externallib.php');
|
||||
|
||||
/**
|
||||
* External function for getting properties of entity generators.
|
||||
*/
|
||||
class get_entity_generator extends \external_api {
|
||||
|
||||
/**
|
||||
* Define parameters for external function.
|
||||
*
|
||||
* The parameter is either in the format 'entity' or 'component_name > entity'. There is no appropriate param type for a
|
||||
* string like this containing angle brackets, so we will do PARAM_RAW. The value will be parsed by
|
||||
* behat_data_generators::parse_entity_type, which validates the format of the parameter and throws an exception if it is not
|
||||
* correct.
|
||||
*
|
||||
* @return \external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): \external_function_parameters {
|
||||
return new \external_function_parameters([
|
||||
'entitytype' => new \external_value(PARAM_RAW, 'Entity type that can be created by a generator.'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the required fields for a given entity type.
|
||||
*
|
||||
* @param string $entitytype
|
||||
* @return array
|
||||
*/
|
||||
public static function execute(string $entitytype): array {
|
||||
global $CFG;
|
||||
|
||||
// Ensure we can load Behat and Facebook namespaces in behat libraries.
|
||||
require_once("{$CFG->dirroot}/vendor/autoload.php");
|
||||
require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
|
||||
|
||||
$params = self::validate_parameters(self::execute_parameters(), ['entitytype' => $entitytype]);
|
||||
$context = \context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
$generators = new \behat_data_generators();
|
||||
$entity = $generators->get_entity($params['entitytype']);
|
||||
return ['required' => $entity['required']];
|
||||
}
|
||||
|
||||
/**
|
||||
* Define return values.
|
||||
*
|
||||
* Return required fields
|
||||
*
|
||||
* @return \external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): \external_single_structure {
|
||||
return new \external_single_structure([
|
||||
'required' => new \external_multiple_structure(
|
||||
new \external_value(PARAM_TEXT, 'Required field'),
|
||||
'Required fields',
|
||||
VALUE_OPTIONAL
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Define web service functions for tool_behat
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$functions = [
|
||||
'tool_behat_get_entity_generator' => [
|
||||
'classname' => 'tool_behat\\external\\get_entity_generator',
|
||||
'methodname' => 'execute',
|
||||
'description' => 'Get the generator details for an entity',
|
||||
'type' => 'read',
|
||||
'ajax' => true,
|
||||
'capabilities' => 'moodle/site:config'
|
||||
]
|
||||
];
|
||||
@@ -56,6 +56,7 @@ if ($components) {
|
||||
$form = new steps_definitions_form(null, array('components' => $componentswithsteps));
|
||||
|
||||
// Output contents.
|
||||
$PAGE->requires->js_call_amd('tool_behat/steps', 'init');
|
||||
$renderer = $PAGE->get_renderer('tool_behat');
|
||||
echo $renderer->render_stepsdefinitions($steps, $form);
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
|
||||
|
||||
/**
|
||||
* Renderer for behat tool web features
|
||||
*
|
||||
@@ -106,6 +108,32 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
},
|
||||
$stepsdefinitions
|
||||
);
|
||||
|
||||
$elementstrings = [];
|
||||
$count = 1;
|
||||
$stepsdefinitions = preg_replace_callback('/(the following ")ELEMENT\d?_STRING(" exist:)/',
|
||||
function($matches) use (&$elementstrings, &$count) {
|
||||
// Replace element type arguments with a user-friendly select.
|
||||
if (empty($elementstrings)) {
|
||||
$behatgenerators = new behat_data_generators();
|
||||
$componententities = $behatgenerators->get_all_entities();
|
||||
ksort($componententities);
|
||||
$elementstrings = [];
|
||||
foreach ($componententities as $component => $entities) {
|
||||
asort($entities);
|
||||
foreach ($entities as $entity) {
|
||||
$string = ($component === 'core') ? $entity : $component . ' > ' . $entity;
|
||||
$elementstrings[$string] = $string;
|
||||
}
|
||||
}
|
||||
}
|
||||
$select = html_writer::select($elementstrings, 'entities' . $count, '', ['' => 'choosedots'],
|
||||
['class' => 'entities']);
|
||||
$count++;
|
||||
return $matches[1] . $select . $matches[2];
|
||||
},
|
||||
$stepsdefinitions
|
||||
);
|
||||
}
|
||||
|
||||
// Steps definitions.
|
||||
|
||||
@@ -29,3 +29,9 @@
|
||||
#page-admin-tool-behat-index .steps-definitions .stepregex {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
#page-admin-tool-behat-index .steprequiredfields {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{{!
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template tool_behat/steprequiredfields
|
||||
|
||||
Display a Gherkin-style table row showing required columns for a step.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"fields": [
|
||||
"user",
|
||||
"role",
|
||||
"context"
|
||||
]
|
||||
}
|
||||
}}
|
||||
<pre class="steprequiredfields">
|
||||
|{{#fields}} {{{.}}} |{{/fields}}
|
||||
</pre>
|
||||
@@ -30,10 +30,9 @@ Feature: Verify that all form fields values can be get and set
|
||||
| student2 | G2 |
|
||||
| student3 | G2 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | Test this one | collaborative | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
| activity | course | idnumber | name | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | collaborative | 0 |
|
||||
And I am on the "Course 1" course page logged in as admin
|
||||
And I navigate to "Reset" in current page administration
|
||||
# Select (multi-select) - Checking "the select box should contain".
|
||||
And I expand all fieldsets
|
||||
@@ -61,16 +60,14 @@ Feature: Verify that all form fields values can be get and set
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I set the field "Force format" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value "1"
|
||||
And the field "Force format" does not match value ""
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Force format" to ""
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value ""
|
||||
And the field "Force format" does not match value "1"
|
||||
@@ -78,8 +75,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | 1 |
|
||||
@@ -89,8 +85,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | |
|
||||
@@ -143,10 +138,11 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And the field "Course ID number" matches value "Course id number"
|
||||
|
||||
Scenario: with JS disabled all form fields getters and setters works as expected
|
||||
|
||||
@javascript
|
||||
Scenario: with JS enabled all form fields getters and setters works as expected
|
||||
Given the following "activities" exist:
|
||||
| activity | course | name |
|
||||
| lesson | C1 | Test lesson |
|
||||
Then I am on "Course 1" course homepage
|
||||
And I navigate to "Users > Groups" in current page administration
|
||||
# Select (multi-select & AJAX) - Checking "I set the field" and "select box should contain".
|
||||
@@ -159,11 +155,8 @@ Feature: Verify that all form fields values can be get and set
|
||||
And the "members" select box should contain "Student 2 (s2@example.com)"
|
||||
And the "members" select box should not contain "Student 3 (s3@example.com)"
|
||||
# Checkbox (AJAX) - Checking "I set the field" and "I set the following fields to these values".
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Lesson" to section "1"
|
||||
And I am on the "Test lesson" "lesson activity editing" page
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson |
|
||||
| Description | Test lesson description |
|
||||
| available[enabled] | 1 |
|
||||
And I set the field "deadline[enabled]" to "1"
|
||||
# Checkbox (AJAX) - Checking "the field matches value" before saving.
|
||||
|
||||
@@ -13,6 +13,10 @@ Feature: List the system steps definitions
|
||||
Scenario: Accessing the list
|
||||
Then I should see "Step definitions"
|
||||
And I should not see "There aren't steps definitions matching this filter"
|
||||
And I should not see "the following \"ELEMENT_STRING\" exist:"
|
||||
And "entities1" "select" should exist
|
||||
And the "entities1" select box should contain "users"
|
||||
And the "entities1" select box should contain "mod_assign > submissions"
|
||||
|
||||
@javascript
|
||||
Scenario: Filtering by type
|
||||
@@ -34,3 +38,11 @@ Feature: List the system steps definitions
|
||||
Then I should not see "There aren't steps definitions matching this filter"
|
||||
And I should see "Checks the provided element and selector type exists in the current page."
|
||||
And I should see "Checks that an element and selector type exists in another element and selector type on the current page."
|
||||
|
||||
@javascript
|
||||
Scenario: Get required fields
|
||||
Given I set the field "entities1" to "users"
|
||||
And I should see "| username |"
|
||||
When I set the field "entities1" to "mod_quiz > user overrides"
|
||||
Then I should not see "| username |"
|
||||
And I should see "| quiz | user |"
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Unit tests for get_entity_generator web service
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
|
||||
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_behat\external;
|
||||
|
||||
/**
|
||||
* Tests for get_entity_generator web service
|
||||
*
|
||||
* @covers \tool_behat\external\get_entity_generator
|
||||
*/
|
||||
class get_entity_generator_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Log in as admin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for a core entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_core_entity(): void {
|
||||
$generator = get_entity_generator::execute('users');
|
||||
$this->assertEquals(['required' => ['username']], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for the plugin entity.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_plugin_entity(): void {
|
||||
$generator = get_entity_generator::execute('mod_book > chapters');
|
||||
$this->assertEquals(['required' => ['book', 'title', 'content']], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generator for an entity with no required fields.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_no_requried(): void {
|
||||
$generator = get_entity_generator::execute('mod_forum > posts');
|
||||
$this->assertEquals(['required' => []], $generator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get the generator for a core entity that does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_entity(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a generator form a plugin that does not exist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_plugin(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('foo > bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to get a generator for an entity that does not exist, from a plugin that does.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_execute_invalid_plugin_entity(): void {
|
||||
$this->expectException('coding_exception');
|
||||
get_entity_generator::execute('mod_book > bar');
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2021051700; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2021051701; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2021051100; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -79,6 +79,19 @@ class locale {
|
||||
* @return string|false Returns the new current locale, or FALSE on error.
|
||||
*/
|
||||
protected function set_locale(int $category = LC_ALL, string $locale = '0') {
|
||||
return setlocale($category, $locale);
|
||||
if (strlen($locale) <= 255 || PHP_OS_FAMILY === 'BSD' || PHP_OS_FAMILY === 'Darwin') {
|
||||
// We can set the whole locale all together.
|
||||
return setlocale($category, $locale);
|
||||
}
|
||||
|
||||
// Too long locale with linux or windows, let's split it into known and supported categories.
|
||||
$split = explode(';', $locale);
|
||||
foreach ($split as $element) {
|
||||
[$category, $value] = explode('=', $element);
|
||||
if (defined($category)) { // Only if the category exists, there are OS differences.
|
||||
setlocale(constant($category), $value);
|
||||
}
|
||||
}
|
||||
return setlocale(LC_ALL, 0); // Finally, return the complete configured locale.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +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/>.
|
||||
|
||||
/**
|
||||
* Tests for \tool_langimport\locale class.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2018 Université Rennes 2 {@link https://www.univ-rennes2.fr}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport;
|
||||
|
||||
/**
|
||||
@@ -29,6 +21,7 @@ namespace tool_langimport;
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @coversDefaultClass \tool_langimport\locale
|
||||
* @copyright 2018 Université Rennes 2 {@link https://www.univ-rennes2.fr}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
@@ -36,6 +29,7 @@ class locale_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test that \tool_langimport\locale::check_locale_availability() works as expected.
|
||||
*
|
||||
* @covers ::check_locale_availability
|
||||
* @return void
|
||||
*/
|
||||
public function test_check_locale_availability() {
|
||||
@@ -43,7 +37,7 @@ class locale_test extends \advanced_testcase {
|
||||
// - first setlocale() call which backup current locale
|
||||
// - second setlocale() call which try to set new 'es' locale
|
||||
// - third setlocale() call which restore locale.
|
||||
$mock = $this->getMockBuilder(\tool_langimport\locale::class)
|
||||
$mock = $this->getMockBuilder(locale::class)
|
||||
->onlyMethods(['set_locale'])
|
||||
->getMock();
|
||||
$mock->method('set_locale')->will($this->onConsecutiveCalls('en', 'es', 'en'));
|
||||
@@ -56,7 +50,7 @@ class locale_test extends \advanced_testcase {
|
||||
// - first setlocale() call which backup current locale
|
||||
// - second setlocale() call which fail to set new locale
|
||||
// - third setlocale() call which restore locale.
|
||||
$mock = $this->getMockBuilder(\tool_langimport\locale::class)
|
||||
$mock = $this->getMockBuilder(locale::class)
|
||||
->onlyMethods(['set_locale'])
|
||||
->getMock();
|
||||
$mock->method('set_locale')->will($this->onConsecutiveCalls('en', false, 'en'));
|
||||
@@ -66,8 +60,104 @@ class locale_test extends \advanced_testcase {
|
||||
$this->assertFalse($result);
|
||||
|
||||
// Test an invalid parameter.
|
||||
$locale = new \tool_langimport\locale();
|
||||
$locale = new locale();
|
||||
$this->expectException(\coding_exception::class);
|
||||
$locale->check_locale_availability('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test \tool_langimport\locale::set_locale() own logic.
|
||||
*
|
||||
* We have to explicitly test set_locale() own logic and results,
|
||||
* that effectively sets the current locale, so we need to restore
|
||||
* the original locale after every test (ugly, from a purist unit test
|
||||
* point of view, but needed).
|
||||
*
|
||||
* @dataProvider set_locale_provider
|
||||
* @covers ::set_locale
|
||||
*
|
||||
* @param string $set locale string to be set.
|
||||
* @param string $ret expected results returned after setting the locale.
|
||||
*/
|
||||
public function test_set_locale(string $set, string $ret) {
|
||||
// Make set_locale() public.
|
||||
$loc = new locale();
|
||||
$rc = new \ReflectionClass(locale::class);
|
||||
$rm = $rc->getMethod('set_locale');
|
||||
$rm->setAccessible(true);
|
||||
|
||||
// Capture current locale for later restore (funnily, using the set_locale() method itself.
|
||||
$originallocale = $rm->invokeArgs($loc, [LC_ALL, 0]);
|
||||
|
||||
// Assert we get the locale defined as expected.
|
||||
$this->assertEquals($ret, $rm->invokeArgs($loc, [LC_ALL, $set]));
|
||||
|
||||
// We have finished, restore the original locale, so this doesn't affect other tests at distance.
|
||||
// (again, funnily, using the very same set_locale() method).
|
||||
$rm->invokeArgs($loc, [LC_ALL, $originallocale]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for test_set_locale().
|
||||
*
|
||||
* Provides a locale to be set (as 'set') and a expected return value (as 'ret'). Note that
|
||||
* some of the locales are OS dependent, so only the ones matching the OS will be provided.
|
||||
*
|
||||
* We make extensive use of the en_AU.UTF-8/English_Australia.1252 locale that is mandatory to
|
||||
* be installed in any system running PHPUnit tests.
|
||||
*/
|
||||
public function set_locale_provider(): array {
|
||||
// Let's list the allowed categories by OS.
|
||||
$bsdallowed = ['LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME'];
|
||||
$winallowed = ['LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME'];
|
||||
$linuxallowed = [
|
||||
'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME',
|
||||
'LC_PAPER', 'LC_NAME', 'LC_ADDRESS', 'LC_TELEPHONE', 'LC_MEASUREMENT', 'LC_IDENTIFICATION'
|
||||
];
|
||||
|
||||
// The base locale name is also OS dependent.
|
||||
$baselocale = get_string('locale', 'langconfig');
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
$baselocale = get_string('localewin', 'langconfig');
|
||||
}
|
||||
|
||||
// Here we'll go accumulating cases to be provided.
|
||||
$cases = [];
|
||||
|
||||
// First, the simplest case, just pass a locale name, without categories.
|
||||
$cases['rawlocale'] = [
|
||||
'set' => $baselocale,
|
||||
'ret' => $baselocale,
|
||||
];
|
||||
|
||||
// Now, let's fill ALL LC categories, we should get back the locale name if all them are set with same value.
|
||||
// Note that this case is the one that, under Linux only, covers the changes performed to the set_locale() method.
|
||||
// Pick the correct categories depending on the OS.
|
||||
$oscategories = $bsdallowed; // Default to BSD/Dawrwin ones because they are the standard 6 supported by PHP.
|
||||
if (PHP_OS_FAMILY === 'Windows') {
|
||||
$oscategories = $winallowed;
|
||||
} else if (PHP_OS_FAMILY === 'Linux') {
|
||||
$oscategories = $linuxallowed;
|
||||
}
|
||||
|
||||
$localestr = '';
|
||||
foreach ($oscategories as $category) {
|
||||
// Format is different by OS too, so let build the string conditionally.
|
||||
if (PHP_OS_FAMILY === 'BSD' || PHP_OS_FAMILY === 'Darwin') {
|
||||
// BSD uses slashes (/) separated list of the 6 values in exact order.
|
||||
$localestr .= '/' . $baselocale;
|
||||
} else {
|
||||
// Linux/Windows use semicolon (;) separated list of category=value pairs.
|
||||
$localestr .= ';' . $category . '=' . $baselocale;
|
||||
}
|
||||
}
|
||||
$cases['allcategories'] = [
|
||||
'set' => trim($localestr, ';/'),
|
||||
'ret' => $baselocale,
|
||||
];
|
||||
|
||||
// Return all the built cases.
|
||||
return $cases;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,3 +33,27 @@ Feature: Licence manager
|
||||
And "This is the site default licence" "icon" should exist in the "cc" "table_row"
|
||||
And "Enable licence" "icon" should not exist in the "cc" "table_row"
|
||||
And "This is the site default licence" "icon" should not exist in the "public" "table_row"
|
||||
|
||||
@javascript @_file_upload
|
||||
Scenario Outline: User licence preference is remembered depending of setting value
|
||||
Given the following config values are set as admin:
|
||||
| sitedefaultlicense | cc |
|
||||
| rememberuserlicensepref | <rememberuserlicensepref> |
|
||||
And I log in as "admin"
|
||||
And I follow "Manage private files..."
|
||||
And I follow "Add..."
|
||||
And I follow "Upload a file"
|
||||
And the field with xpath "//select[@name='license']" matches value "Creative Commons"
|
||||
And I click on "Close" "button" in the "File picker" "dialogue"
|
||||
When I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager as:
|
||||
| Save as | empty_copy.txt |
|
||||
| license | Public domain |
|
||||
And I press "Save changes"
|
||||
And I follow "Manage private files..."
|
||||
And I follow "Add..."
|
||||
Then the field with xpath "//select[@name='license']" matches value "<expectedlicence>"
|
||||
|
||||
Examples:
|
||||
| rememberuserlicensepref | expectedlicence |
|
||||
| 0 | Creative Commons |
|
||||
| 1 | Public domain |
|
||||
|
||||
@@ -33,8 +33,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests log writing.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_log_writing(bool $jsonformat) {
|
||||
global $DB, $CFG;
|
||||
@@ -252,9 +251,9 @@ class store_test extends \advanced_testcase {
|
||||
* Returns different JSON format settings so the test can be run with JSON format either on or
|
||||
* off.
|
||||
*
|
||||
* @return [bool] Array of true/false
|
||||
* @return bool[] Array of true/false
|
||||
*/
|
||||
public static function test_log_writing_provider(): array {
|
||||
public static function log_writing_provider(): array {
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
@@ -311,17 +310,16 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_database');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_database');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,20 +217,19 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive',
|
||||
'report_outline' => '/report/outline',
|
||||
'report_participation' => '/report/participation',
|
||||
'report_stats' => '/report/stats'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_legacy');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
'outline' => 'report_outline',
|
||||
'participation' => 'report_participation',
|
||||
'stats' => 'report_stats'
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_legacy');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests log writing.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_log_writing(bool $jsonformat) {
|
||||
global $DB;
|
||||
@@ -223,9 +222,9 @@ class store_test extends \advanced_testcase {
|
||||
* Returns different JSON format settings so the test can be run with JSON format either on or
|
||||
* off.
|
||||
*
|
||||
* @return [bool] Array of true/false
|
||||
* @return bool[] Array of true/false
|
||||
*/
|
||||
public static function test_log_writing_provider(): array {
|
||||
public static function log_writing_provider(): array {
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
@@ -239,20 +238,19 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive',
|
||||
'report_outline' => '/report/outline',
|
||||
'report_participation' => '/report/participation',
|
||||
'report_stats' => '/report/stats'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_standard');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
'outline' => 'report_outline',
|
||||
'participation' => 'report_participation',
|
||||
'stats' => 'report_stats'
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_standard');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +366,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests the decode_other function can cope with both JSON and PHP serialized format.
|
||||
*
|
||||
* @param mixed $value Value to encode and decode
|
||||
* @dataProvider test_decode_other_provider
|
||||
* @dataProvider decode_other_provider
|
||||
*/
|
||||
public function test_decode_other($value) {
|
||||
$this->assertEquals($value, \logstore_standard\log\store::decode_other(serialize($value)));
|
||||
@@ -387,7 +385,7 @@ class store_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array Array of parameters
|
||||
*/
|
||||
public function test_decode_other_provider(): array {
|
||||
public function decode_other_provider(): array {
|
||||
return [
|
||||
[['info' => 'd2819896', 'logurl' => 'discuss.php?d=2819896']],
|
||||
[null],
|
||||
@@ -400,8 +398,7 @@ class store_test extends \advanced_testcase {
|
||||
* Checks that backup and restore of log data works correctly.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_backup_restore(bool $jsonformat) {
|
||||
global $DB;
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -59,22 +59,26 @@ class api_test extends \externallib_advanced_testcase {
|
||||
*/
|
||||
public function test_get_potential_config_issues() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$CFG->userquota = '73289234723498234723423489273423497234234';
|
||||
// Set non-SSL wwwroot, to avoid spurious certificate checking.
|
||||
$CFG->wwwroot = 'http://www.example.com';
|
||||
$CFG->debugdisplay = 1;
|
||||
|
||||
set_config('debugauthdb', 1, 'auth_db');
|
||||
set_config('debugdb', 1, 'enrol_database');
|
||||
$expectedissues = array('adodbdebugwarning', 'displayerrorswarning');
|
||||
|
||||
// Get potential issues, obtain their keys for comparison.
|
||||
$issues = api::get_potential_config_issues();
|
||||
$this->assertCount(count($expectedissues), $issues);
|
||||
foreach ($issues as $issue) {
|
||||
$this->assertTrue(in_array($issue[0], $expectedissues));
|
||||
}
|
||||
$issuekeys = array_column($issues, 0);
|
||||
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'nohttpsformobilewarning',
|
||||
'adodbdebugwarning',
|
||||
'displayerrorswarning',
|
||||
], $issuekeys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+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"
|
||||
|
||||
@@ -67,14 +67,10 @@ Feature: Upload users
|
||||
@javascript
|
||||
Scenario: Upload users with custom profile fields
|
||||
# Create user profile field.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Accounts > User profile fields" in site administration
|
||||
And I click on "Create a new profile field" "link"
|
||||
And I click on "Text area" "link"
|
||||
And I set the following fields to these values:
|
||||
| Short name | superfield |
|
||||
| Name | Super field |
|
||||
And I click on "Save changes" "button"
|
||||
Given the following "custom profile fields" exist:
|
||||
| datatype | shortname | name |
|
||||
| text | superfield | Super field |
|
||||
And I log in as "admin"
|
||||
# Upload users.
|
||||
When I navigate to "Users > Accounts > Upload users" in site administration
|
||||
And I upload "lib/tests/fixtures/upload_users_profile.csv" file to "File" filemanager
|
||||
|
||||
@@ -152,14 +152,11 @@ Feature: Apply tour filters to a tour
|
||||
| fullname | shortname | format | enablecompletion |
|
||||
| Course 1 | C1 | topics | 1 |
|
||||
| Course 2 | C2 | topics | 1 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | firstpagetitle | wikimode |
|
||||
| wiki | C1 | Test wiki name | First page | collaborative |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Wiki" to section "1" and I fill the form with:
|
||||
| Wiki name | Test wiki name |
|
||||
| Description | Test wiki description |
|
||||
| First page name | First page |
|
||||
| Wiki mode | Collaborative wiki |
|
||||
And I am on "Course 2" course homepage
|
||||
And I am on "Course 2" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Forum type | Standard forum for general use |
|
||||
|
||||
@@ -378,7 +378,7 @@ class condition_test extends \advanced_testcase {
|
||||
/**
|
||||
* Tests the is_available and get_description functions for previous activity option.
|
||||
*
|
||||
* @dataProvider test_previous_activity_data
|
||||
* @dataProvider previous_activity_data
|
||||
* @param int $grade the current assign grade (0 for none)
|
||||
* @param int $condition true for complete, false for incomplete
|
||||
* @param string $mark activity to mark as complete
|
||||
@@ -467,7 +467,7 @@ class condition_test extends \advanced_testcase {
|
||||
$this->assertMatchesRegularExpression($description, $information);
|
||||
}
|
||||
|
||||
public function test_previous_activity_data(): array {
|
||||
public function previous_activity_data(): array {
|
||||
// Assign grade, condition, activity to complete, activity to test, result, resultnot, description.
|
||||
return [
|
||||
'Missing previous activity complete' => [
|
||||
@@ -559,7 +559,7 @@ class condition_test extends \advanced_testcase {
|
||||
* Tests the is_available and get_description functions for
|
||||
* previous activity option in course sections.
|
||||
*
|
||||
* @dataProvider test_section_previous_activity_data
|
||||
* @dataProvider section_previous_activity_data
|
||||
* @param int $condition condition value
|
||||
* @param bool $mark if Page 1 must be mark as completed
|
||||
* @param string $section section to add the availability
|
||||
@@ -632,7 +632,7 @@ class condition_test extends \advanced_testcase {
|
||||
|
||||
}
|
||||
|
||||
public function test_section_previous_activity_data(): array {
|
||||
public function section_previous_activity_data(): array {
|
||||
return [
|
||||
// Condition, Activity completion, section to test, result, resultnot, description.
|
||||
'Completion complete Section with no previous activity' => [
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -197,7 +197,12 @@ class condition extends \core_availability\condition {
|
||||
$this->customfield);
|
||||
}
|
||||
} else {
|
||||
$translatedfieldname = \core_user\fields::get_display_name($this->standardfield);
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (array_key_exists($this->standardfield, $standardfields)) {
|
||||
$translatedfieldname = $standardfields[$this->standardfield];
|
||||
} else {
|
||||
$translatedfieldname = get_string('missing', 'availability_profile', $this->standardfield);
|
||||
}
|
||||
}
|
||||
$a = new \stdClass();
|
||||
// Not safe to call format_string here; use the special function to call it later.
|
||||
@@ -321,6 +326,27 @@ class condition extends \core_availability\condition {
|
||||
return $fieldconditionmet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of standard user profile fields used by the condition
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_standard_profile_fields(): array {
|
||||
return [
|
||||
'firstname' => \core_user\fields::get_display_name('firstname'),
|
||||
'lastname' => \core_user\fields::get_display_name('lastname'),
|
||||
'email' => \core_user\fields::get_display_name('email'),
|
||||
'city' => \core_user\fields::get_display_name('city'),
|
||||
'country' => \core_user\fields::get_display_name('country'),
|
||||
'idnumber' => \core_user\fields::get_display_name('idnumber'),
|
||||
'institution' => \core_user\fields::get_display_name('institution'),
|
||||
'department' => \core_user\fields::get_display_name('department'),
|
||||
'phone1' => \core_user\fields::get_display_name('phone1'),
|
||||
'phone2' => \core_user\fields::get_display_name('phone2'),
|
||||
'address' => \core_user\fields::get_display_name('address'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data about custom profile fields. Cached statically in current
|
||||
* request.
|
||||
@@ -472,6 +498,11 @@ class condition extends \core_availability\condition {
|
||||
$valuefield = 'data';
|
||||
$default = $customfield->defaultdata;
|
||||
} else {
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (!array_key_exists($this->standardfield, $standardfields)) {
|
||||
// If the field isn't found, nobody matches.
|
||||
return [];
|
||||
}
|
||||
$values = $DB->get_records_select('user', 'id ' . $sql, $params,
|
||||
'', 'id, '. $this->standardfield);
|
||||
$valuefield = $this->standardfield;
|
||||
@@ -595,6 +626,11 @@ class condition extends \core_availability\condition {
|
||||
$where = "(ud.data IS NOT NULL AND $condition)";
|
||||
}
|
||||
} else {
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (!array_key_exists($this->standardfield, $standardfields)) {
|
||||
// If the field isn't found, nobody matches.
|
||||
return ['SELECT id FROM {user} WHERE 0 = 1', []];
|
||||
}
|
||||
$tablesql = "JOIN {user} u ON u.id = userids.id";
|
||||
list ($where, $mainparams) = $this->get_condition_sql(
|
||||
'u.' . $this->standardfield);
|
||||
|
||||
@@ -42,20 +42,9 @@ class frontend extends \core_availability\frontend {
|
||||
|
||||
protected function get_javascript_init_params($course, \cm_info $cm = null,
|
||||
\section_info $section = null) {
|
||||
|
||||
// Standard user fields.
|
||||
$standardfields = array(
|
||||
'firstname' => \core_user\fields::get_display_name('firstname'),
|
||||
'lastname' => \core_user\fields::get_display_name('lastname'),
|
||||
'email' => \core_user\fields::get_display_name('email'),
|
||||
'city' => \core_user\fields::get_display_name('city'),
|
||||
'country' => \core_user\fields::get_display_name('country'),
|
||||
'idnumber' => \core_user\fields::get_display_name('idnumber'),
|
||||
'institution' => \core_user\fields::get_display_name('institution'),
|
||||
'department' => \core_user\fields::get_display_name('department'),
|
||||
'phone1' => \core_user\fields::get_display_name('phone1'),
|
||||
'phone2' => \core_user\fields::get_display_name('phone2'),
|
||||
'address' => \core_user\fields::get_display_name('address')
|
||||
);
|
||||
$standardfields = condition::get_standard_profile_fields();
|
||||
\core_collator::asort($standardfields);
|
||||
|
||||
// Custom fields.
|
||||
|
||||
@@ -39,7 +39,7 @@ $string['requires_notendswith'] = 'Your <strong>{$a->field}</strong> does not en
|
||||
$string['requires_notisequalto'] = 'Your <strong>{$a->field}</strong> is not <strong>{$a->value}</strong>';
|
||||
$string['requires_notstartswith'] = 'Your <strong>{$a->field}</strong> does not start with <strong>{$a->value}</strong>';
|
||||
$string['requires_startswith'] = 'Your <strong>{$a->field}</strong> starts with <strong>{$a->value}</strong>';
|
||||
$string['missing'] = '(Missing custom field: {$a})';
|
||||
$string['missing'] = '(Missing field: {$a})';
|
||||
$string['title'] = 'User profile';
|
||||
$string['op_contains'] = 'contains';
|
||||
$string['op_doesnotcontain'] = 'doesn\'t contain';
|
||||
|
||||
@@ -62,15 +62,10 @@ Feature: availability_profile
|
||||
|
||||
@javascript
|
||||
Scenario: Test with custom user profile field
|
||||
# Add custom field.
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Users > Accounts > User profile fields" in site administration
|
||||
And I click on "Create a new profile field" "link"
|
||||
And I click on "Text input" "link"
|
||||
And I set the following fields to these values:
|
||||
| Short name | superfield |
|
||||
| Name | Super field |
|
||||
And I click on "Save changes" "button"
|
||||
Given the following "custom profile fields" exist:
|
||||
| datatype | shortname | name |
|
||||
| text | superfield | Super field |
|
||||
And I log in as "admin"
|
||||
|
||||
# Set field value for user.
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class backup_files_edit_form extends moodleform {
|
||||
$mform->setType('component', PARAM_COMPONENT);
|
||||
|
||||
$mform->addElement('hidden', 'returnurl', $this->_customdata['returnurl']);
|
||||
$mform->setType('returnurl', PARAM_URL);
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
$this->set_data($this->_customdata['data']);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -15,25 +15,15 @@ Feature: Block appearances
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | description | course | idnumber | section |
|
||||
| survey | Test survey name | Test survey description | C1 | survey1 | 1 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I follow "Test survey name"
|
||||
And I navigate to "Edit settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Survey type | ATTLS (20 item version) |
|
||||
And I press "Save and return to course"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I follow "Test book name"
|
||||
And I set the following fields to these values:
|
||||
| Chapter title | Book title |
|
||||
| Content | Book content test test |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
| activity | name | course | idnumber | section | template |
|
||||
| survey | Test survey name | C1 | survey1 | 1 | 4 |
|
||||
| book | Test book name | C1 | book1 | 1 | |
|
||||
And the following "mod_book > chapter" exists:
|
||||
| book | Test book name |
|
||||
| title | Book title |
|
||||
| content | Book content test test |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I turn editing mode on
|
||||
And I add the "Comments" block
|
||||
And I configure the "Comments" block
|
||||
And I set the following fields to these values:
|
||||
|
||||
@@ -14,21 +14,14 @@ Feature: Block region moving
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Survey" to section "1" and I fill the form with:
|
||||
| Name | Test survey name |
|
||||
| Survey type | ATTLS (20 item version) |
|
||||
| Description | Test survey description |
|
||||
And I add a "Book" to section "1" and I fill the form with:
|
||||
| Name | Test book name |
|
||||
| Description | Test book description |
|
||||
And I follow "Test book name"
|
||||
And I set the following fields to these values:
|
||||
| Chapter title | Book title |
|
||||
| Content | Book content test test |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | template |
|
||||
| survey | Test survey name | C1 | 4 |
|
||||
| book | Test book name | C1 | |
|
||||
And the following "mod_book > chapter" exists:
|
||||
| book | Test book name |
|
||||
| title | Book title |
|
||||
| content | Book content test test |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Comments" block
|
||||
|
||||
@@ -64,7 +64,7 @@ class blog_edit_external_form extends moodleform {
|
||||
$mform->setDefault('id', 0);
|
||||
|
||||
$mform->addElement('hidden', 'returnurl');
|
||||
$mform->setType('returnurl', PARAM_URL);
|
||||
$mform->setType('returnurl', PARAM_LOCALURL);
|
||||
$mform->setDefault('returnurl', 0);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace MongoDB\Exception;
|
||||
use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function get_debug_type;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function sprintf;
|
||||
@@ -56,6 +56,6 @@ class InvalidArgumentException extends DriverInvalidArgumentException implements
|
||||
$expectedType = $typeString;
|
||||
}
|
||||
|
||||
return new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, get_debug_type($value)));
|
||||
return new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, gettype($value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
use function get_debug_type;
|
||||
use function gettype;
|
||||
use function sprintf;
|
||||
|
||||
class ResumeTokenException extends RuntimeException
|
||||
@@ -30,7 +30,7 @@ class ResumeTokenException extends RuntimeException
|
||||
*/
|
||||
public static function invalidType($value)
|
||||
{
|
||||
return new static(sprintf('Expected resume token to have type "array or object" but found "%s"', get_debug_type($value)));
|
||||
return new static(sprintf('Expected resume token to have type "array or object" but found "%s"', gettype($value)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
@@ -10,3 +10,7 @@ Import procedure:
|
||||
- Check the minim php driver version in https://docs.mongodb.com/drivers/php#compatibility and change the value in the "are_requirements_met" method if necessary.
|
||||
|
||||
This version (1.8.0) requires PHP mongodb extension >= 1.8.0
|
||||
|
||||
Local changes:
|
||||
- Replaced 4 occurrences of get_debug_type() by gettype() to keep PHP 7.4 compatibility. Note this
|
||||
has not been applied to 4.2dev and up because, there, it's safe to use get_debug_type().
|
||||
|
||||
@@ -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}}
|
||||
|
||||
@@ -2624,7 +2624,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function test_get_calendar_event_by_id_prevent_read_other_users_events_data_provider(): array {
|
||||
public function get_calendar_event_by_id_prevent_read_other_users_events_data_provider(): array {
|
||||
$syscontext = \context_system::instance();
|
||||
$managerrole = 'manager';
|
||||
return [
|
||||
@@ -2639,7 +2639,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
* Prevent user from reading other user's event.
|
||||
*
|
||||
* @covers \core_calendar_external::get_calendar_event_by_id
|
||||
* @dataProvider test_get_calendar_event_by_id_prevent_read_other_users_events_data_provider
|
||||
* @dataProvider get_calendar_event_by_id_prevent_read_other_users_events_data_provider
|
||||
*
|
||||
* @param bool $isadminevent Is admin's event
|
||||
* @param bool $isadmin Is current user admin user
|
||||
@@ -2695,7 +2695,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function test_edit_or_delete_other_users_events_data_provider(): array {
|
||||
public function edit_or_delete_other_users_events_data_provider(): array {
|
||||
$syscontext = \context_system::instance();
|
||||
$managerrole = 'manager';
|
||||
return [
|
||||
@@ -2709,7 +2709,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test the behavior of deleting other users' user events.
|
||||
*
|
||||
* @dataProvider test_edit_or_delete_other_users_events_data_provider
|
||||
* @dataProvider edit_or_delete_other_users_events_data_provider
|
||||
* @covers \core_calendar_external::delete_calendar_events
|
||||
* @param bool $isadmin Whether the current user is admin.
|
||||
* @param bool $isadminevent Whether it's an admin event or not.
|
||||
@@ -2756,7 +2756,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test the behavior of editing other users' user events
|
||||
*
|
||||
* @dataProvider test_edit_or_delete_other_users_events_data_provider
|
||||
* @dataProvider edit_or_delete_other_users_events_data_provider
|
||||
* @covers \core_calendar_external::submit_create_update_form
|
||||
* @param bool $isadmin Whether the current user is admin.
|
||||
* @param bool $isadminevent Whether it's an admin event or not.
|
||||
|
||||
@@ -49,7 +49,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test proxying.
|
||||
*
|
||||
* @dataProvider test_proxy_testcases()
|
||||
* @dataProvider proxy_testcases
|
||||
* @param int $id Object ID.
|
||||
* @param string $member Object member to retrieve.
|
||||
* @param mixed $expected Expected value of member.
|
||||
@@ -65,7 +65,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test setting values with a base class.
|
||||
*
|
||||
* @dataProvider test_proxy_testcases()
|
||||
* @dataProvider proxy_testcases
|
||||
* @param int $id Object ID.
|
||||
* @param string $member Object member to retrieve.
|
||||
* @param mixed $storedvalue Value as would be stored externally.
|
||||
@@ -86,7 +86,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test getting a non existant member.
|
||||
*
|
||||
* @dataProvider test_get_set_testcases()
|
||||
* @dataProvider get_set_testcases
|
||||
* @param int $id ID of the object being proxied.
|
||||
*/
|
||||
public function test_get_invalid_member($id) {
|
||||
@@ -101,7 +101,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test get proxied instance.
|
||||
*
|
||||
* @dataProvider test_get_set_testcases()
|
||||
* @dataProvider get_set_testcases
|
||||
* @param int $id Object ID.
|
||||
*/
|
||||
public function test_get_proxied_instance($id) {
|
||||
@@ -115,7 +115,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test cases for proxying test.
|
||||
*/
|
||||
public function test_proxy_testcases() {
|
||||
public function proxy_testcases() {
|
||||
return [
|
||||
'Object 1 member 1' => [
|
||||
1,
|
||||
@@ -153,7 +153,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test cases for getting and setting tests.
|
||||
*/
|
||||
public function test_get_set_testcases() {
|
||||
public function get_set_testcases() {
|
||||
return [
|
||||
'Object 1' => [1],
|
||||
'Object 2' => [5]
|
||||
|
||||
@@ -108,26 +108,16 @@ class completion_criteria_test extends \advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that enrolment timestart/timecreated are used when duration criteria is marked as completed.
|
||||
* Test that enrolment timestart are used when duration criteria is marked as completed.
|
||||
*/
|
||||
public function test_completion_criteria_duration(): void {
|
||||
public function test_completion_criteria_duration_timestart(): void {
|
||||
global $DB;
|
||||
$timestarted = 1610000000;
|
||||
$timecreated = 1620000000;
|
||||
$durationperiod = DAYSECS;
|
||||
|
||||
// Create a course and users.
|
||||
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
|
||||
|
||||
// Enrol User 1 with time start = $timestarted.
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id, 'manual', $timestarted);
|
||||
|
||||
// Enrol User 2 with an empty time start, but update the record like it was created at $timecreated.
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id);
|
||||
$DB->set_field('user_enrolments', 'timecreated', $timecreated, ['userid' => $user2->id]);
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', $timestarted);
|
||||
|
||||
// Set completion criteria.
|
||||
$criteriadata = (object) [
|
||||
@@ -147,13 +137,49 @@ class completion_criteria_test extends \advanced_testcase {
|
||||
sleep(1);
|
||||
$task->execute();
|
||||
|
||||
// The course for User 1 is supposed to be marked as completed at $timestarted + $durationperiod.
|
||||
$ccompletion = new \completion_completion(['userid' => $user1->id, 'course' => $course->id]);
|
||||
// The course for User is supposed to be marked as completed at $timestarted + $durationperiod.
|
||||
$ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
|
||||
$this->assertEquals($timestarted + $durationperiod, $ccompletion->timecompleted);
|
||||
$this->assertTrue($ccompletion->is_complete());
|
||||
}
|
||||
|
||||
// The course for User 2 is supposed to be marked as completed at $timecreated + $durationperiod.
|
||||
$ccompletion = new \completion_completion(['userid' => $user2->id, 'course' => $course->id]);
|
||||
/**
|
||||
* Test that enrolment timecreated are used when duration criteria is marked as completed.
|
||||
*/
|
||||
public function test_completion_criteria_duration_timecreated(): void {
|
||||
global $DB;
|
||||
|
||||
$timecreated = 1620000000;
|
||||
$durationperiod = DAYSECS;
|
||||
|
||||
// Create a course and users.
|
||||
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
|
||||
|
||||
// Create and enrol user with an empty time start, but update the record like it was created at $timecreated.
|
||||
$user = $this->getDataGenerator()->create_and_enrol($course);
|
||||
$DB->set_field('user_enrolments', 'timecreated', $timecreated, ['userid' => $user->id]);
|
||||
|
||||
// Set completion criteria.
|
||||
$criteriadata = (object) [
|
||||
'id' => $course->id,
|
||||
'criteria_duration' => 1,
|
||||
'criteria_duration_days' => $durationperiod,
|
||||
];
|
||||
$criterion = new \completion_criteria_duration();
|
||||
$criterion->update_config($criteriadata);
|
||||
|
||||
// Run completion scheduled task.
|
||||
$task = new \core\task\completion_regular_task();
|
||||
$this->expectOutputRegex("/Marking complete/");
|
||||
$task->execute();
|
||||
|
||||
// Hopefully, some day MDL-33320 will be fixed and all these sleeps
|
||||
// and double cron calls in behat and unit tests will be removed.
|
||||
sleep(1);
|
||||
$task->execute();
|
||||
|
||||
// The course for user is supposed to be marked as completed at $timecreated + $durationperiod.
|
||||
$ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
|
||||
$this->assertEquals($timecreated + $durationperiod, $ccompletion->timecompleted);
|
||||
$this->assertTrue($ccompletion->is_complete());
|
||||
}
|
||||
|
||||
+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.2.1"
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-0": {
|
||||
|
||||
Generated
+427
-666
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:
|
||||
|
||||
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);
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Sections can be edited and deleted in topics format
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Test assignment name | Test assignment description | C1 | assign1 | 0 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 |
|
||||
| book | Test book name | | C1 | book1 | 1 |
|
||||
| chat | Test chat name | Test chat description | C1 | chat1 | 4 |
|
||||
| choice | Test choice name | Test choice description | C1 | choice1 | 5 |
|
||||
And the following "course enrolments" exist:
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Sections can be edited and deleted in weeks format
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Test assignment name | Test assignment description | C1 | assign1 | 0 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 |
|
||||
| book | Test book name | | C1 | book1 | 1 |
|
||||
| chat | Test chat name | Test chat description | C1 | chat1 | 4 |
|
||||
| choice | Test choice name | Test choice description | C1 | choice1 | 5 |
|
||||
And the following "course enrolments" exist:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -34,7 +34,7 @@ require_once($CFG->dirroot.'/course/lib.php');
|
||||
|
||||
$id = required_param('id', PARAM_INT);
|
||||
$switchrole = optional_param('switchrole', -1, PARAM_INT);
|
||||
$returnurl = optional_param('returnurl', '', PARAM_RAW);
|
||||
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
|
||||
|
||||
if (strpos($returnurl, '?') === false) {
|
||||
// Looks like somebody did not set proper page url, better go to course page.
|
||||
@@ -43,7 +43,7 @@ if (strpos($returnurl, '?') === false) {
|
||||
if (strpos($returnurl, $CFG->wwwroot) !== 0) {
|
||||
$returnurl = $CFG->wwwroot.$returnurl;
|
||||
}
|
||||
$returnurl = clean_param($returnurl, PARAM_URL);
|
||||
$returnurl = clean_param($returnurl, PARAM_LOCALURL);
|
||||
}
|
||||
|
||||
$PAGE->set_url('/course/switchrole.php', array('id'=>$id, 'switchrole'=>$switchrole));
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
@core @core_course
|
||||
Feature: Teacher can change the course format
|
||||
In order to change course format
|
||||
As a teacher
|
||||
I should be able to edit a course
|
||||
|
||||
@javascript
|
||||
Scenario: Teacher can change the course format
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
# Course format is initially set to Topics format
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format | startdate |
|
||||
| Course 1 | C1 | topics | ## 1 day ago ## |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
# Confirm that course format is Topics
|
||||
When I am on the "Course 1" course page logged in as teacher1
|
||||
Then I should see "Topic 1"
|
||||
And I am on the "Course 1" "course editing" page
|
||||
And I expand all fieldsets
|
||||
# Fields that appear for Topics format exist
|
||||
# Also confirm contents of Hidden sections and Course layout select box
|
||||
And I should see "Hidden sections"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are shown in collapsed form"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are completely invisible"
|
||||
# Hidden sections default value is 0 (Hidden sections are shown in collapsed form)
|
||||
And the field "Hidden sections" matches value "0"
|
||||
And I should see "Course layout"
|
||||
And the "Course layout" select box should contain "Show all sections on one page"
|
||||
And the "Course layout" select box should contain "Show one section per page"
|
||||
# Course layout default value is 0 (Show all sections on one page)
|
||||
And the field "Course layout" matches value "0"
|
||||
# Set course format to Single activity format
|
||||
And I set the field "Format" to "Single activity format"
|
||||
And I expand all fieldsets
|
||||
# Confirm that fields that appear for Single activity format appears
|
||||
And I should see "Type of activity"
|
||||
And I set the field "Type of activity" to "Glossary"
|
||||
And I press "Save and display"
|
||||
And I set the field "Name" to "Glossary 1"
|
||||
And I press "Save and display"
|
||||
# Confirm that course page displays single activity of type Glossary
|
||||
And I should see "Browse the glossary using this index"
|
||||
And I should not see "Topic 1"
|
||||
And I am on the "Course 1" "course editing" page
|
||||
And I expand all fieldsets
|
||||
# Set course format to Weekly format
|
||||
And I set the field "Format" to "Weekly format"
|
||||
And I expand all fieldsets
|
||||
# Confirm that fields that appear for Weekly format appears
|
||||
# Also confirm contents of Hidden sections and Course layout select box
|
||||
And I should see "Hidden sections"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are shown in collapsed form"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are completely invisible"
|
||||
# Hidden sections default value is 0 (Hidden sections are shown in collapsed form)
|
||||
And the field "Hidden sections" matches value "0"
|
||||
And I should see "Course layout"
|
||||
And the "Course layout" select box should contain "Show all sections on one page"
|
||||
And the "Course layout" select box should contain "Show one section per page"
|
||||
# Course layout default value is 0 (Show all sections on one page)
|
||||
And the field "Course layout" matches value "0"
|
||||
And I press "Save and display"
|
||||
# Confirm that course page displays weekly sections
|
||||
And I should see "This week"
|
||||
And I should not see "Browse the glossary using this index"
|
||||
And I am on the "Course 1" "course editing" page
|
||||
And I expand all fieldsets
|
||||
# Set course format to Social format
|
||||
And I set the field "Format" to "Social format"
|
||||
# Confirm that fields that appear for Social format appears
|
||||
And I expand all fieldsets
|
||||
And I should see "Number of discussions"
|
||||
And the field "Number of discussions" matches value "10"
|
||||
And I press "Save and display"
|
||||
# Confirm that course page displays a forum
|
||||
And I should see "There are no discussion topics yet in this forum"
|
||||
And I should not see "This week"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user