Compare commits
331 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c989335be | |||
| d4937c4527 | |||
| 62e7dc94d9 | |||
| cf40395830 | |||
| ab62e5f23f | |||
| a29056941b | |||
| 78db6582ba | |||
| b1ccbfc24d | |||
| 8c9545ca78 | |||
| 5b48a61484 | |||
| ef3eb09347 | |||
| abff2a6570 | |||
| 15afb64771 | |||
| c8631653cd | |||
| 30add0c159 | |||
| 2fbb766149 | |||
| 3fa41951f3 | |||
| 3d02f36f87 | |||
| dcd20bec34 | |||
| fec48e90ac | |||
| 1a469cda51 | |||
| f98b725610 | |||
| cc9f2527a8 | |||
| 8e5f9ca9d4 | |||
| d247ea08e9 | |||
| eab902354f | |||
| d3e4957556 | |||
| 40b68fd88f | |||
| c180b1babd | |||
| a1e281a31d | |||
| ab12596a7b | |||
| fd5585777f | |||
| 5132a27822 | |||
| 9f6fbc11dd | |||
| a801a741b9 | |||
| 685be3d41b | |||
| 0e504f73ee | |||
| 7dfcc7e3f5 | |||
| 35500db40c | |||
| cfb5b76ba7 | |||
| ff68353e39 | |||
| 0f410c087a | |||
| e160cdd8a7 | |||
| d25ad8aaf9 | |||
| c938c41de8 | |||
| 04996f2cf8 | |||
| 5481c31fe6 | |||
| 79a9167a1e | |||
| 4d035d0f80 | |||
| cd885856f3 | |||
| 5f67d77aae | |||
| d59a10108c | |||
| b4cf5c50bf | |||
| 71440dc236 | |||
| 75264720ac | |||
| 735c2c6b47 | |||
| 319d3954f8 | |||
| 0fc6e59121 | |||
| ace6e8db3d | |||
| 2970f0f433 | |||
| 4899d8c11a | |||
| 20302d4f86 | |||
| d1053fe035 | |||
| 5d361ee332 | |||
| a43b2b2998 | |||
| cf46e93304 | |||
| bb7b0f996d | |||
| 9c5e63cf17 | |||
| 5d89ce0058 | |||
| 6143ad4b1b | |||
| d54edef0f7 | |||
| 02d2e80bae | |||
| 5cf5134a12 | |||
| 5112c89929 | |||
| fab3b2ccbc | |||
| 56f75d7aea | |||
| 2f10bf1a1f | |||
| 0384f8dfa0 | |||
| e05576d74c | |||
| 01b577ee65 | |||
| 0f5a1a61f7 | |||
| b4479d7981 | |||
| 2a2badacb2 | |||
| eb0585ea72 | |||
| 7faf41dce5 | |||
| 6aa360ae83 | |||
| 804e8b62da | |||
| 1092a998ae | |||
| 027e3c6660 | |||
| 2b407d891f | |||
| 1b284001ac | |||
| b3350a0ea7 | |||
| 0ffed15ee4 | |||
| d20cf16533 | |||
| 3e13847324 | |||
| 24f646038c | |||
| 928760f865 | |||
| 9a3f097da5 | |||
| 1198d57f71 | |||
| 6b8884e13b | |||
| 7edbca66f9 | |||
| e0c8854480 | |||
| 7d5b30290f | |||
| 3e2bf77656 | |||
| 15b0cd25e6 | |||
| e99fcecdf9 | |||
| 5feb510035 | |||
| cae92e5a92 | |||
| 1342f28224 | |||
| b0b214bbf2 | |||
| 1ff32127d4 | |||
| a443a29b79 | |||
| f92c748a2d | |||
| af0f37405f | |||
| fb71a7a8c7 | |||
| b10afcdd4c | |||
| 93c35a89bb | |||
| 43fdf37a96 | |||
| b490a0ae08 | |||
| 80410a354b | |||
| b1b0c2d59b | |||
| aa7aec1088 | |||
| 7bae6c8ca6 | |||
| 7a5806d3cb | |||
| 279cc50e5c | |||
| dc4ff6a2f5 | |||
| fb343534d0 | |||
| b4935649b3 | |||
| 0d426e571a | |||
| b938b53096 | |||
| 525b69dc69 | |||
| 5630f86d81 | |||
| 30ac87781a | |||
| 2b9a9286d0 | |||
| 2e6d8b72b1 | |||
| 2724eb6041 | |||
| df8413ade0 | |||
| 414f0df046 | |||
| 29a7e00f9c | |||
| 81b9a51fb7 | |||
| 03c461ab87 | |||
| c2fbb10a52 | |||
| 4781b41631 | |||
| caf4da762c | |||
| 0ab5bf01f0 | |||
| 078782e656 | |||
| 2b6456c1d0 | |||
| a37ce627a8 | |||
| 26b885edb6 | |||
| b514f0bb1d | |||
| 12dc12c954 | |||
| ec7b3cab86 | |||
| 6808c8f3b2 | |||
| 109a0ffeb9 | |||
| 4a04cda71b | |||
| a0920d8b8d | |||
| 11bf54289f | |||
| 666708b561 | |||
| a1162e3943 | |||
| 9de9651809 | |||
| dcb3ce31ce | |||
| 8b641a1b0d | |||
| 8fa53a336e | |||
| 5a22258f42 | |||
| 92cba2c5ba | |||
| 7d8a40fe3e | |||
| 2de2d6bc30 | |||
| beb55edffc | |||
| ae8466162d | |||
| b5f98e022d | |||
| b9d21ee2ad | |||
| 04fb9beb20 | |||
| 3be559b763 | |||
| 88a1d4d4c2 | |||
| e0045688b3 | |||
| c645df564a | |||
| 8bac8a2da7 | |||
| 2e339446d8 | |||
| 1c9379ab09 | |||
| 24ad6848aa | |||
| da43ea4ef7 | |||
| f49f24c516 | |||
| 473cfc369d | |||
| 0ba9466281 | |||
| 9e6f6c0e7e | |||
| b87a75110b | |||
| 52bcdf9e06 | |||
| f113d4c116 | |||
| 16bac432fd | |||
| 4e28613a16 | |||
| 1df40c823e | |||
| 5dfec00bb1 | |||
| c00c6dd4cf | |||
| 0f687a9028 | |||
| 1d2b0ade40 | |||
| a5f2c1d591 | |||
| 5e59ad2b6e | |||
| 441003231f | |||
| 54c8336373 | |||
| e3ac233307 | |||
| 4d263b0505 | |||
| 25953f9c7f | |||
| b112cee58c | |||
| bc7dacecb6 | |||
| d1fcfd1de2 | |||
| 32bc50a135 | |||
| 02e893a575 | |||
| 59c75c928d | |||
| c2a74815c0 | |||
| 9ac38f5db6 | |||
| 04b35cb3db | |||
| c6cc0449ed | |||
| 30f1f0778f | |||
| f9edf5c1be | |||
| c4f7a44824 | |||
| 26dbb8466a | |||
| 2fb84af337 | |||
| 717c74a448 | |||
| 4a2e621012 | |||
| 732dc4f334 | |||
| c348119685 | |||
| ced8835b5f | |||
| a5cf13cd90 | |||
| 10f9d0d51a | |||
| 9bdfec812d | |||
| 78d90e3c16 | |||
| d5ec3594cc | |||
| 5303c032bb | |||
| b2cca9ef62 | |||
| 87736d9a0b | |||
| b1496fa5df | |||
| 411dc66fd9 | |||
| c58d3b4759 | |||
| 39a930f762 | |||
| 3493d9ebc3 | |||
| eff51c6001 | |||
| 7365bc38b2 | |||
| 856803faf8 | |||
| 97d935b337 | |||
| f46e5fc229 | |||
| 8a6c536b29 | |||
| 84da51dafd | |||
| 98448477d9 | |||
| 62076a191e | |||
| b1a7ae63c3 | |||
| 929ad63114 | |||
| 29a21ee986 | |||
| c721cc6803 | |||
| 2ccc6a2346 | |||
| cd3643a149 | |||
| 2138619b01 | |||
| 97f6672420 | |||
| f6afe82978 | |||
| 16f91dfdb3 | |||
| da46551bea | |||
| 861ce57a8a | |||
| 048070e25f | |||
| 223b1afabf | |||
| 92a57c95be | |||
| 680644b593 | |||
| bdaed5ec3c | |||
| 812219fcb2 | |||
| 514865575c | |||
| 1b1c1a56b1 | |||
| 33f62c3309 | |||
| 0f66c8fe5c | |||
| a56ca931aa | |||
| 453ea97395 | |||
| 4e9be8c131 | |||
| a7055da32d | |||
| bd85500e2a | |||
| e0e94dbf84 | |||
| 9de24c27c6 | |||
| 89215b79fb | |||
| 4065904ad1 | |||
| 3862ec015d | |||
| c516a6fc14 | |||
| fb14c67dec | |||
| b297347f12 | |||
| b89351f084 | |||
| b78a8983ed | |||
| 84ddb8c655 | |||
| cc3828c85a | |||
| 7af8bddad7 | |||
| 3bdfc594b6 | |||
| c6ff4c551e | |||
| b6531bf613 | |||
| 7c4fc1725f | |||
| 4f625c1e2e | |||
| 99e38b7118 | |||
| 5650cab0d6 | |||
| 4b23b98e16 | |||
| c7595a7169 | |||
| b97ffab51a | |||
| f1633ba0f8 | |||
| 3f4b46b16a | |||
| 32df1530ff | |||
| 20e1d18c29 | |||
| 01fd68f06d | |||
| a8a3855c6d | |||
| 950aa78611 | |||
| b2e36b6baa | |||
| 85662b721b | |||
| eb6c618fd4 | |||
| d43dc80d65 | |||
| 8e1583455e | |||
| 4bfce15818 | |||
| 6b8aeb5c90 | |||
| d9f71f0666 | |||
| 9e0d12e5ae | |||
| 86fd45f0de | |||
| ffd32bacba | |||
| 3ee04ecf78 | |||
| c675170c4e | |||
| 0c74bbfa06 | |||
| 4f7ccd0432 | |||
| 4806324231 | |||
| 9c779fefc7 | |||
| b82cc59782 | |||
| e38a933fa2 | |||
| 9ef5ed8527 | |||
| f1afcf6616 | |||
| 0a05336551 | |||
| a9c5734f04 | |||
| 1e81424bdd | |||
| 4aaaaa5f57 | |||
| 963b56cf7e | |||
| f3368a55b5 | |||
| 37564d61d5 | |||
| 94a87bc47e | |||
| e6615e587f |
@@ -0,0 +1,144 @@
|
||||
name: Windows Testing
|
||||
|
||||
on:
|
||||
workflow_dispatch
|
||||
env:
|
||||
php: 8.1
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
- name: Installing node stuff
|
||||
run: npm ci
|
||||
|
||||
- name: Running grunt
|
||||
run: npx grunt
|
||||
|
||||
- name: Looking for uncommitted changes
|
||||
# Add all files to the git index and then run diff --cached to see all changes.
|
||||
# This ensures that we get the status of all files, including new files.
|
||||
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
|
||||
run: |
|
||||
git add .
|
||||
git reset -- npm-shrinkwrap.json
|
||||
git diff --cached --exit-code
|
||||
|
||||
PHPUnit:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
php: 8.1
|
||||
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
|
||||
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
|
||||
# this is the place to enable them.
|
||||
# db: mysqli
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
|
||||
- os: windows-latest
|
||||
php: 8.0
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
|
||||
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: shogo82148/actions-setup-mysql@v1
|
||||
with:
|
||||
mysql-version: 8.0
|
||||
user: test
|
||||
password: test
|
||||
|
||||
- name: Creating DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
run: mysql --host 127.0.0.1 -utest -ptest -e 'CREATE DATABASE IF NOT EXISTS test COLLATE = utf8mb4_bin;';
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
run: |
|
||||
# TODO: Remove these conf. modifications when php74 or php80 are lowest.
|
||||
# Change to old md5 auth, because php73 does not support it.
|
||||
# #password_encryption = scram-sha-256
|
||||
(Get-Content "$env:PGDATA\postgresql.conf"). `
|
||||
replace('#password_encryption = scram-sha-256', 'password_encryption = md5') | `
|
||||
Set-Content "$env:PGDATA\postgresql.conf"
|
||||
(Get-Content "$env:PGDATA\pg_hba.conf"). `
|
||||
replace('scram-sha-256', 'md5') | `
|
||||
Set-Content "$env:PGDATA\pg_hba.conf"
|
||||
$pgService = Get-Service -Name postgresql*
|
||||
Set-Service -InputObject $pgService -Status running -StartupType automatic
|
||||
Start-Process -FilePath "$env:PGBIN\pg_isready" -Wait -PassThru
|
||||
& $env:PGBIN\psql --command="CREATE USER test PASSWORD 'test'" --command="\du"
|
||||
|
||||
- name: Creating DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
run: |
|
||||
& $env:PGBIN\createdb --owner=test test
|
||||
$env:PGPASSWORD = 'test'
|
||||
& $env:PGBIN\psql --username=test --host=localhost --list test
|
||||
|
||||
- name: Configuring git vars
|
||||
uses: rlespinasse/github-slug-action@v4
|
||||
|
||||
- name: Setting up PHP ${{ matrix.php }}
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: ${{ matrix.extensions }}
|
||||
ini-values: max_input_vars=5000
|
||||
coverage: none
|
||||
|
||||
- name: Set git to use LF
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Needs to be done after php is available, git configured and Moodle checkout has happened.
|
||||
- name: Setting up moodle-exttests service
|
||||
run: |
|
||||
git clone https://github.com/moodlehq/moodle-exttests.git
|
||||
nssm install php-built-in C:\tools\php\php.exe -S localhost:8080 -t D:\a\moodle\moodle\moodle-exttests
|
||||
nssm start php-built-in
|
||||
|
||||
- name: Setting up redis service
|
||||
run: |
|
||||
choco install redis-64 --version 3.0.503 --no-progress
|
||||
nssm install redis redis-server
|
||||
nssm start redis
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
|
||||
cp .github/workflows/config-template.php config.php
|
||||
mkdir ../moodledata
|
||||
php admin/tool/phpunit/cli/init.php --no-composer-self-update
|
||||
|
||||
- name: Running PHPUnit tests
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
phpunit_options: ${{ secrets.phpunit_options }}
|
||||
run: vendor/bin/phpunit $phpunit_options
|
||||
@@ -30,10 +30,9 @@
|
||||
* @param {String} srcPath the matched src path
|
||||
* @return {String} The rewritten destination path.
|
||||
*/
|
||||
|
||||
const babelRename = function(destPath, srcPath) {
|
||||
destPath = srcPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
destPath = srcPath.replace(`amd/src`, `amd/build`);
|
||||
destPath = destPath.replace(/\.js$/, '.min.js');
|
||||
return destPath;
|
||||
};
|
||||
|
||||
|
||||
@@ -3751,6 +3751,7 @@
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="7.4.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_82" message="unsupportedphpversion82" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
|
||||
@@ -6,7 +6,7 @@ require_once(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
include_once($CFG->dirroot.'/mnet/lib.php');
|
||||
|
||||
$sort = optional_param('sort', 'username', PARAM_ALPHA);
|
||||
$sort = optional_param('sort', 'username', PARAM_ALPHAEXT);
|
||||
$dir = optional_param('dir', 'ASC', PARAM_ALPHA);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$perpage = optional_param('perpage', 30, PARAM_INT);
|
||||
@@ -153,7 +153,15 @@ foreach ($columns as $column) {
|
||||
$headings[$column] = "<a href=\"?sort=$column&dir=$columndir&\">".$string[$column]."</a>$columnicon";
|
||||
}
|
||||
$headings['delete'] = '';
|
||||
$acl = $DB->get_records('mnet_sso_access_control', null, "$sort $dir", '*'); //, $page * $perpage, $perpage);
|
||||
|
||||
$sortorder = get_safe_orderby([
|
||||
'username' => 'username',
|
||||
'mnet_host_id' => 'mnet_host_id',
|
||||
'access' => 'accessctrl',
|
||||
'default' => 'username',
|
||||
], $sort, $dir, false);
|
||||
|
||||
$acl = $DB->get_records('mnet_sso_access_control', null, $sortorder);
|
||||
$aclcount = $DB->count_records('mnet_sso_access_control');
|
||||
|
||||
if (!$acl) {
|
||||
|
||||
@@ -83,7 +83,6 @@ if ($formdata = $simpleform->get_data()) {
|
||||
$mnet_peer->bootstrap($formdata->wwwroot, null, $application);
|
||||
// bootstrap the second form straight with the data from the first form
|
||||
$reviewform = new mnet_review_host_form(null, array('peer' => $mnet_peer)); // the second step (also the edit host form)
|
||||
$formdata->oldpublickey = $mnet_peer->public_key; // set this so we can confirm on form post without having to recreate the mnet_peer object
|
||||
$reviewform->set_data($mnet_peer);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->box_start();
|
||||
@@ -115,7 +114,6 @@ if (!empty($hostid)) {
|
||||
}
|
||||
$credentials = $mnet_peer->check_credentials($mnet_peer->public_key);
|
||||
$reviewform = new mnet_review_host_form(null, array('peer' => $mnet_peer)); // the second step (also the edit host form)
|
||||
$mnet_peer->oldpublickey = $mnet_peer->public_key; // set this so we can confirm on form post without having to recreate the mnet_peer object
|
||||
$reviewform->set_data((object)$mnet_peer);
|
||||
echo $OUTPUT->box_start();
|
||||
$reviewform->display();
|
||||
|
||||
@@ -56,12 +56,12 @@ Feature: Reset course indentation
|
||||
Scenario Outline: Apply course indentation reset
|
||||
Given I navigate to "Plugins > Course formats > <format> format" in site administration
|
||||
And I wait "5" seconds
|
||||
And "Reset indentation" "link" should exist
|
||||
When I click on "Reset indentation" "link"
|
||||
And I should see "Reset indentation on course page"
|
||||
And "Reset indentation" "button" should exist
|
||||
And I click on "Reset indentation" "button"
|
||||
Then I should see "Indentation reset"
|
||||
And "Reset indentation sitewide" "link" should exist
|
||||
When I click on "Reset indentation sitewide" "link"
|
||||
And I should see "Reset indentation sitewide"
|
||||
And "Reset indentation sitewide" "button" should exist
|
||||
And I click on "Reset indentation sitewide" "button"
|
||||
Then I should see "Indentation reset."
|
||||
And I am on "<format> Course 1" course homepage with editing mode on
|
||||
And I open "<format> forum name" actions menu
|
||||
And "Move right" "link" in the "<format> forum name" "activity" should be visible
|
||||
@@ -87,13 +87,13 @@ Feature: Reset course indentation
|
||||
|
||||
Scenario Outline: Cancel course indentation reset
|
||||
Given I navigate to "Plugins > Course formats > <format> format" in site administration
|
||||
And "Reset indentation" "link" should exist
|
||||
When I click on "Reset indentation" "link"
|
||||
And I should see "Reset indentation on course page"
|
||||
And "Reset indentation" "button" should exist
|
||||
And "Reset indentation sitewide" "link" should exist
|
||||
When I click on "Reset indentation sitewide" "link"
|
||||
And I should see "Reset indentation sitewide"
|
||||
And "Reset indentation sitewide" "button" should exist
|
||||
And "Cancel" "button" should exist
|
||||
And I click on "Cancel" "button"
|
||||
Then I should not see "Indentation reset"
|
||||
Then I should not see "Indentation reset."
|
||||
And I am on "<format> Course 1" course homepage with editing mode on
|
||||
And I open "<format> forum name" actions menu
|
||||
And "Move right" "link" in the "<format> forum name" "activity" should not be visible
|
||||
|
||||
@@ -49,7 +49,7 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'torun' => 0,
|
||||
'optimize-runs' => '',
|
||||
'add-core-features-to-theme' => false,
|
||||
'axe' => false,
|
||||
'axe' => null,
|
||||
'disable-composer' => false,
|
||||
'composer-upgrade' => true,
|
||||
'composer-self-update' => true,
|
||||
@@ -69,7 +69,7 @@ Behat utilities to initialise behat tests
|
||||
|
||||
Usage:
|
||||
php init.php [--parallel=value [--maxruns=value] [--fromrun=value --torun=value]]
|
||||
[--axe] [-o | --optimize-runs] [-a | --add-core-features-to-theme]
|
||||
[--no-axe] [-o | --optimize-runs] [-a | --add-core-features-to-theme]
|
||||
[--no-composer-self-update] [--no-composer-upgrade]
|
||||
[--disable-composer]
|
||||
[--help]
|
||||
@@ -79,7 +79,7 @@ Options:
|
||||
-m, --maxruns Max parallel processes to be executed at one time
|
||||
--fromrun Execute run starting from (Used for parallel runs on different vms)
|
||||
--torun Execute run till (Used for parallel runs on different vms)
|
||||
--axe Include axe accessibility tests
|
||||
--no-axe Disable axe accessibility tests.
|
||||
|
||||
-o, --optimize-runs
|
||||
Split features with specified tags in all parallel runs.
|
||||
@@ -102,7 +102,7 @@ Options:
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/behat/cli/init.php --parallel=2
|
||||
|
||||
More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
|
||||
More info in https://moodledev.io/general/development/tools/behat/running
|
||||
";
|
||||
|
||||
if (!empty($options['help'])) {
|
||||
@@ -110,6 +110,12 @@ if (!empty($options['help'])) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($options['axe']) {
|
||||
echo "Axe accessibility tests are enabled by default, to disable them, use the --no-axe option.\n";
|
||||
} else if ($options['axe'] === false) {
|
||||
echo "Axe accessibility tests have been disabled.\n";
|
||||
}
|
||||
|
||||
// Check which util file to call.
|
||||
$utilfile = 'util_single_run.php';
|
||||
$commandoptions = "";
|
||||
@@ -118,9 +124,7 @@ if ($options['parallel'] && $options['parallel'] > 1) {
|
||||
$utilfile = 'util.php';
|
||||
// Sanitize all input options, so they can be passed to util.
|
||||
foreach ($options as $option => $value) {
|
||||
if ($value) {
|
||||
$commandoptions .= " --$option=\"$value\"";
|
||||
}
|
||||
$commandoptions .= behat_get_command_flags($option, $value);
|
||||
}
|
||||
} else {
|
||||
// Only sanitize options for single run.
|
||||
@@ -130,9 +134,7 @@ if ($options['parallel'] && $options['parallel'] > 1) {
|
||||
];
|
||||
|
||||
foreach ($cmdoptionsforsinglerun as $option) {
|
||||
if (!empty($options[$option])) {
|
||||
$commandoptions .= " --$option='$options[$option]'";
|
||||
}
|
||||
$commandoptions .= behat_get_command_flags($option, $options[$option]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ Options:
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/behat/cli/run.php --tags=\"@javascript\"
|
||||
|
||||
More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
|
||||
More info in https://moodledev.io/general/development/tools/behat/running
|
||||
";
|
||||
|
||||
if (!empty($options['help'])) {
|
||||
|
||||
@@ -57,7 +57,7 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'torun' => 0,
|
||||
'optimize-runs' => '',
|
||||
'add-core-features-to-theme' => false,
|
||||
'axe' => false,
|
||||
'axe' => true,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
@@ -73,7 +73,7 @@ $help = "
|
||||
Behat utilities to manage the test environment
|
||||
|
||||
Usage:
|
||||
php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--axe|--help] [--parallel=value [--maxruns=value]]
|
||||
php util.php [--install|--drop|--enable|--disable|--diag|--updatesteps|--no-axe|--help] [--parallel=value [--maxruns=value]]
|
||||
|
||||
Options:
|
||||
--install Installs the test environment for acceptance tests
|
||||
@@ -82,7 +82,7 @@ Options:
|
||||
--disable Disables test environment
|
||||
--diag Get behat test environment status code
|
||||
--updatesteps Update feature step file.
|
||||
--axe Include axe accessibility tests
|
||||
--no-axe Disable axe accessibility tests.
|
||||
|
||||
-j, --parallel Number of parallel behat run operation
|
||||
-m, --maxruns Max parallel processes to be executed at one time.
|
||||
@@ -94,7 +94,7 @@ Options:
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/behat/cli/util.php --enable --parallel=4
|
||||
|
||||
More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
|
||||
More info in https://moodledev.io/general/development/tools/behat/running
|
||||
";
|
||||
|
||||
if (!empty($options['help'])) {
|
||||
@@ -320,12 +320,7 @@ function commands_to_execute($options) {
|
||||
}
|
||||
|
||||
foreach ($extraoptions as $option => $value) {
|
||||
if ($options[$option]) {
|
||||
$extra .= " --$option";
|
||||
if ($value) {
|
||||
$extra .= "=\"$value\"";
|
||||
}
|
||||
}
|
||||
$extra .= behat_get_command_flags($option, $value);
|
||||
}
|
||||
|
||||
if (empty($options['parallel'])) {
|
||||
|
||||
@@ -52,7 +52,7 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'updatesteps' => false,
|
||||
'optimize-runs' => '',
|
||||
'add-core-features-to-theme' => false,
|
||||
'axe' => false,
|
||||
'axe' => true,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
@@ -79,7 +79,7 @@ Options:
|
||||
--disable Disables test environment
|
||||
--diag Get behat test environment status code
|
||||
--updatesteps Update feature step file.
|
||||
--axe Include axe accessibility tests
|
||||
--no-axe Disable axe accessibility tests.
|
||||
|
||||
-o, --optimize-runs Split features with specified tags in all parallel runs.
|
||||
-a, --add-core-features-to-theme Add all core features to specified theme's
|
||||
@@ -89,7 +89,7 @@ Options:
|
||||
Example from Moodle root directory:
|
||||
\$ php admin/tool/behat/cli/util_single_run.php --enable
|
||||
|
||||
More info in http://docs.moodle.org/dev/Acceptance_testing#Running_tests
|
||||
More info in https://moodledev.io/general/development/tools/behat/running
|
||||
";
|
||||
|
||||
if (!empty($options['help'])) {
|
||||
@@ -186,7 +186,7 @@ if ($options['install']) {
|
||||
behat_config_manager::set_behat_run_config_value('behatsiteenabled', 1);
|
||||
}
|
||||
|
||||
// Define whether to run Behat with axe tests.
|
||||
// Configure axe according to option.
|
||||
behat_config_manager::set_behat_run_config_value('axe', $options['axe']);
|
||||
|
||||
// Enable test mode.
|
||||
|
||||
@@ -30,7 +30,7 @@ $string['errordataroot'] = '$CFG->behat_dataroot is not set or is invalid.';
|
||||
$string['errorsetconfig'] = '$CFG->behat_dataroot, $CFG->behat_prefix and $CFG->behat_wwwroot need to be set in config.php.';
|
||||
$string['erroruniqueconfig'] = '$CFG->behat_dataroot, $CFG->behat_prefix and $CFG->behat_wwwroot values need to be different than $CFG->dataroot, $CFG->prefix, $CFG->wwwroot, $CFG->phpunit_dataroot and $CFG->phpunit_prefix values.<br/>Or, if $CFG->behat_prefix is the same, $CFG->behat_dbname or $CFG->behat_dbhost need to be different from $CFG->phpunit_dbname and $CFG->phpunit_dbhost and from $CFG->dbname and $CFG->dbhost.';
|
||||
$string['fieldvalueargument'] = 'Field value arguments';
|
||||
$string['fieldvalueargument_help'] = 'This argument should be completed by a field value. There are many field types, including simple ones like checkboxes, selects or textareas, or complex ones like date selectors. See the dev documentation <a href="https://docs.moodle.org/dev/Acceptance_testing" target="_blank">Acceptance_testing</a> for details of expected field values.';
|
||||
$string['fieldvalueargument_help'] = 'This argument should be completed by a field value. There are many field types, including simple ones like checkboxes, selects or textareas, or complex ones like date selectors. See the dev documentation <a href="https://moodledev.io/general/development/tools/behat" target="_blank">Acceptance_testing</a> for details of expected field values.';
|
||||
$string['giveninfo'] = 'Given. Processes to set up the environment';
|
||||
$string['infoheading'] = 'Info';
|
||||
$string['installinfo'] = 'Read {$a} for installation and tests execution info';
|
||||
|
||||
@@ -184,9 +184,10 @@ class tool_behat_renderer extends plugin_renderer_base {
|
||||
// Info.
|
||||
$installurl = behat_command::DOCS_URL;
|
||||
$installlink = html_writer::tag('a', $installurl, array('href' => $installurl, 'target' => '_blank'));
|
||||
$writetestsurl = 'https://docs.moodle.org/dev/Writing acceptance tests';
|
||||
$writetestsurl = 'https://moodledev.io/general/development/tools/behat/writing';
|
||||
$writetestslink = html_writer::tag('a', $writetestsurl, array('href' => $writetestsurl, 'target' => '_blank'));
|
||||
$writestepsurl = 'https://docs.moodle.org/dev/Writing_new_acceptance_test_step_definitions';
|
||||
$writestepsurl = 'https://moodledev.io/general/development/tools/behat/writing#' .
|
||||
'writing-new-acceptance-test-step-definitions';
|
||||
$writestepslink = html_writer::tag('a', $writestepsurl, array('href' => $writestepsurl, 'target' => '_blank'));
|
||||
$infos = array(
|
||||
get_string('installinfo', 'tool_behat', $installlink),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
This files describes API changes in the tool_behat code.
|
||||
|
||||
=== 4.2.1 ===
|
||||
* Behat is initialised with Axe accessibility tests enabled by default, if you want to disable them please use the --no-axe option.
|
||||
=== 3.7 ===
|
||||
* Behat will now look for behat step definitions in the current
|
||||
theme and any parents the theme may have.
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2023042400; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2023042401; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
namespace tool_brickfield\local\tool;
|
||||
|
||||
use tool_brickfield\manager;
|
||||
|
||||
/**
|
||||
* Class advanced.
|
||||
*
|
||||
@@ -51,12 +53,36 @@ class advanced extends tool {
|
||||
return 'advanced';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds context data used to render a single grid item on the advanced page.
|
||||
* @param string $icon
|
||||
* @param string $heading
|
||||
* @param string $content
|
||||
* @return array
|
||||
*/
|
||||
protected function get_grid_item_context(string $icon, string $heading, string $content): array {
|
||||
return [
|
||||
"icon" => "pix/i/$icon.png",
|
||||
"iconalt" => get_string("icon:$icon", manager::PLUGINNAME),
|
||||
"heading" => get_string($heading, manager::PLUGINNAME),
|
||||
"content" => get_string($content, manager::PLUGINNAME)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data for renderer / template display.
|
||||
* @return \stdClass
|
||||
*/
|
||||
protected function fetch_data(): \stdClass {
|
||||
$data = (object)[
|
||||
'griditems' => [
|
||||
$this->get_grid_item_context("analytics-custom", "headingone", "contentone"),
|
||||
$this->get_grid_item_context("tools-custom", "headingtwo", "contenttwo"),
|
||||
$this->get_grid_item_context("file-edit-custom", "headingthree", "contentthree"),
|
||||
$this->get_grid_item_context("search-plus-custom", "headingfour", "contentfour"),
|
||||
$this->get_grid_item_context("wand-magic-custom", "headingfive", "contentfive"),
|
||||
$this->get_grid_item_context("hands-helping-custom", "headingsix", "contentsix"),
|
||||
],
|
||||
'valid' => true,
|
||||
'error' => '',
|
||||
];
|
||||
|
||||
@@ -270,3 +270,9 @@ $string['headingthree'] = 'Accessible file formats';
|
||||
$string['headingfour'] = 'Focus effort';
|
||||
$string['headingfive'] = 'HTML fixes';
|
||||
$string['headingsix'] = 'Performance support';
|
||||
$string['icon:analytics-custom'] = 'Analytics icon';
|
||||
$string['icon:tools-custom'] = 'Tools icon';
|
||||
$string['icon:file-edit-custom'] = 'Edit file icon';
|
||||
$string['icon:search-plus-custom'] = 'Search icon';
|
||||
$string['icon:wand-magic-custom'] = 'Magic wand icon';
|
||||
$string['icon:hands-helping-custom'] = 'Helping hands icon';
|
||||
|
||||
@@ -10,49 +10,22 @@
|
||||
|
||||
/* Advanced Page CSS */
|
||||
|
||||
@media only screen and (min-width: 768px) {
|
||||
.tool_brickfield_grid_item {
|
||||
width: 33.333333333333336%;
|
||||
}
|
||||
#tool_brickifeld_advanced_page {
|
||||
margin: 20px 20px 20px 10px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767px) {
|
||||
.tool_brickfield_grid_item {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.tool_brickfield_grid {
|
||||
max-width: 1140px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_inner {
|
||||
width: 100%;
|
||||
.tool_brickfield_banner_heading {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_item_shape {
|
||||
height: 96%;
|
||||
background-color: #fff;
|
||||
padding: 10% 10% 10% 10%;
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.05);
|
||||
margin: 1% 1% 1% 1%;
|
||||
border-radius: 15px 15px 15px 70px;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_display {
|
||||
display: grid;
|
||||
grid-template-columns: 0.6fr 1.4fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_spacing {
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
margin-left: auto;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.tool_brickfield_banner_heading > img {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.tool_brickfield_banner > p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_heading {
|
||||
@@ -60,59 +33,63 @@
|
||||
font-size: 20px;
|
||||
font-weight: 400;
|
||||
color: #040d29;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_content {
|
||||
color: #040d29;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tool_brickfield_logo_height {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.tool_brickfield_logo_position {
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
|
||||
.tool_brickfield_icon_position {
|
||||
line-height: 1;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
.tool_brickfield_icon_height {
|
||||
.tool_brickfield_grid_heading > img {
|
||||
height: 30px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.tool_brickfield_center_button {
|
||||
text-align: center;
|
||||
.tool_brickfield_grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin: 20px 20px 30px;
|
||||
}
|
||||
|
||||
.tool_brickfield_advanced_button {
|
||||
.tool_brickfield_grid > div {
|
||||
margin: 10px;
|
||||
padding: 20px;
|
||||
flex-basis: 30%;
|
||||
border: 1px solid grey;
|
||||
max-width: 500px;
|
||||
min-width: 250px;
|
||||
flex-grow: 4;
|
||||
border-radius: 15px 15px 15px 50px;
|
||||
}
|
||||
|
||||
.tool_brickfield_grid_heading {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tool_brickfield_footer > a {
|
||||
font-size: 18px;
|
||||
letter-spacing: 1px;
|
||||
color: #fff;
|
||||
background-color: #4054b2;
|
||||
border-style: solid;
|
||||
border-color: #fff;
|
||||
border-radius: 5px 5px 5px 5px;
|
||||
padding: 15px 50px 15px 50px;
|
||||
border-radius: 5px;
|
||||
padding: 15px 50px;
|
||||
transition: 0.3s;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tool_brickfield_advanced_button:hover {
|
||||
.tool_brickfield_footer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tool_brickfield_footer > a:hover {
|
||||
color: #fff;
|
||||
background-color: #253687;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.tool_brickfield_banner_heading {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.tool_brickfield_banner {
|
||||
height: 10em;
|
||||
padding: 2.5em;
|
||||
margin-bottom: 2em;
|
||||
.tool_brickfield_footer > p {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
@@ -21,184 +21,42 @@
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"pagetitle": "Advanced"
|
||||
"griditems": [
|
||||
{
|
||||
"icon": "some-icon-name",
|
||||
"iconalt": "some-icon-alt",
|
||||
"heading": "some-heading",
|
||||
"content": "some-content"
|
||||
}
|
||||
]
|
||||
}
|
||||
}}
|
||||
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<h3>{{{pagetitle}}}</h3>
|
||||
|
||||
<section class="tool_brickfield_banner">
|
||||
<div class="tool_brickfield_banner_heading">
|
||||
<img src="pix/i/Brickfield-logo-black.png" alt="Brickfield Logo" class="pull-right tool_brickfield_logo_height">
|
||||
<h2>{{# str }}bannerheadingone, tool_brickfield{{/ str }}</h2>
|
||||
<div id="tool_brickifeld_advanced_page">
|
||||
<div class="tool_brickfield_banner">
|
||||
<div class="tool_brickfield_banner_heading">
|
||||
<h2>{{#str}} bannerheadingone, tool_brickfield{{/str}}</h2>
|
||||
<img src="pix/i/Brickfield-logo-black.png" alt="Brickfield Logo">
|
||||
</div>
|
||||
<p>{{#str}} bannercontentone, tool_brickfield, https://www.brickfield.ie/moodle_talk_to_sales/{{/str}}</p>
|
||||
</div>
|
||||
<p>
|
||||
{{# str }}bannercontentone, tool_brickfield, https://www.brickfield.ie/moodle_talk_to_sales/{{/ str }}
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<div class="tool_brickfield_grid">
|
||||
<div class="tool_brickfield_grid_inner">
|
||||
|
||||
<div class="tool_brickfield_grid">
|
||||
{{#griditems}}
|
||||
<div class="tool_brickfield_grid_item">
|
||||
<div class="tool_brickfield_grid_item_shape">
|
||||
<div class="tool_brickfield_grid_display" style="grid-template-areas: 'al ar ar' 'al ar ar'; grid-area: a;">
|
||||
<div style="grid-area: al;">
|
||||
<div class="tool_brickfield_grid_spacing">
|
||||
<span class="tool_brickfield_icon_position">
|
||||
<img src="pix/i/analytics-custom.png" alt="Analytics icon" class="tool_brickfield_icon_height">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="grid-area: ar;">
|
||||
<h3>
|
||||
<span class="tool_brickfield_grid_heading">
|
||||
{{# str }}headingone, tool_brickfield{{/ str }}
|
||||
</span>
|
||||
</h3>
|
||||
<p class="tool_brickfield_grid_content">
|
||||
{{# str }}contentone, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool_brickfield_grid_heading">
|
||||
<img src="{{icon}}" alt="{{iconalt}}">
|
||||
<h3>{{heading}}</h3>
|
||||
</div>
|
||||
<div class="tool_brickfield_grid_content">
|
||||
<p>{{content}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tool_brickfield_grid_item">
|
||||
<div class="tool_brickfield_grid_item_shape">
|
||||
<div class="tool_brickfield_grid_display" style="grid-template-areas: 'bl br br' 'bl br br'; grid-area: b;">
|
||||
<div style="grid-area: bl;">
|
||||
<div class="tool_brickfield_grid_spacing">
|
||||
<span class="tool_brickfield_icon_position">
|
||||
<img src="pix/i/tools-custom.png" alt="Tools icon" class="tool_brickfield_icon_height">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="grid-area: br;">
|
||||
<h3>
|
||||
<span class="tool_brickfield_grid_heading">
|
||||
{{# str }}headingtwo, tool_brickfield{{/ str }}
|
||||
</span>
|
||||
</h3>
|
||||
<p class="tool_brickfield_grid_content">
|
||||
{{# str }}contenttwo, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tool_brickfield_grid_item">
|
||||
<div class="tool_brickfield_grid_item_shape">
|
||||
<div class="tool_brickfield_grid_display" style="grid-template-areas: 'cl cr cr' 'cl cr cr'; grid-area: c;">
|
||||
<div style="grid-area: cl;">
|
||||
<div class="tool_brickfield_grid_spacing">
|
||||
<span class="tool_brickfield_icon_position">
|
||||
<img src="pix/i/file-edit-custom.png" alt="Edit file icon" class="tool_brickfield_icon_height">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="grid-area: cr;">
|
||||
<h3>
|
||||
<span class="tool_brickfield_grid_heading">
|
||||
{{# str }}headingthree, tool_brickfield{{/ str }}
|
||||
</span>
|
||||
</h3>
|
||||
<p class="tool_brickfield_grid_content">
|
||||
{{# str }}contentthree, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tool_brickfield_grid_item">
|
||||
<div class="tool_brickfield_grid_item_shape">
|
||||
<div class="tool_brickfield_grid_display" style="grid-template-areas: 'dl dr dr' 'dl dr dr'; grid-area: d;">
|
||||
<div style="grid-area: dl;">
|
||||
<div class="tool_brickfield_grid_spacing">
|
||||
<span class="tool_brickfield_icon_position">
|
||||
<img src="pix/i/search-plus-custom.png" alt="Search icon" class="tool_brickfield_icon_height">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="grid-area: dr;">
|
||||
<h3>
|
||||
<span class="tool_brickfield_grid_heading">
|
||||
{{# str }}headingfour, tool_brickfield{{/ str }}
|
||||
</span>
|
||||
</h3>
|
||||
<p class="tool_brickfield_grid_content">
|
||||
{{# str }}contentfour, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tool_brickfield_grid_item">
|
||||
<div class="tool_brickfield_grid_item_shape">
|
||||
<div class="tool_brickfield_grid_display" style="grid-template-areas: 'el er er' 'el er er'; grid-area: e;">
|
||||
<div style="grid-area: el;">
|
||||
<div class="tool_brickfield_grid_spacing">
|
||||
<span class="tool_brickfield_icon_position">
|
||||
<img src="pix/i/wand-magic-custom.png" alt="Magic wand icon" class="tool_brickfield_icon_height">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="grid-area: er;">
|
||||
<h3>
|
||||
<span class="tool_brickfield_grid_heading">
|
||||
{{# str }}headingfive, tool_brickfield{{/ str }}
|
||||
</span>
|
||||
</h3>
|
||||
<p class="tool_brickfield_grid_content">
|
||||
{{# str }}contentfive, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tool_brickfield_grid_item">
|
||||
<div class="tool_brickfield_grid_item_shape">
|
||||
<div class="tool_brickfield_grid_display" style="grid-template-areas: 'fl fr fr' 'fl fr fr'; grid-area: f;">
|
||||
<div style="grid-area: fl;">
|
||||
<div class="tool_brickfield_grid_spacing">
|
||||
<span class="tool_brickfield_icon_position">
|
||||
<img src="pix/i/hands-helping-custom.png" alt="Helping hands icon" class="tool_brickfield_icon_height">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="grid-area: fr;">
|
||||
<h3>
|
||||
<span class="tool_brickfield_grid_heading">
|
||||
{{# str }}headingsix, tool_brickfield{{/ str }}
|
||||
</span>
|
||||
</h3>
|
||||
<p class="tool_brickfield_grid_content">
|
||||
{{# str }}contentsix, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{/griditems}}
|
||||
</div>
|
||||
<div class="tool_brickfield_footer">
|
||||
<h2 class="accesshide">{{#str}} footerheading, tool_brickfield {{/str}}</h2>
|
||||
<p>{{#str}}bannercontenttwo, tool_brickfield{{/str}}</p>
|
||||
<a href="https://www.brickfield.ie/moodle_free_demo/">
|
||||
{{#str}}buttonone, tool_brickfield{{/str}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="tool_brickfield_banner">
|
||||
<h2 class="accesshide">{{# str }}footerheading, tool_brickfield{{/ str }}</h2>
|
||||
<p>
|
||||
{{# str }}bannercontenttwo, tool_brickfield{{/ str }}
|
||||
</p>
|
||||
<div class="tool_brickfield_center_button">
|
||||
<form action="https://www.brickfield.ie/moodle_free_demo/">
|
||||
<button class="tool_brickfield_advanced_button">
|
||||
{{# str }}buttonone, tool_brickfield{{/ str }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@@ -179,6 +179,7 @@ class api {
|
||||
AND ra.roleid = :roleid
|
||||
AND ra.userid = :userid
|
||||
WHERE cm.cohortid ' . $cohortsql . '
|
||||
AND u.deleted = 0
|
||||
AND ra.id IS NULL';
|
||||
|
||||
$toadd = $DB->get_records_sql($sql, $params);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace tool_cohortroles;
|
||||
|
||||
use core\event\user_deleted;
|
||||
|
||||
/**
|
||||
* Plugin event observer callbacks
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class observers {
|
||||
|
||||
/**
|
||||
* User deleted event, remove cohort role assignments specific to them
|
||||
*
|
||||
* @param user_deleted $event
|
||||
*/
|
||||
public static function user_deleted(user_deleted $event): void {
|
||||
$cohortroleassignments = cohort_role_assignment::get_records(['userid' => $event->objectid]);
|
||||
foreach ($cohortroleassignments as $cohortroleassignment) {
|
||||
$cohortroleassignment->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Plugin event observers
|
||||
*
|
||||
* @package tool_cohortroles
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$observers = [
|
||||
[
|
||||
'eventname' => '\core\event\user_deleted',
|
||||
'callback' => '\tool_cohortroles\observers::user_deleted',
|
||||
],
|
||||
];
|
||||
@@ -50,5 +50,16 @@ function xmldb_tool_cohortroles_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2023042401) {
|
||||
// Delete any tool_cohortroles mappings for users who no longer exist.
|
||||
$DB->delete_records_select('tool_cohortroles', 'userid NOT IN (SELECT id FROM {user} WHERE deleted = 0)');
|
||||
|
||||
// Cohortroles savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2023042401, 'tool', 'cohortroles');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$plugin->version = 2023042400; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2023042401; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2023041800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -11,7 +11,7 @@ tags:
|
||||
|
||||
## Description
|
||||
|
||||
Most Moodle icons are rendered using the 6.3 versions of [Fontawesome](https://fontawesome.com/v6/search). Iconnames are mapped from the Moodle icon name to the Font Awesome icon names in `/lib/classes/output/icon_system_fontawesome.php`
|
||||
Most Moodle icons are rendered using the 6.4 versions of [Fontawesome](https://fontawesome.com/v6/search). Iconnames are mapped from the Moodle icon name to the Font Awesome icon names in `/lib/classes/output/icon_system_fontawesome.php`
|
||||
|
||||
If needed a theme can override this map and provide its own mapping.
|
||||
|
||||
|
||||
@@ -38,5 +38,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -87,5 +87,8 @@ function xmldb_tool_dataprivacy_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
namespace tool_langimport;
|
||||
|
||||
use moodle_url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
@@ -59,6 +61,25 @@ class controller {
|
||||
$this->availablelangs = $this->installer->get_remote_list_of_languages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the specified url, outputting any required messages.
|
||||
*
|
||||
* @param moodle_url $url
|
||||
*/
|
||||
public function redirect(moodle_url $url): void {
|
||||
if ($this->info) {
|
||||
$info = implode('<br />', $this->info);
|
||||
\core\notification::success($info);
|
||||
}
|
||||
|
||||
if ($this->errors) {
|
||||
$info = implode('<br />', $this->errors);
|
||||
\core\notification::error($info);
|
||||
}
|
||||
|
||||
redirect($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install language packs provided
|
||||
*
|
||||
@@ -112,6 +133,18 @@ class controller {
|
||||
public function uninstall_language($lang) {
|
||||
global $CFG;
|
||||
|
||||
$lang = clean_param($lang, PARAM_LANG);
|
||||
if ($lang === '') {
|
||||
// Do not allow uninstallation of invalid languages.
|
||||
// Note: PARAM_LANG returns an empty string for invalid validation.
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($lang === 'en') {
|
||||
// Never allow removal of the default langauge.
|
||||
return false;
|
||||
}
|
||||
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$lang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$lang;
|
||||
$rm1 = false;
|
||||
|
||||
@@ -43,6 +43,13 @@ $uninstalllang = optional_param_array('uninstalllang', array(), PARAM_LANG)
|
||||
$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_SAFEPATH); // uninstallation confirmation
|
||||
$purgecaches = optional_param('purgecaches', false, PARAM_BOOL); // explicit caches reset
|
||||
|
||||
// Filter the uninstall language list.
|
||||
// If the list contains a language which is not installed, it is replaced with an empty string.
|
||||
// When we try to uninstall an empty string, we uninstall every language.
|
||||
$uninstalllang = array_filter($uninstalllang, function($lang) {
|
||||
return !empty($lang);
|
||||
});
|
||||
|
||||
if ($purgecaches) {
|
||||
require_sesskey();
|
||||
get_string_manager()->reset_caches();
|
||||
@@ -69,11 +76,12 @@ if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($p
|
||||
if (is_array($pack) && count($pack) > 1) {
|
||||
// Installing multiple languages can take a while - perform it asynchronously in the background.
|
||||
$controller->schedule_languagepacks_installation($pack);
|
||||
|
||||
$controller->redirect($PAGE->url);
|
||||
} else {
|
||||
// Single language pack to be installed synchronously. It should be reasonably quick and can be used for debugging, too.
|
||||
core_php_time_limit::raise();
|
||||
$controller->install_languagepacks($pack);
|
||||
$controller->redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +110,7 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
|
||||
foreach ($uninstalllang as $ulang) {
|
||||
$controller->uninstall_language($ulang);
|
||||
}
|
||||
|
||||
$controller->redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<?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/>.
|
||||
|
||||
namespace tool_langimport;
|
||||
|
||||
/**
|
||||
* Tests for \tool_langimport\locale class.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @coversDefaultClass \tool_langimport\controller
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class controller_test extends \advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test uninstall of language with invalid values.
|
||||
*
|
||||
* @covers ::uninstall_lang
|
||||
* @dataProvider uninstall_lang_invalid_provider
|
||||
* @params string $lang
|
||||
*/
|
||||
public function test_uninstall_lang_invalid(string $lang): void {
|
||||
global $CFG;
|
||||
|
||||
$controller = new controller();
|
||||
$this->assertFalse($controller->uninstall_language($lang));
|
||||
$this->assertFileExists("{$CFG->dataroot}/lang");
|
||||
$this->assertFileExists("{$CFG->dirroot}/lang/en");
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for uninstall_lang tests with invalid values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function uninstall_lang_invalid_provider(): array {
|
||||
return [
|
||||
'Empty string' => [''],
|
||||
'Meaningless empty string' => [' '],
|
||||
'Default language' => ['en'],
|
||||
'Invalid language string' => ['swedish'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -14,19 +14,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* License manager helper class.
|
||||
*
|
||||
* @package tool_licensemanager
|
||||
* @copyright 2019 Tom Dickman <tomdickman@catalyst-au.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_licensemanager;
|
||||
|
||||
use moodle_url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* License manager helper class.
|
||||
@@ -48,12 +40,7 @@ class helper {
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public static function get_licensemanager_url() : moodle_url {
|
||||
global $CFG;
|
||||
|
||||
$url = new moodle_url($CFG->wwwroot . self::MANAGER_PATH,
|
||||
['sesskey' => sesskey()]);
|
||||
|
||||
return $url;
|
||||
return new moodle_url(self::MANAGER_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,9 +77,8 @@ class helper {
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public static function get_create_license_url() : moodle_url {
|
||||
$url = new moodle_url(self::MANAGER_PATH,
|
||||
['action' => manager::ACTION_CREATE, 'sesskey' => sesskey()]);
|
||||
|
||||
$url = self::get_licensemanager_url();
|
||||
$url->params(['action' => manager::ACTION_CREATE]);
|
||||
return $url;
|
||||
}
|
||||
|
||||
@@ -104,9 +90,8 @@ class helper {
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public static function get_update_license_url(string $licenseshortname) : moodle_url {
|
||||
$url = new moodle_url(self::MANAGER_PATH,
|
||||
['action' => manager::ACTION_UPDATE, 'license' => $licenseshortname, 'sesskey' => sesskey()]);
|
||||
|
||||
$url = self::get_licensemanager_url();
|
||||
$url->params(['action' => manager::ACTION_UPDATE, 'license' => $licenseshortname]);
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,22 +14,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* License manager.
|
||||
*
|
||||
* @package tool_licensemanager
|
||||
* @copyright 2019 Tom Dickman <tomdickman@catalyst-au.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_licensemanager;
|
||||
|
||||
use tool_licensemanager\form\edit_license;
|
||||
use license_manager;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* License manager, main controller for tool_licensemanager.
|
||||
*
|
||||
@@ -96,22 +86,29 @@ class manager {
|
||||
|
||||
$viewmanager = true;
|
||||
$message = null;
|
||||
$redirect = helper::get_licensemanager_url();
|
||||
|
||||
switch ($action) {
|
||||
case self::ACTION_DISABLE:
|
||||
require_sesskey();
|
||||
license_manager::disable($license);
|
||||
redirect($redirect);
|
||||
break;
|
||||
|
||||
case self::ACTION_ENABLE:
|
||||
require_sesskey();
|
||||
license_manager::enable($license);
|
||||
redirect($redirect);
|
||||
break;
|
||||
|
||||
case self::ACTION_DELETE:
|
||||
require_sesskey();
|
||||
try {
|
||||
license_manager::delete($license);
|
||||
} catch (\moodle_exception $e) {
|
||||
$message = $e->getMessage();
|
||||
}
|
||||
|
||||
redirect($redirect, $message);
|
||||
break;
|
||||
|
||||
case self::ACTION_CREATE:
|
||||
@@ -121,7 +118,9 @@ class manager {
|
||||
|
||||
case self::ACTION_MOVE_UP:
|
||||
case self::ACTION_MOVE_DOWN:
|
||||
require_sesskey();
|
||||
$this->change_license_order($action, $license);
|
||||
redirect($redirect);
|
||||
break;
|
||||
|
||||
case self::ACTION_VIEW_LICENSE_MANAGER:
|
||||
|
||||
@@ -28,15 +28,9 @@ require_once($CFG->libdir . '/licenselib.php');
|
||||
|
||||
require_admin();
|
||||
|
||||
$returnurl = \tool_licensemanager\helper::get_licensemanager_url();
|
||||
|
||||
$action = optional_param('action', '', PARAM_ALPHANUMEXT);
|
||||
$license = optional_param('license', '', PARAM_SAFEDIR);
|
||||
|
||||
if (!confirm_sesskey()) {
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
// Route via the manager.
|
||||
$licensemanager = new \tool_licensemanager\manager();
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_tool_log_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,5 +36,8 @@ function xmldb_logstore_database_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,5 +63,8 @@ function xmldb_logstore_standard_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -128,3 +128,18 @@ Feature: Manage competency frameworks
|
||||
Then I should see "Competency framework updated"
|
||||
And I should see "Science Year-6 Edited"
|
||||
And I should see "sc-y-6"
|
||||
|
||||
Scenario: Duplicate a competency framework
|
||||
Given the following lp "frameworks" exist:
|
||||
| shortname | idnumber |
|
||||
| CF1 | CF1 |
|
||||
And the following lp "competencies" exist:
|
||||
| shortname | framework |
|
||||
| C1 | CF1 |
|
||||
And I navigate to "Competencies > Competency frameworks" in site administration
|
||||
# Duplicate the selected competency framework
|
||||
When I click on "Duplicate" of edit menu in the "CF1" row
|
||||
# Confirm that the selected framework was duplicated by clicking on the link
|
||||
And I click on "CF1 (copy) (CF1_1)" "link"
|
||||
# Confirm that the corresponding competency also exists in the duplicated framework
|
||||
Then I should see "C1"
|
||||
|
||||
@@ -44,5 +44,8 @@ function xmldb_tool_mobile_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -14,17 +14,11 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Event documentation
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
use core_component;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* Class for returning event information.
|
||||
@@ -35,126 +29,6 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class eventlist {
|
||||
/**
|
||||
* Return all of the core event files.
|
||||
*
|
||||
* @return array Core events.
|
||||
*/
|
||||
protected static function get_core_eventlist() {
|
||||
global $CFG;
|
||||
|
||||
// Disable developer debugging as deprecated events will fire warnings.
|
||||
// Setup backup variables to restore the following settings back to what they were when we are finished.
|
||||
$debuglevel = $CFG->debug;
|
||||
$debugdisplay = $CFG->debugdisplay;
|
||||
$debugdeveloper = $CFG->debugdeveloper;
|
||||
$CFG->debug = 0;
|
||||
$CFG->debugdisplay = false;
|
||||
$CFG->debugdeveloper = false;
|
||||
|
||||
$eventinformation = array();
|
||||
$directory = $CFG->libdir . '/classes/event';
|
||||
$files = self::get_file_list($directory);
|
||||
|
||||
// Remove exceptional events that will cause problems being displayed.
|
||||
if (isset($files['unknown_logged'])) {
|
||||
unset($files['unknown_logged']);
|
||||
}
|
||||
foreach ($files as $file => $location) {
|
||||
$classname = '\\core\\event\\' . $file;
|
||||
// Check to see if this is actually a valid event.
|
||||
if (method_exists($classname, 'get_static_info')) {
|
||||
$ref = new \ReflectionClass($classname);
|
||||
// Ignore abstracts.
|
||||
if (!$ref->isAbstract() && $file != 'manager') {
|
||||
$eventinformation[$classname] = $classname::get_name_with_info();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now enable developer debugging as event information has been retrieved.
|
||||
$CFG->debug = $debuglevel;
|
||||
$CFG->debugdisplay = $debugdisplay;
|
||||
$CFG->debugdeveloper = $debugdeveloper;
|
||||
return $eventinformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns an array of all events for the plugins of the system.
|
||||
*
|
||||
* @param bool $withoutcomponent Return an eventlist without associated components.
|
||||
*
|
||||
* @return array A list of events from all plug-ins.
|
||||
*/
|
||||
protected static function get_non_core_eventlist($withoutcomponent = false) {
|
||||
global $CFG;
|
||||
// Disable developer debugging as deprecated events will fire warnings.
|
||||
// Setup backup variables to restore the following settings back to what they were when we are finished.
|
||||
$debuglevel = $CFG->debug;
|
||||
$debugdisplay = $CFG->debugdisplay;
|
||||
$debugdeveloper = $CFG->debugdeveloper;
|
||||
$CFG->debug = 0;
|
||||
$CFG->debugdisplay = false;
|
||||
$CFG->debugdeveloper = false;
|
||||
|
||||
$noncorepluginlist = array();
|
||||
$plugintypes = \core_component::get_plugin_types();
|
||||
foreach ($plugintypes as $plugintype => $notused) {
|
||||
$pluginlist = \core_component::get_plugin_list($plugintype);
|
||||
foreach ($pluginlist as $plugin => $directory) {
|
||||
$plugindirectory = $directory . '/classes/event';
|
||||
foreach (self::get_file_list($plugindirectory) as $eventname => $notused) {
|
||||
$fullpluginname = $plugintype . '_' . $plugin;
|
||||
$plugineventname = '\\' . $fullpluginname . '\\event\\' . $eventname;
|
||||
// Check that this is actually an event.
|
||||
if (method_exists($plugineventname, 'get_static_info') && $fullpluginname !== 'tool_monitor') { // No selfie here.
|
||||
$ref = new \ReflectionClass($plugineventname);
|
||||
if (!$ref->isAbstract() && $fullpluginname !== 'logstore_legacy') {
|
||||
if ($withoutcomponent) {
|
||||
$noncorepluginlist[$plugineventname] = $plugineventname::get_name_with_info();
|
||||
} else {
|
||||
$noncorepluginlist[$fullpluginname][$plugineventname] = $plugineventname::get_name_with_info();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now enable developer debugging as event information has been retrieved.
|
||||
$CFG->debug = $debuglevel;
|
||||
$CFG->debugdisplay = $debugdisplay;
|
||||
$CFG->debugdeveloper = $debugdeveloper;
|
||||
|
||||
return $noncorepluginlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of files with a full directory path in a specified directory.
|
||||
*
|
||||
* @param string $directory location of files.
|
||||
* @return array full location of files from the specified directory.
|
||||
*/
|
||||
protected static function get_file_list($directory) {
|
||||
global $CFG;
|
||||
$directoryroot = $CFG->dirroot;
|
||||
$finalfiles = array();
|
||||
if (is_dir($directory)) {
|
||||
if ($handle = opendir($directory)) {
|
||||
$files = scandir($directory);
|
||||
foreach ($files as $file) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
// Ignore the file if it is external to the system.
|
||||
if (strrpos($directory, $directoryroot) !== false) {
|
||||
$location = substr($directory, strlen($directoryroot));
|
||||
$name = substr($file, 0, -4);
|
||||
$finalfiles[$name] = $location . '/' . $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $finalfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of events present in the system.
|
||||
@@ -164,13 +38,58 @@ class eventlist {
|
||||
* @return array list of events present in the system.
|
||||
*/
|
||||
public static function get_all_eventlist($withoutcomponent = false) {
|
||||
if ($withoutcomponent) {
|
||||
$return = array_merge(self::get_core_eventlist(), self::get_non_core_eventlist($withoutcomponent));
|
||||
array_multisort($return, SORT_NATURAL);
|
||||
} else {
|
||||
$return = array_merge(array('core' => self::get_core_eventlist()),
|
||||
self::get_non_core_eventlist($withoutcomponent = false));
|
||||
global $CFG;
|
||||
|
||||
// Disable developer debugging as deprecated events will fire warnings.
|
||||
// Setup backup variables to restore the following settings back to what they were when we are finished.
|
||||
$debuglevel = $CFG->debug;
|
||||
$debugdisplay = $CFG->debugdisplay;
|
||||
$debugdeveloper = $CFG->debugdeveloper;
|
||||
$CFG->debug = 0;
|
||||
$CFG->debugdisplay = false;
|
||||
$CFG->debugdeveloper = false;
|
||||
|
||||
// List of exceptional events that will cause problems if displayed.
|
||||
$eventsignore = [
|
||||
\core\event\unknown_logged::class,
|
||||
\logstore_legacy\event\legacy_logged::class,
|
||||
];
|
||||
|
||||
$return = [];
|
||||
|
||||
$events = core_component::get_component_classes_in_namespace(null, 'event');
|
||||
foreach (array_keys($events) as $event) {
|
||||
// We need to filter all classes that extend event base, or the base class itself.
|
||||
if (is_a($event, \core\event\base::class, true) && !in_array($event, $eventsignore)) {
|
||||
|
||||
$reflectionclass = new ReflectionClass($event);
|
||||
if ($reflectionclass->isAbstract()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We can't choose this component's own events.
|
||||
[$component] = explode('\\', $event);
|
||||
if ($component === 'tool_monitor') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($withoutcomponent) {
|
||||
$return["\\{$event}"] = $event::get_name_with_info();
|
||||
} else {
|
||||
$return[$component]["\\{$event}"] = $event::get_name_with_info();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now enable developer debugging as event information has been retrieved.
|
||||
$CFG->debug = $debuglevel;
|
||||
$CFG->debugdisplay = $debugdisplay;
|
||||
$CFG->debugdeveloper = $debugdeveloper;
|
||||
|
||||
if ($withoutcomponent) {
|
||||
array_multisort($return, SORT_NATURAL);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,5 +72,8 @@ function xmldb_tool_monitor_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -152,5 +152,8 @@ function xmldb_tool_moodlenet_upgrade(int $oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -151,25 +151,25 @@ Feature: Basic OAuth2 functionality
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
When I press "Save changes"
|
||||
Then I should see "Changes saved"
|
||||
And I should see "Open Badges"
|
||||
And "Allow services" "icon" should exist in the "Open Badges" "table_row"
|
||||
And "Do not allow login" "icon" should exist in the "Open Badges" "table_row"
|
||||
And "Service discovery successful" "icon" should exist in the "Open Badges" "table_row"
|
||||
And the "src" attribute of "table.admintable th img" "css_element" should contain "IMS-Global-Logo.png"
|
||||
And I click on "Configure endpoints" "link" in the "Open Badges" "table_row"
|
||||
And I should see "https://dc.imsglobal.org/.well-known/badgeconnect.json" in the "discovery_endpoint" "table_row"
|
||||
And I should see "authorization_endpoint"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And I click on "Configure user field mappings" "link" in the "Open Badges" "table_row"
|
||||
And I should not see "given_name"
|
||||
And I should not see "middle_name"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And I click on "Edit" "link" in the "Open Badges" "table_row"
|
||||
And I should see "IMS Global Reference Implementation"
|
||||
And I click on "Edit" "link" in the "IMS Global Reference Implementation" "table_row"
|
||||
And I set the following fields to these values:
|
||||
| Name | IMS Global |
|
||||
And I press "Save changes"
|
||||
And I should see "Changes saved"
|
||||
And I should see "IMS Global"
|
||||
And "Allow services" "icon" should exist in the "IMS Global" "table_row"
|
||||
And "Do not allow login" "icon" should exist in the "IMS Global" "table_row"
|
||||
And "Service discovery successful" "icon" should exist in the "IMS Global" "table_row"
|
||||
And the "src" attribute of "table.admintable th img" "css_element" should contain "IMS-Global-Logo.png"
|
||||
And I click on "Configure endpoints" "link" in the "IMS Global" "table_row"
|
||||
And I should see "https://dc.imsglobal.org/.well-known/badgeconnect.json" in the "discovery_endpoint" "table_row"
|
||||
And I should see "authorization_endpoint"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And I click on "Configure user field mappings" "link" in the "IMS Global" "table_row"
|
||||
And I should not see "given_name"
|
||||
And I should not see "middle_name"
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And I click on "Delete" "link" in the "IMS Global" "table_row"
|
||||
And I should see "Are you sure you want to delete the identity issuer \"IMS Global\"?"
|
||||
And I press "Continue"
|
||||
|
||||
@@ -573,7 +573,7 @@ class acceptances_table extends \table_sql {
|
||||
if ($row->timemodified) {
|
||||
if ($this->is_downloading()) {
|
||||
// Use timestamp format readable for both machines and humans.
|
||||
return date_format_string($row->timemodified, '%Y-%m-%d %H:%M:%S %Z');
|
||||
return date_format_string((int) $row->timemodified, '%Y-%m-%d %H:%M:%S %Z');
|
||||
} else {
|
||||
// Use localised calendar format.
|
||||
return userdate($row->timemodified, get_string('strftimedatetime'));
|
||||
|
||||
@@ -43,5 +43,8 @@ function xmldb_tool_policy_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -135,5 +135,8 @@ function xmldb_tool_usertours_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,6 @@ foreach ($filterdata->services as $i => $serviceid) {
|
||||
$table->define_baseurl($baseurl);
|
||||
|
||||
$table->attributes['class'] = 'admintable generaltable';
|
||||
$table->data = [];
|
||||
$table->out(30, false);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -29,6 +29,7 @@ require_once(__DIR__ . '/fixtures/test_target_course_level_shortname.php');
|
||||
* @package core_analytics
|
||||
* @copyright 2017 David Monllaó {@link http://www.davidmonllao.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \core_analytics\manager
|
||||
*/
|
||||
class manager_test extends \advanced_testcase {
|
||||
|
||||
@@ -491,25 +492,63 @@ class manager_test extends \advanced_testcase {
|
||||
// No potential context restrictions.
|
||||
$this->assertFalse(\core_analytics\manager::get_potential_context_restrictions([]));
|
||||
|
||||
$defaultcategory = \core_course_category::get_default();
|
||||
$defaultcategorycontext = $defaultcategory->get_context();
|
||||
|
||||
// Include the all context levels so the misc. category get included.
|
||||
$this->assertCount(1, \core_analytics\manager::get_potential_context_restrictions());
|
||||
$this->assertEquals([
|
||||
$defaultcategorycontext->id => "Category: {$defaultcategory->name}",
|
||||
], manager::get_potential_context_restrictions());
|
||||
|
||||
$this->getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->create_category();
|
||||
$this->assertCount(3, \core_analytics\manager::get_potential_context_restrictions());
|
||||
$this->assertCount(3, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSE, CONTEXT_COURSECAT]));
|
||||
$category = $this->getDataGenerator()->create_category(['name' => 'My category']);
|
||||
$categorycontext = $category->get_context();
|
||||
|
||||
$this->assertCount(1, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSE]));
|
||||
$this->assertCount(2, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSECAT]));
|
||||
$courseone = $this->getDataGenerator()->create_course(['fullname' => 'Course one', 'shortname' => 'CS1']);
|
||||
$courseonecontext = \context_course::instance($courseone->id);
|
||||
|
||||
$this->assertCount(1, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'Course category'));
|
||||
$this->assertCount(1, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'Course category 1'));
|
||||
$this->assertCount(
|
||||
2,
|
||||
\core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSECAT],
|
||||
get_string('defaultcategoryname')
|
||||
));
|
||||
$this->assertCount(1, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSE], 'Test course 1'));
|
||||
$this->assertCount(1, \core_analytics\manager::get_potential_context_restrictions([CONTEXT_COURSE], 'Test course'));
|
||||
$coursetwo = $this->getDataGenerator()->create_course(['fullname' => 'Course two', 'shortname' => 'CS2']);
|
||||
$coursetwocontext = \context_course::instance($coursetwo->id);
|
||||
|
||||
// All context levels.
|
||||
$this->assertEqualsCanonicalizing([
|
||||
$defaultcategorycontext->id => "Category: {$defaultcategory->name}",
|
||||
$categorycontext->id => "Category: {$category->name}",
|
||||
$courseonecontext->id => "Course: {$courseone->shortname}",
|
||||
$coursetwocontext->id => "Course: {$coursetwo->shortname}",
|
||||
], manager::get_potential_context_restrictions());
|
||||
|
||||
// All category/course context levels.
|
||||
$this->assertEqualsCanonicalizing([
|
||||
$defaultcategorycontext->id => "Category: {$defaultcategory->name}",
|
||||
$categorycontext->id => "Category: {$category->name}",
|
||||
$courseonecontext->id => "Course: {$courseone->shortname}",
|
||||
$coursetwocontext->id => "Course: {$coursetwo->shortname}",
|
||||
], manager::get_potential_context_restrictions([CONTEXT_COURSECAT, CONTEXT_COURSE]));
|
||||
|
||||
// All category context levels.
|
||||
$this->assertEqualsCanonicalizing([
|
||||
$defaultcategorycontext->id => "Category: {$defaultcategory->name}",
|
||||
$categorycontext->id => "Category: {$category->name}",
|
||||
], manager::get_potential_context_restrictions([CONTEXT_COURSECAT]));
|
||||
|
||||
// Filtered category context levels.
|
||||
$this->assertEquals([
|
||||
$categorycontext->id => "Category: {$category->name}",
|
||||
], manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'My cat'));
|
||||
|
||||
$this->assertEmpty(manager::get_potential_context_restrictions([CONTEXT_COURSECAT], 'nothing'));
|
||||
|
||||
// All course context levels.
|
||||
$this->assertEqualsCanonicalizing([
|
||||
$courseonecontext->id => "Course: {$courseone->shortname}",
|
||||
$coursetwocontext->id => "Course: {$coursetwo->shortname}",
|
||||
], manager::get_potential_context_restrictions([CONTEXT_COURSE]));
|
||||
|
||||
// Filtered course context levels.
|
||||
$this->assertEquals([
|
||||
$courseonecontext->id => "Course: {$courseone->shortname}",
|
||||
], manager::get_potential_context_restrictions([CONTEXT_COURSE], 'one'));
|
||||
|
||||
$this->assertEmpty(manager::get_potential_context_restrictions([CONTEXT_COURSE], 'nothing'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,5 +49,8 @@ function xmldb_auth_cas_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_auth_db_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_auth_email_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+6
@@ -45,6 +45,12 @@ require_once($CFG->dirroot . '/webservice/tests/helpers.php');
|
||||
*/
|
||||
class external_test extends externallib_advanced_testcase {
|
||||
|
||||
/** @var int custom profile field1 ID. */
|
||||
protected $field1;
|
||||
|
||||
/** @var int custom profile field2 ID. */
|
||||
protected $field2;
|
||||
|
||||
/**
|
||||
* Set up for every test
|
||||
*/
|
||||
|
||||
@@ -86,6 +86,18 @@ require_once($CFG->dirroot.'/auth/ldap/locallib.php');
|
||||
*/
|
||||
class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
/** @var string */
|
||||
protected $roleauth;
|
||||
|
||||
/** @var string */
|
||||
public $pluginconfig;
|
||||
|
||||
/** @var LDAP\Connection LDAP connection. */
|
||||
protected $ldapconnection;
|
||||
|
||||
/** @var int */
|
||||
protected $ldapconns = 0;
|
||||
|
||||
/**
|
||||
* Init plugin config from database settings depending on the plugin auth type.
|
||||
*/
|
||||
|
||||
@@ -49,5 +49,8 @@ function xmldb_auth_ldap_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+5
-2
@@ -199,7 +199,6 @@ class auth_plugin_lti extends \auth_plugin_base {
|
||||
}
|
||||
}
|
||||
$user = $this->create_new_account($member, $iss);
|
||||
$this->update_user_account($user, $member, $iss);
|
||||
return \core_user::get_user($user->id);
|
||||
}
|
||||
}
|
||||
@@ -381,7 +380,11 @@ class auth_plugin_lti extends \auth_plugin_base {
|
||||
'lastname' => $userdata['family_name'] ?? $iss,
|
||||
'email' => $email
|
||||
];
|
||||
user_update_user($update);
|
||||
$userfieldstocompare = array_intersect_key((array) $user, $update);
|
||||
|
||||
if (!empty(array_diff($update, $userfieldstocompare))) {
|
||||
user_update_user($update); // Only update if there's a change.
|
||||
}
|
||||
|
||||
if (!empty($userdata['picture'])) {
|
||||
try {
|
||||
|
||||
@@ -91,5 +91,8 @@ function xmldb_auth_lti_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -249,12 +249,15 @@ class auth_test extends \advanced_testcase {
|
||||
$mockjwtdata = $this->get_mock_launchdata_for_user($launchdata['user'], $launchdata['migration_claim'] ?? []);
|
||||
|
||||
// Authenticate the platform user.
|
||||
$sink = $this->redirectEvents();
|
||||
$countusersbefore = $DB->count_records('user');
|
||||
$user = $auth->find_or_create_user_from_launch($mockjwtdata, true, $legacysecrets);
|
||||
if (!empty($expected['migration_debugging'])) {
|
||||
$this->assertDebuggingCalled();
|
||||
}
|
||||
$countusersafter = $DB->count_records('user');
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Verify user count is correct. i.e. no user is created when migration claim is correctly processed or when
|
||||
// the user has authenticated with the tool before.
|
||||
@@ -295,15 +298,18 @@ class auth_test extends \advanced_testcase {
|
||||
$this->verify_user_profile_image_updated($user->id);
|
||||
}
|
||||
|
||||
// If migrated, verify the user account is reusing the legacy user account.
|
||||
if (!empty($expected['migrated']) && $expected['migrated']) {
|
||||
// If migrated, verify the user account is reusing the legacy user account.
|
||||
$legacyuserids = array_column($legacyusers, 'id');
|
||||
$this->assertContains($user->id, $legacyuserids);
|
||||
}
|
||||
|
||||
// If the user is authenticating a second time, confirm the same account is being returned.
|
||||
if (isset($firstauthuser)) {
|
||||
$this->assertInstanceOf(\core\event\user_updated::class, $events[0]);
|
||||
} else if (isset($firstauthuser)) {
|
||||
// If the user is authenticating a second time, confirm the same account is being returned.
|
||||
$this->assertEquals($firstauthuser->id, $user->id);
|
||||
$this->assertEmpty($events); // The user authenticated with the same data once before, so we don't expect an update.
|
||||
} else {
|
||||
// The user wasn't migrated and hasn't launched before, so we expect a user_created event.
|
||||
$this->assertInstanceOf(\core\event\user_created::class, $events[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -819,9 +825,12 @@ class auth_test extends \advanced_testcase {
|
||||
$mockmemberdata = $this->get_mock_member_data_for_user($memberdata['user'], $memberdata['legacy_user_id'] ?? '');
|
||||
|
||||
// Authenticate the platform user.
|
||||
$sink = $this->redirectEvents();
|
||||
$countusersbefore = $DB->count_records('user');
|
||||
$user = $auth->find_or_create_user_from_membership($mockmemberdata, $iss, $legacyconsumerkey ?? '');
|
||||
$countusersafter = $DB->count_records('user');
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Verify user count is correct. i.e. no user is created when migration claim is correctly processed or when
|
||||
// the user has authenticated with the tool before.
|
||||
@@ -857,15 +866,18 @@ class auth_test extends \advanced_testcase {
|
||||
break;
|
||||
}
|
||||
|
||||
// If migrated, verify the user account is reusing the legacy user account.
|
||||
if (!empty($expected['migrated']) && $expected['migrated']) {
|
||||
// If migrated, verify the user account is reusing the legacy user account.
|
||||
$legacyuserids = array_column($legacyusers, 'id');
|
||||
$this->assertContains($user->id, $legacyuserids);
|
||||
}
|
||||
|
||||
// If the user is authenticating a second time, confirm the same account is being returned.
|
||||
if (isset($firstauthuser)) {
|
||||
$this->assertInstanceOf(\core\event\user_updated::class, $events[0]);
|
||||
} else if (isset($firstauthuser)) {
|
||||
// If the user is authenticating a second time, confirm the same account is being returned.
|
||||
$this->assertEquals($firstauthuser->id, $user->id);
|
||||
$this->assertEmpty($events); // The user authenticated with the same data once before, so we don't expect an update.
|
||||
} else {
|
||||
// The user wasn't migrated and hasn't launched before, so we expect a user_created event.
|
||||
$this->assertInstanceOf(\core\event\user_created::class, $events[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1090,7 +1102,23 @@ class auth_test extends \advanced_testcase {
|
||||
'PII' => self::PII_NONE,
|
||||
'migrated' => false
|
||||
]
|
||||
]
|
||||
],
|
||||
'Existing (linked) platform learner including PII, no legacy data, no consumer key bound, no legacy id' => [
|
||||
'legacy_data' => null,
|
||||
'launch_data' => [
|
||||
'has_authenticated_before' => true,
|
||||
'user' => $this->get_mock_users_with_ids(
|
||||
['1'],
|
||||
'http://purl.imsglobal.org/vocab/lis/v2/membership#Learner'
|
||||
)[0],
|
||||
],
|
||||
'iss' => $this->issuer,
|
||||
'legacy_consumer_key' => null,
|
||||
'expected' => [
|
||||
'PII' => self::PII_ALL,
|
||||
'migrated' => false
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_auth_manual_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@ require_once($CFG->libdir.'/authlib.php');
|
||||
*/
|
||||
class auth_plugin_mnet extends auth_plugin_base {
|
||||
|
||||
/** @var mnet_environment mnet environment. */
|
||||
protected $mnet;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_auth_mnet_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ function xmldb_auth_none_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_auth_oauth2_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,5 +63,8 @@ function xmldb_auth_shibboleth_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class frontend extends \core_availability\frontend {
|
||||
/**
|
||||
* @var array Cached init parameters
|
||||
*/
|
||||
protected $cacheparams = [];
|
||||
protected $cacheinitparams = [];
|
||||
|
||||
/**
|
||||
* @var string IDs of course, cm, and section for cache (if any)
|
||||
|
||||
@@ -167,6 +167,7 @@ class backup_course_task extends backup_task {
|
||||
$content = self::encode_links_helper($content, 'GRADEREPORTINDEXBYID', '/grade/report/index.php?id=');
|
||||
$content = self::encode_links_helper($content, 'BADGESVIEWBYID', '/badges/view.php?type=2&id=');
|
||||
$content = self::encode_links_helper($content, 'USERINDEXVIEWBYID', '/user/index.php?id=');
|
||||
$content = self::encode_links_helper($content, 'PLUGINFILEBYCONTEXT', '/pluginfile.php/');
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@ class base64_encode_final_element extends backup_final_element {
|
||||
* @param string $value Original value coming from backup step source, usually db.
|
||||
*/
|
||||
public function set_value($value) {
|
||||
// Avoid null being passed to base64_encode.
|
||||
$value = $value ?? '';
|
||||
parent::set_value(base64_encode($value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2383,28 +2383,40 @@ class backup_annotate_all_question_files extends backup_execution_step {
|
||||
AND bi.itemname = 'question_categoryfinal'", array($this->get_backupid()));
|
||||
// To know about qtype specific components/fileareas
|
||||
$components = backup_qtype_plugin::get_components_and_fileareas();
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress($this->get_name());
|
||||
// Let's loop
|
||||
foreach($rs as $record) {
|
||||
// Backup all the file areas the are managed by the core question component.
|
||||
// That is, by the question_type base class. In particular, we don't want
|
||||
// to include files belonging to responses here.
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'questiontext', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'generalfeedback', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'answer', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'answerfeedback', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'hint', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'correctfeedback', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'partiallycorrectfeedback', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'incorrectfeedback', null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'questiontext', null,
|
||||
$progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'generalfeedback', null,
|
||||
$progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'answer', null,
|
||||
$progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'answerfeedback', null,
|
||||
$progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'hint', null,
|
||||
$progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'correctfeedback', null,
|
||||
$progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question',
|
||||
'partiallycorrectfeedback', null, $progress);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, 'question', 'incorrectfeedback', null,
|
||||
$progress);
|
||||
|
||||
// For files belonging to question types, we make the leap of faith that
|
||||
// all the files belonging to the question type are part of the question definition,
|
||||
// so we can just backup all the files in bulk, without specifying each
|
||||
// file area name separately.
|
||||
foreach ($components as $component => $fileareas) {
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, $component, null, null);
|
||||
backup_structure_dbops::annotate_files($this->get_backupid(), $record->contextid, $component, null, null,
|
||||
$progress);
|
||||
}
|
||||
}
|
||||
$progress->end_progress();
|
||||
$rs->close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ class restore_course_task extends restore_task {
|
||||
$rules[] = new restore_decode_rule('GRADEREPORTINDEXBYID', '/grade/report/index.php?id=$1', 'course');
|
||||
$rules[] = new restore_decode_rule('BADGESVIEWBYID', '/badges/view.php?type=2&id=$1', 'course');
|
||||
$rules[] = new restore_decode_rule('USERINDEXVIEWBYID', '/user/index.php?id=$1', 'course');
|
||||
$rules[] = new restore_decode_rule('PLUGINFILEBYCONTEXT', '/pluginfile.php/$1', 'context');
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
@@ -119,18 +119,14 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Identify the backup we're dealing with.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
$backupbuild = 0;
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
if (!empty($matches[1])) {
|
||||
$backupbuild = (int) $matches[1]; // The date of Moodle build at the time of the backup.
|
||||
}
|
||||
$restoretask = $this->get_task();
|
||||
|
||||
// On older versions the freeze value has to be converted.
|
||||
// We do this from here as it is happening right before the file is read.
|
||||
// This only targets the backup files that can contain the legacy freeze.
|
||||
if ($backupbuild > 20150618 && (version_compare($backuprelease, '3.0', '<') || $backupbuild < 20160527)) {
|
||||
if ($restoretask->backup_version_compare(20150618, '>')
|
||||
&& $restoretask->backup_release_compare('3.0', '<')
|
||||
|| $restoretask->backup_version_compare(20160527, '<')) {
|
||||
$this->rewrite_step_backup_file_for_legacy_freeze($fullpath);
|
||||
}
|
||||
|
||||
@@ -505,24 +501,25 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
protected function gradebook_calculation_freeze() {
|
||||
global $CFG;
|
||||
$gradebookcalculationsfreeze = get_config('core', 'gradebook_calculations_freeze_' . $this->get_courseid());
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
$restoretask = $this->get_task();
|
||||
|
||||
// Extra credits need adjustments only for backups made between 2.8 release (20141110) and the fix release (20150619).
|
||||
if (!$gradebookcalculationsfreeze && $backupbuild >= 20141110 && $backupbuild < 20150619) {
|
||||
if (!$gradebookcalculationsfreeze && $restoretask->backup_version_compare(20141110, '>=')
|
||||
&& $restoretask->backup_version_compare(20150619, '<')) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_extra_credit_weightoverride($this->get_courseid());
|
||||
}
|
||||
// Calculated grade items need recalculating for backups made between 2.8 release (20141110) and the fix release (20150627).
|
||||
if (!$gradebookcalculationsfreeze && $backupbuild >= 20141110 && $backupbuild < 20150627) {
|
||||
if (!$gradebookcalculationsfreeze && $restoretask->backup_version_compare(20141110, '>=')
|
||||
&& $restoretask->backup_version_compare(20150627, '<')) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_calculated_grade_items($this->get_courseid());
|
||||
}
|
||||
// Courses from before 3.1 (20160518) may have a letter boundary problem and should be checked for this issue.
|
||||
// Backups from before and including 2.9 could have a build number that is greater than 20160518 and should
|
||||
// be checked for this problem.
|
||||
if (!$gradebookcalculationsfreeze && ($backupbuild < 20160518 || version_compare($backuprelease, '2.9', '<='))) {
|
||||
if (!$gradebookcalculationsfreeze
|
||||
&& ($restoretask->backup_version_compare(20160518, '<') || $restoretask->backup_release_compare('2.9', '<='))) {
|
||||
require_once($CFG->libdir . '/db/upgradelib.php');
|
||||
upgrade_course_letter_boundary($this->get_courseid());
|
||||
}
|
||||
@@ -4868,13 +4865,8 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
protected function define_structure() {
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$before40 = false;
|
||||
if (version_compare($backuprelease, '4.0', '<') || $backupbuild < 20220202) {
|
||||
$before40 = true;
|
||||
}
|
||||
$restoretask = $this->get_task();
|
||||
$before40 = $restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<');
|
||||
// Start creating the path, category should be the first one.
|
||||
$paths = [];
|
||||
$paths [] = new restore_path_element('question_category', '/question_categories/question_category');
|
||||
@@ -4956,13 +4948,8 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
|
||||
// Before 3.5, question categories could be created at top level.
|
||||
// From 3.5 onwards, all question categories should be a child of a special category called the "top" category.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$before35 = false;
|
||||
if (version_compare($backuprelease, '3.5', '<') || $backupbuild < 20180205) {
|
||||
$before35 = true;
|
||||
}
|
||||
$restoretask = $this->get_task();
|
||||
$before35 = $restoretask->backup_release_compare('3.5', '<') || $restoretask->backup_version_compare(20180205, '<');
|
||||
if (empty($mapping->info->parent) && $before35) {
|
||||
$top = question_get_top_category($data->contextid, true);
|
||||
$data->parent = $top->id;
|
||||
@@ -5110,14 +5097,8 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
$oldid = $data->id;
|
||||
|
||||
// Check if the backup is a pre 4.0 one.
|
||||
$backuprelease = $this->get_task()->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->get_task()->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$before40 = false;
|
||||
if (version_compare($backuprelease, '4.0', '<') || $backupbuild < 20220202) {
|
||||
$before40 = true;
|
||||
}
|
||||
if ($before40) {
|
||||
$restoretask = $this->get_task();
|
||||
if ($restoretask->backup_release_compare('4.0', '<') || $restoretask->backup_version_compare(20220202, '<')) {
|
||||
// Check we have one mapping for this question.
|
||||
if (!$questionmapping = $this->get_mapping('question', $oldid)) {
|
||||
return; // No mapping = this question doesn't need to be created/mapped.
|
||||
@@ -5342,13 +5323,7 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
$backuprelease = $this->task->get_info()->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $this->task->get_info()->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$after35 = false;
|
||||
if (version_compare($backuprelease, '3.5', '>=') && $backupbuild > 20180205) {
|
||||
$after35 = true;
|
||||
}
|
||||
$after35 = $this->task->backup_release_compare('3.5', '>=') && $this->task->backup_version_compare(20180205, '>');
|
||||
|
||||
$contexts = restore_dbops::restore_get_question_banks($this->get_restoreid(), CONTEXT_MODULE);
|
||||
foreach ($contexts as $contextid => $contextlevel) {
|
||||
|
||||
@@ -578,16 +578,11 @@ abstract class restore_dbops {
|
||||
CONTEXT_SYSTEM => CONTEXT_COURSE,
|
||||
CONTEXT_COURSECAT => CONTEXT_COURSE);
|
||||
|
||||
/** @var restore_controller $rc */
|
||||
$rc = restore_controller_dbops::load_controller($restoreid);
|
||||
$restoreinfo = $rc->get_info();
|
||||
$plan = $rc->get_plan();
|
||||
$after35 = $plan->backup_release_compare('3.5', '>=') && $plan->backup_version_compare(20180205, '>');
|
||||
$rc->destroy(); // Always need to destroy.
|
||||
$backuprelease = $restoreinfo->backup_release; // The major version: 2.9, 3.0, 3.10...
|
||||
preg_match('/(\d{8})/', $restoreinfo->moodle_release, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
$after35 = false;
|
||||
if (version_compare($backuprelease, '3.5', '>=') && $backupbuild > 20180205) {
|
||||
$after35 = true;
|
||||
}
|
||||
|
||||
// For any contextlevel, follow this process logic:
|
||||
//
|
||||
|
||||
@@ -212,6 +212,30 @@ class restore_plan extends base_plan implements loggable {
|
||||
}
|
||||
$progress->end_progress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle version with the one the backup was taken from.
|
||||
*
|
||||
* @param int $version Moodle version number (YYYYMMDD or YYYYMMDDXX)
|
||||
* @param string $operator Operator to compare the provided version to the backup version. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_version_compare(int $version, string $operator): bool {
|
||||
preg_match('/(\d{' . strlen($version) . '})/', $this->get_info()->moodle_version, $matches);
|
||||
$backupbuild = (int)$matches[1];
|
||||
return version_compare($backupbuild, $version, $operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle release with the one the backup was taken from.
|
||||
*
|
||||
* @param string $release Moodle release (X.Y or X.Y.Z)
|
||||
* @param string $operator Operator to compare the provided release to the backup release. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_release_compare(string $release, string $operator): bool {
|
||||
return version_compare($this->get_info()->backup_release, $release, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -124,6 +124,28 @@ abstract class restore_task extends base_task {
|
||||
$this->after_restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle version with the one the backup was taken from.
|
||||
*
|
||||
* @param int $version Moodle version number (YYYYMMDD or YYYYMMDDXX)
|
||||
* @param string $operator Operator to compare the provided version to the backup version. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_version_compare(int $version, string $operator) {
|
||||
return $this->plan->backup_version_compare($version, $operator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the provided moodle release with the one the backup was taken from.
|
||||
*
|
||||
* @param string $release Moodle release (X.Y or X.Y.Z)
|
||||
* @param string $operator Operator to compare the provided release to the backup release. {@see version_compare()}
|
||||
* @return bool True if the comparison passes.
|
||||
*/
|
||||
public function backup_release_compare(string $release, string $operator) {
|
||||
return $this->plan->backup_release_compare($release, $operator);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -786,6 +786,10 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
'extraclasses' => 'rcs-search mb-3 w-25',
|
||||
'inputname' => restore_course_search::$VAR_SEARCH,
|
||||
'searchstring' => get_string('searchcourses'),
|
||||
'buttonattributes' => [
|
||||
(object) ['key' => 'name', 'value' => 'searchcourses'],
|
||||
(object) ['key' => 'value', 'value' => 1],
|
||||
],
|
||||
'query' => $component->get_search(),
|
||||
];
|
||||
$output .= $this->output->render_from_template('core/search_input', $data);
|
||||
@@ -955,6 +959,10 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
'extraclasses' => 'rcs-search mb-3 w-25',
|
||||
'inputname' => restore_category_search::$VAR_SEARCH,
|
||||
'searchstring' => get_string('searchcoursecategories'),
|
||||
'buttonattributes' => [
|
||||
(object) ['key' => 'name', 'value' => 'searchcourses'],
|
||||
(object) ['key' => 'value', 'value' => 1],
|
||||
],
|
||||
'query' => $component->get_search(),
|
||||
];
|
||||
$output .= $this->output->render_from_template('core/search_input', $data);
|
||||
|
||||
@@ -262,7 +262,7 @@ class xml_writer {
|
||||
protected function xml_safe_utf8($content) {
|
||||
$content = preg_replace('/[\x-\x8\xb-\xc\xe-\x1f\x7f]/is', '', $content ?? ''); // clean CTRL chars.
|
||||
$content = preg_replace("/\r\n|\r/", "\n", $content); // Normalize line&return=>line
|
||||
return $content;
|
||||
return fix_utf8($content);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,6 +36,9 @@ use core_badges\backpack_api2p1_mapping;
|
||||
use core_badges\oauth2\client;
|
||||
use curl;
|
||||
use stdClass;
|
||||
use core\oauth2\issuer;
|
||||
use core\oauth2\endpoint;
|
||||
use core\oauth2\discovery\imsbadgeconnect;
|
||||
|
||||
/**
|
||||
* To process badges with backpack and control api request and this class using for Open Badge API v2.1 methods.
|
||||
@@ -61,8 +64,11 @@ class backpack_api2p1 {
|
||||
/** @var null version api of the backpack. */
|
||||
protected $backpackapiversion;
|
||||
|
||||
/** @var null api URL of the backpack. */
|
||||
protected $backpackapiurl = '';
|
||||
/** @var issuer The OAuth2 Issuer for this backpack */
|
||||
protected issuer $issuer;
|
||||
|
||||
/** @var endpoint The apiBase endpoint */
|
||||
protected endpoint $apibase;
|
||||
|
||||
/**
|
||||
* backpack_api2p1 constructor.
|
||||
@@ -75,8 +81,7 @@ class backpack_api2p1 {
|
||||
if (!empty($externalbackpack)) {
|
||||
$this->externalbackpack = $externalbackpack;
|
||||
$this->backpackapiversion = $externalbackpack->apiversion;
|
||||
$this->backpackapiurl = $externalbackpack->backpackapiurl;
|
||||
$this->get_clientid = $this->get_clientid($externalbackpack->oauth2_issuerid);
|
||||
$this->get_clientid($externalbackpack->oauth2_issuerid);
|
||||
|
||||
if (!($this->tokendata = $this->get_stored_token($externalbackpack->id))
|
||||
&& $this->backpackapiversion != OPEN_BADGES_V2P1) {
|
||||
@@ -87,6 +92,44 @@ class backpack_api2p1 {
|
||||
$this->define_mappings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises or returns the OAuth2 issuer associated to this backpack.
|
||||
*
|
||||
* @return issuer
|
||||
*/
|
||||
protected function get_issuer(): issuer {
|
||||
if (!isset($this->issuer)) {
|
||||
$this->issuer = new \core\oauth2\issuer($this->externalbackpack->oauth2_issuerid);
|
||||
}
|
||||
return $this->issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the apiBase url associated to this backpack.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_api_base_url(): string {
|
||||
if (!isset($this->apibase)) {
|
||||
$apibase = endpoint::get_record([
|
||||
'issuerid' => $this->externalbackpack->oauth2_issuerid,
|
||||
'name' => 'apiBase',
|
||||
]);
|
||||
|
||||
if (empty($apibase)) {
|
||||
imsbadgeconnect::create_endpoints($this->get_issuer());
|
||||
$apibase = endpoint::get_record([
|
||||
'issuerid' => $this->externalbackpack->oauth2_issuerid,
|
||||
'name' => 'apiBase',
|
||||
]);
|
||||
}
|
||||
|
||||
$this->apibase = $apibase;
|
||||
}
|
||||
|
||||
return $this->apibase->get('url');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Define the mappings supported by this usage and api version.
|
||||
@@ -157,7 +200,7 @@ class backpack_api2p1 {
|
||||
foreach ($this->mappings as $mapping) {
|
||||
if ($mapping->is_match($action)) {
|
||||
return $mapping->request(
|
||||
$this->backpackapiurl,
|
||||
$this->get_api_base_url(),
|
||||
$tokenkey,
|
||||
$postdata
|
||||
);
|
||||
@@ -194,6 +237,7 @@ class backpack_api2p1 {
|
||||
private function get_clientid($issuerid) {
|
||||
$issuer = \core\oauth2\api::get_issuer($issuerid);
|
||||
if (!empty($issuer)) {
|
||||
$this->issuer = $issuer;
|
||||
$this->clientid = $issuer->get('clientid');
|
||||
}
|
||||
}
|
||||
@@ -212,7 +256,7 @@ class backpack_api2p1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
$issuer = new \core\oauth2\issuer($this->externalbackpack->oauth2_issuerid);
|
||||
$issuer = $this->get_issuer();
|
||||
$client = new client($issuer, new moodle_url('/badges/mybadges.php'), '', $this->externalbackpack);
|
||||
if (!$client->is_logged_in()) {
|
||||
$redirecturl = new moodle_url('/badges/mybadges.php', ['error' => 'backpackexporterror']);
|
||||
|
||||
@@ -67,6 +67,12 @@ class backpack_api2p1_mapping {
|
||||
/** @var boolean Differentiate the function that can be called on a user backpack or a site backpack. */
|
||||
private $isuserbackpack;
|
||||
|
||||
/** @var mixed List of parameters for this method. */
|
||||
protected $postparams;
|
||||
|
||||
/** @var int OpenBadges version 1 or 2. */
|
||||
protected $backpackapiversion;
|
||||
|
||||
/**
|
||||
* Create a mapping.
|
||||
*
|
||||
|
||||
@@ -79,6 +79,12 @@ class backpack_api_mapping {
|
||||
/** @var string Error string from authentication request. */
|
||||
private static $authenticationerror = '';
|
||||
|
||||
/** @var mixed List of parameters for this method. */
|
||||
protected $postparams;
|
||||
|
||||
/** @var int OpenBadges version 1 or 2. */
|
||||
protected $backpackapiversion;
|
||||
|
||||
/**
|
||||
* Create a mapping.
|
||||
*
|
||||
|
||||
@@ -129,6 +129,24 @@ class badge {
|
||||
/** @var array Badge criteria */
|
||||
public $criteria = array();
|
||||
|
||||
/** @var int|null Total users which have the award. Called from badges_get_badges() */
|
||||
public $awards;
|
||||
|
||||
/** @var string|null The name of badge status. Called from badges_get_badges() */
|
||||
public $statstring;
|
||||
|
||||
/** @var int|null The date the badges were issued. Called from badges_get_badges() */
|
||||
public $dateissued;
|
||||
|
||||
/** @var string|null Unique hash. Called from badges_get_badges() */
|
||||
public $uniquehash;
|
||||
|
||||
/** @var string|null Message format. Called from file_prepare_standard_editor() */
|
||||
public $messageformat;
|
||||
|
||||
/** @var array Message editor. Called from file_prepare_standard_editor() */
|
||||
public $message_editor = [];
|
||||
|
||||
/**
|
||||
* Constructs with badge details.
|
||||
*
|
||||
@@ -240,7 +258,16 @@ class badge {
|
||||
foreach (get_object_vars($this) as $k => $v) {
|
||||
$fordb->{$k} = $v;
|
||||
}
|
||||
// TODO: We need to making it more simple.
|
||||
// Since the variables are not exist in the badge table,
|
||||
// unsetting them is a must to avoid errors.
|
||||
unset($fordb->criteria);
|
||||
unset($fordb->awards);
|
||||
unset($fordb->statstring);
|
||||
unset($fordb->dateissued);
|
||||
unset($fordb->uniquehash);
|
||||
unset($fordb->messageformat);
|
||||
unset($fordb->message_editor);
|
||||
|
||||
$fordb->timemodified = time();
|
||||
if ($DB->update_record_raw('badge', $fordb)) {
|
||||
|
||||
@@ -39,6 +39,12 @@ use core_badges\external\backpack_exporter;
|
||||
*/
|
||||
class external_backpacks_page implements \renderable {
|
||||
|
||||
/** @var \moodle_url Badges backpacks URL. */
|
||||
protected $url;
|
||||
|
||||
/** @var array List the backpacks at site level. */
|
||||
protected $backpacks = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param \moodle_url $url
|
||||
|
||||
@@ -48,9 +48,9 @@ class external_backpacks_table extends table_sql {
|
||||
public function __construct() {
|
||||
parent::__construct('backpacks');
|
||||
|
||||
$this->context = \context_system::instance();
|
||||
$context = \context_system::instance();
|
||||
// This object should not be used without the right permissions.
|
||||
require_capability('moodle/badges:manageglobalsettings', $this->context);
|
||||
require_capability('moodle/badges:manageglobalsettings', $context);
|
||||
|
||||
// Define columns in the table.
|
||||
$this->define_table_columns();
|
||||
|
||||
@@ -128,6 +128,24 @@ abstract class award_criteria {
|
||||
*/
|
||||
public $params = array();
|
||||
|
||||
/**
|
||||
* Criteria type.
|
||||
* @var string
|
||||
*/
|
||||
public $criteriatype;
|
||||
|
||||
/**
|
||||
* Required parameters.
|
||||
* @var string
|
||||
*/
|
||||
public $required_param = '';
|
||||
|
||||
/**
|
||||
* Optional parameters.
|
||||
* @var array
|
||||
*/
|
||||
public $optional_params = [];
|
||||
|
||||
/**
|
||||
* The base constructor
|
||||
*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_badges @_file_upload
|
||||
@core @core_badges
|
||||
Feature: Backpack badges
|
||||
Test the settings to add/update a backpack for a site and user.
|
||||
I need to verify display backpack in the my profile
|
||||
@@ -37,36 +37,21 @@ Feature: Backpack badges
|
||||
|
||||
@javascript
|
||||
Scenario: Verify backback settings
|
||||
Given I am on homepage
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Badges settings" in site administration
|
||||
And I set the following fields to these values:
|
||||
| External backpack connection | 1 |
|
||||
And I press "Save changes"
|
||||
And I navigate to "Badges > Manage backpacks" in site administration
|
||||
And I click on "Move up" "link" in the "https://dc.imsglobal.org" "table_row"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Test badge verify backpack |
|
||||
| Version | v1 |
|
||||
| Language | English |
|
||||
| Description | Test badge description |
|
||||
| Image author | http://author.example.com |
|
||||
| Image caption | Test caption image |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I set the field "type" to "Manual issue by role"
|
||||
And I set the field "Manager" to "1"
|
||||
And I press "Save"
|
||||
And I press "Enable access"
|
||||
And I press "Continue"
|
||||
And I select "Recipients (0)" from the "jump" singleselect
|
||||
And I press "Award badge"
|
||||
And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
|
||||
And I press "Award badge"
|
||||
And I log out
|
||||
When I am on homepage
|
||||
And I log in as "student1"
|
||||
Given the following "core_badges > Badge" exists:
|
||||
| name | Test badge verify backpack |
|
||||
| version | 1 |
|
||||
| language | en |
|
||||
| description | Test badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
| imageauthorurl | http://author.example.com |
|
||||
| imagecaption | Test caption image |
|
||||
And the following "core_badges > Criteria" exists:
|
||||
| badge | Test badge verify backpack |
|
||||
| role | editingteacher |
|
||||
And the following "core_badges > Issued badge" exists:
|
||||
| badge | Test badge verify backpack |
|
||||
| user | student1 |
|
||||
When I log in as "student1"
|
||||
And I follow "Preferences" in the user menu
|
||||
And I follow "Backpack settings"
|
||||
Then I should see "https://dc.imsglobal.org"
|
||||
@@ -82,26 +67,20 @@ Feature: Backpack badges
|
||||
And I press "Save changes"
|
||||
And I navigate to "Badges > Manage backpacks" in site administration
|
||||
And I click on "Move up" "link" in the "https://dc.imsglobal.org" "table_row"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Test badge verify backpack |
|
||||
| Version | v1 |
|
||||
| Language | English |
|
||||
| Description | Test badge description |
|
||||
| Image author | http://author.example.com |
|
||||
| Image caption | Test caption image |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I set the field "type" to "Manual issue by role"
|
||||
And I set the field "Manager" to "1"
|
||||
And I press "Save"
|
||||
And I press "Enable access"
|
||||
And I press "Continue"
|
||||
And I select "Recipients (0)" from the "jump" singleselect
|
||||
And I press "Award badge"
|
||||
And I set the field "potentialrecipients[]" to "Student 1 (student1@example.com)"
|
||||
And I press "Award badge"
|
||||
And I log out
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Test badge verify backpack |
|
||||
| version | 1 |
|
||||
| language | en |
|
||||
| description | Test badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
| imageauthorurl | http://author.example.com |
|
||||
| imagecaption | Test caption image |
|
||||
And the following "core_badges > Criteria" exists:
|
||||
| badge | Test badge verify backpack |
|
||||
| role | editingteacher |
|
||||
And the following "core_badges > Issued badge" exists:
|
||||
| badge | Test badge verify backpack |
|
||||
| user | student1 |
|
||||
And the following "setup backpack connected" exist:
|
||||
| user | externalbackpack |
|
||||
| student1 | https://dc.imsglobal.org |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_badges @_file_upload @javascript
|
||||
@core @core_badges @javascript
|
||||
Feature: Test tertiary navigation as various users
|
||||
|
||||
Background:
|
||||
@@ -15,38 +15,32 @@ Feature: Test tertiary navigation as various users
|
||||
| teacher | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| nonediting | C1 | teacher |
|
||||
# Create system badge and define a criterion.
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage
|
||||
And I navigate to "Badges > Add a new badge" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Testing course badge |
|
||||
| Version | 1.1 |
|
||||
| Language | Catalan |
|
||||
| Description | Testing course badge description |
|
||||
| Image author | http://author.example.com |
|
||||
| Image caption | Test caption image |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I set the field "type" to "Manual issue by role"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Teacher" to "1"
|
||||
And I press "Save"
|
||||
And I am on site homepage
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Testing site badge |
|
||||
| Version | 1.1 |
|
||||
| Language | Catalan |
|
||||
| Description | Testing site badge description |
|
||||
| Image author | http://author.example.com |
|
||||
| Image caption | Test caption image |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I set the field "type" to "Manual issue by role"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Teacher" to "1"
|
||||
And I press "Save"
|
||||
# Create a course badge in our test course.
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Testing course badge |
|
||||
| status | inactive |
|
||||
| type | 2 |
|
||||
| course | C1 |
|
||||
| version | 1.1 |
|
||||
| language | ca |
|
||||
| description | Testing course badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
| imageauthorurl | http://author.example.com |
|
||||
| imagecaption | Test caption image |
|
||||
# Create a site badge.
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Testing site badge |
|
||||
| status | inactive |
|
||||
| version | 1.1 |
|
||||
| language | ca |
|
||||
| description | Testing site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
| imageauthorurl | http://author.example.com |
|
||||
| imagecaption | Test caption image |
|
||||
And the following "core_badges > Criterias" exist:
|
||||
| badge | role |
|
||||
| Testing course badge | editingteacher |
|
||||
| Testing site badge | editingteacher |
|
||||
|
||||
Scenario Outline: Check navigation as different users in a course context
|
||||
Given I log in as "<user>"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@mod @mod_quiz @core @core_badges @_file_upload @javascript
|
||||
@mod @mod_quiz @core @core_badges @javascript
|
||||
Feature: Award badges based on activity completion
|
||||
In order to ensure a student has learned the material before being marked complete
|
||||
As a teacher
|
||||
@@ -38,15 +38,13 @@ Feature: Award badges based on activity completion
|
||||
And user "student2" has attempted "Test quiz name" with responses:
|
||||
| slot | response |
|
||||
| 1 | False |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
And I change window size to "large"
|
||||
And I navigate to "Badges > Add a new badge" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Course Badge |
|
||||
| Description | Course badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Course Badge |
|
||||
| status | 0 |
|
||||
| type | 2 |
|
||||
| course | C1 |
|
||||
| description | Course badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
|
||||
Scenario: Student earns a badge using activity completion, but does not get passing grade
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_badges @_file_upload
|
||||
@core @core_badges
|
||||
Feature: Award badges based on cohort
|
||||
In order to award badges to users based on their cohort membership
|
||||
As an admin
|
||||
@@ -18,13 +18,15 @@ Feature: Award badges based on cohort
|
||||
| user | cohort |
|
||||
| user1 | CH1 |
|
||||
| user2 | CH2 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort"
|
||||
And I press "Save"
|
||||
@@ -53,13 +55,15 @@ Feature: Award badges based on cohort
|
||||
| user1 | CH2 |
|
||||
| user2 | CH1 |
|
||||
| user2 | CH3 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I expand all fieldsets
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort,Two Cohort"
|
||||
@@ -93,13 +97,15 @@ Feature: Award badges based on cohort
|
||||
| user2 | CH3 |
|
||||
| user3 | CH2 |
|
||||
| user3 | CH3 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort"
|
||||
And I press "Save"
|
||||
@@ -129,13 +135,15 @@ Feature: Award badges based on cohort
|
||||
| user | cohort |
|
||||
| user1 | CH1 |
|
||||
| user2 | CH2 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort"
|
||||
And I press "Save"
|
||||
@@ -180,13 +188,15 @@ Feature: Award badges based on cohort
|
||||
| user1 | CH1 |
|
||||
| user2 | CH2 |
|
||||
| user3 | CH2 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort"
|
||||
And I press "Save"
|
||||
@@ -237,13 +247,15 @@ Feature: Award badges based on cohort
|
||||
| user1 | CH2 |
|
||||
| user2 | CH2 |
|
||||
| user2 | CH2 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort"
|
||||
And I press "Save"
|
||||
@@ -294,13 +306,15 @@ Feature: Award badges based on cohort
|
||||
| user1 | CH2 |
|
||||
| user2 | CH1 |
|
||||
| user3 | CH2 |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I expand all fieldsets
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort,Two Cohort"
|
||||
@@ -352,25 +366,23 @@ Feature: Award badges based on cohort
|
||||
| user1 | CH1 |
|
||||
| user1 | CH2 |
|
||||
| user2 | CH2 |
|
||||
And the following "core_badges > Badges" exist:
|
||||
| name | status | description | image |
|
||||
| Site Badge 1 | 0 | Site badge description | badges/tests/behat/badge.png |
|
||||
| Site Badge 2 | 0 | Site badge description | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge 1 |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge 1" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort"
|
||||
And I press "Save"
|
||||
And I press "Enable access"
|
||||
When I press "Continue"
|
||||
And I should see "Recipients (1)"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge 2 |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge 2" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I set the field "id_cohort_cohorts" to "Two Cohort"
|
||||
And I press "Save"
|
||||
@@ -411,13 +423,14 @@ Feature: Award badges based on cohort
|
||||
| user1 | CH2 |
|
||||
| user2 | CH2 |
|
||||
| user2 | CH3 |
|
||||
And the following "core_badges > Badges" exist:
|
||||
| name | status | description | image |
|
||||
| Site Badge 1 | 0 | Site badge description | badges/tests/behat/badge.png |
|
||||
| Site Badge 2 | 0 | Site badge description | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge 1 |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge 1" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I expand all fieldsets
|
||||
And I set the field "id_cohort_cohorts" to "One Cohort,Two Cohort"
|
||||
@@ -426,12 +439,9 @@ Feature: Award badges based on cohort
|
||||
And I press "Enable access"
|
||||
When I press "Continue"
|
||||
And I should see "Recipients (1)"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge 2 |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge 2" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Cohort membership"
|
||||
And I expand all fieldsets
|
||||
And I set the field "id_cohort_cohorts" to "Three Cohort,Two Cohort"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_badges @_file_upload
|
||||
@core @core_badges
|
||||
Feature: Award badges based on competency completion
|
||||
In order to award badges to users based on competency completion
|
||||
As an admin
|
||||
@@ -25,6 +25,13 @@ Feature: Award badges based on competency completion
|
||||
|
||||
@javascript
|
||||
Scenario: Award badge for completing a competency in a course
|
||||
Given the following "core_badges > Badge" exists:
|
||||
| name | Course Badge |
|
||||
| status | 0 |
|
||||
| type | 2 |
|
||||
| course | C1 |
|
||||
| description | Course badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
# Add a competency to the course
|
||||
When I am on "Course 1" course homepage
|
||||
And I navigate to "Competencies > Add competencies to course" in current page administration
|
||||
@@ -39,12 +46,10 @@ Feature: Award badges based on competency completion
|
||||
# Add a badge to the course
|
||||
And I am on "Course 1" course homepage
|
||||
And I change window size to "large"
|
||||
And I navigate to "Badges > Add a new badge" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Course Badge |
|
||||
| Description | Course badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges" in current page administration
|
||||
And I press "Manage badges"
|
||||
And I follow "Course Badge"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
# Set the competency as a criteria for the badge
|
||||
And I set the field "type" to "Competencies"
|
||||
When I open the autocomplete suggestions list
|
||||
@@ -72,6 +77,11 @@ Feature: Award badges based on competency completion
|
||||
|
||||
@javascript
|
||||
Scenario: Award badge for completing a competency in the site
|
||||
Given the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
# Add a competency to the course
|
||||
When I am on "Course 1" course homepage
|
||||
And I navigate to "Competencies > Add competencies to course" in current page administration
|
||||
@@ -83,12 +93,9 @@ Feature: Award badges based on competency completion
|
||||
And I select "comp2" of the competency tree
|
||||
And I click on "Add" "button" in the "Competency picker" "dialogue"
|
||||
# Add a badge to the site
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
# Set the competency as a criteria for the badge
|
||||
And I set the field "type" to "Competencies"
|
||||
And I press "Add competency"
|
||||
@@ -123,6 +130,11 @@ Feature: Award badges based on competency completion
|
||||
|
||||
@javascript
|
||||
Scenario: Award badge for completing all competencies in the site
|
||||
Given the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
# Add a competency to the course
|
||||
When I am on "Course 1" course homepage
|
||||
And I navigate to "Competencies > Add competencies to course" in current page administration
|
||||
@@ -134,12 +146,9 @@ Feature: Award badges based on competency completion
|
||||
And I select "comp2" of the competency tree
|
||||
And I click on "Add" "button" in the "Competency picker" "dialogue"
|
||||
# Add a badge to the site
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
# Set the competency as a criteria for the badge
|
||||
And I set the field "type" to "Competencies"
|
||||
And I press "Add competency"
|
||||
|
||||
@@ -9,13 +9,15 @@ Feature: Award badges based on user profile field
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| user1 | First | User | first@example.com |
|
||||
And the following "core_badges > Badge" exists:
|
||||
| name | Site Badge |
|
||||
| status | 0 |
|
||||
| description | Site badge description |
|
||||
| image | badges/tests/behat/badge.png |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Badges > Add a new badge" in site administration
|
||||
And I set the following fields to these values:
|
||||
| Name | Site Badge |
|
||||
| Description | Site badge description |
|
||||
And I upload "badges/tests/behat/badge.png" file to "Image" filemanager
|
||||
And I press "Create badge"
|
||||
And I navigate to "Badges > Manage badges" in site administration
|
||||
And I click on "Edit" "link" in the "Site Badge" "table_row"
|
||||
And I select "Criteria" from the "jump" singleselect
|
||||
And I set the field "type" to "Profile completion"
|
||||
And I set the field "id_field_picture" to "1"
|
||||
And I press "Save"
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<?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/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Badges test generator for Behat
|
||||
*
|
||||
* @package core_badges
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_core_badges_generator extends behat_generator_base {
|
||||
|
||||
/**
|
||||
* Get a list of the entities that can be created for this component
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
protected function get_creatable_entities(): array {
|
||||
return [
|
||||
'Badges' => [
|
||||
'singular' => 'Badge',
|
||||
'datagenerator' => 'badge',
|
||||
'required' => [
|
||||
'name',
|
||||
],
|
||||
'switchids' => [
|
||||
'course' => 'courseid',
|
||||
],
|
||||
],
|
||||
'Criterias' => [
|
||||
'singular' => 'Criteria',
|
||||
'datagenerator' => 'criteria',
|
||||
'required' => [
|
||||
'badge',
|
||||
'role',
|
||||
],
|
||||
'switchids' => [
|
||||
'badge' => 'badgeid',
|
||||
'role' => 'roleid',
|
||||
],
|
||||
],
|
||||
'Issued badges' => [
|
||||
'singular' => 'Issued badge',
|
||||
'datagenerator' => 'issued_badge',
|
||||
'required' => [
|
||||
'badge',
|
||||
'user',
|
||||
],
|
||||
'switchids' => [
|
||||
'badge' => 'badgeid',
|
||||
'user' => 'userid',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up badge ID from given name
|
||||
*
|
||||
* @param string $name
|
||||
* @return int
|
||||
*/
|
||||
protected function get_badge_id(string $name): int {
|
||||
global $DB;
|
||||
|
||||
return (int) $DB->get_field('badge', 'id', ['name' => $name], MUST_EXIST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process badge entity
|
||||
*
|
||||
* @param array $badge
|
||||
* @return array
|
||||
*/
|
||||
protected function preprocess_badge(array $badge): array {
|
||||
global $CFG;
|
||||
|
||||
require_once("{$CFG->libdir}/badgeslib.php");
|
||||
|
||||
// Allow text status' that correspond to badge constants.
|
||||
if (array_key_exists('status', $badge) && !is_numeric($badge['status'])) {
|
||||
$badge['status'] = constant('BADGE_STATUS_' . strtoupper($badge['status']));
|
||||
}
|
||||
|
||||
return $badge;
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,17 @@ class core_badges_generator extends component_generator_base {
|
||||
/**
|
||||
* Create badge
|
||||
*
|
||||
* TODO: MDL-73648 Use from Behat too
|
||||
*
|
||||
* @param array|stdClass $record
|
||||
* @return badge
|
||||
*/
|
||||
public function create_badge($record): badge {
|
||||
global $DB, $USER;
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
$record = (array) $record;
|
||||
|
||||
// Save badge image path for later.
|
||||
$badgeimage = $record['image'] ?? '';
|
||||
unset($record['image']);
|
||||
|
||||
$record = (object) array_merge([
|
||||
'name' => 'Test badge',
|
||||
@@ -67,10 +72,87 @@ class core_badges_generator extends component_generator_base {
|
||||
'imageauthoremail' => 'author@example.com',
|
||||
'imageauthorurl' => 'http://image.example.com/',
|
||||
'imagecaption' => 'Image caption'
|
||||
], (array) $record);
|
||||
], $record);
|
||||
|
||||
$record->id = $DB->insert_record('badge', $record);
|
||||
$badge = new badge($record->id);
|
||||
|
||||
return new badge($record->id);
|
||||
// Process badge image (if supplied).
|
||||
if ($badgeimage !== '') {
|
||||
$file = get_file_storage()->create_file_from_pathname([
|
||||
'contextid' => context_user::instance($USER->id)->id,
|
||||
'userid' => $USER->id,
|
||||
'component' => 'user',
|
||||
'filearea' => 'draft',
|
||||
'itemid' => file_get_unused_draft_itemid(),
|
||||
'filepath' => '/',
|
||||
'filename' => basename($badgeimage),
|
||||
], "{$CFG->dirroot}/$badgeimage");
|
||||
|
||||
// Copy image to temp file, as it'll be deleted by the following call.
|
||||
badges_process_badge_image($badge, $file->copy_content_to_temp());
|
||||
}
|
||||
|
||||
return $badge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create badge criteria
|
||||
*
|
||||
* Note that only manual criteria issues by role is currently supported
|
||||
*
|
||||
* @param array|stdClass $record
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function create_criteria($record): void {
|
||||
$record = (array) $record;
|
||||
|
||||
if (!array_key_exists('badgeid', $record)) {
|
||||
throw new coding_exception('Record must contain \'badgeid\' property');
|
||||
}
|
||||
if (!array_key_exists('roleid', $record)) {
|
||||
throw new coding_exception('Record must contain \'roleid\' property');
|
||||
}
|
||||
|
||||
$badge = new badge($record['badgeid']);
|
||||
|
||||
// Create the overall criteria.
|
||||
if (count($badge->criteria) === 0) {
|
||||
award_criteria::build([
|
||||
'badgeid' => $badge->id,
|
||||
'criteriatype' => BADGE_CRITERIA_TYPE_OVERALL,
|
||||
])->save([
|
||||
'agg' => BADGE_CRITERIA_AGGREGATION_ALL,
|
||||
]);
|
||||
}
|
||||
|
||||
// Create the manual criteria.
|
||||
award_criteria::build([
|
||||
'badgeid' => $badge->id,
|
||||
'criteriatype' => BADGE_CRITERIA_TYPE_MANUAL,
|
||||
])->save([
|
||||
'role_' . $record['roleid'] => $record['roleid'],
|
||||
'description' => $record['description'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create issued badge to a user
|
||||
*
|
||||
* @param array|stdClass $record
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function create_issued_badge($record): void {
|
||||
$record = (array) $record;
|
||||
|
||||
if (!array_key_exists('badgeid', $record)) {
|
||||
throw new coding_exception('Record must contain \'badgeid\' property');
|
||||
}
|
||||
if (!array_key_exists('userid', $record)) {
|
||||
throw new coding_exception('Record must contain \'userid\' property');
|
||||
}
|
||||
|
||||
$badge = new badge($record['badgeid']);
|
||||
$badge->issue($record['userid'], true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace core_badges\reportbuilder\datasource;
|
||||
|
||||
use award_criteria;
|
||||
use core_badges_generator;
|
||||
use core_reportbuilder_generator;
|
||||
use core_reportbuilder_testcase;
|
||||
@@ -100,13 +99,9 @@ class users_test extends core_reportbuilder_testcase {
|
||||
($badgecourse = $generator->create_badge(['name' => 'Badge 2', 'type' => BADGE_TYPE_COURSE, 'courseid' => $course->id]))
|
||||
->issue($user->id, true);
|
||||
|
||||
// Overall, plus specific criteria for manually awarding by role.
|
||||
award_criteria::build(['badgeid' => $badgesite->id, 'criteriatype' => BADGE_CRITERIA_TYPE_OVERALL])
|
||||
->save(['agg' => BADGE_CRITERIA_AGGREGATION_ALL]);
|
||||
|
||||
// Create criteria for manually awarding by role.
|
||||
$managerrole = $DB->get_field('role', 'id', ['shortname' => 'manager']);
|
||||
award_criteria::build(['badgeid' => $badgesite->id, 'criteriatype' => BADGE_CRITERIA_TYPE_MANUAL])
|
||||
->save(["role_{$managerrole}" => $managerrole]);
|
||||
$generator->create_criteria(['badgeid' => $badgesite->id, 'roleid' => $managerrole]);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
|
||||
@@ -54,5 +54,8 @@ function xmldb_block_badges_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -69,5 +69,8 @@ function xmldb_block_calendar_month_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,5 +54,8 @@ function xmldb_block_calendar_upcoming_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,5 +57,8 @@ function xmldb_block_completionstatus_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,5 +68,8 @@ function xmldb_block_course_summary_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -64,5 +64,8 @@ function xmldb_block_feedback_upgrade($oldversion, $block) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ class block_glossary_random extends block_base {
|
||||
*/
|
||||
protected $glossarycm = null;
|
||||
|
||||
/** @var stdClass course data. */
|
||||
public $course;
|
||||
|
||||
function init() {
|
||||
$this->title = get_string('pluginname','block_glossary_random');
|
||||
}
|
||||
|
||||
@@ -8,31 +8,29 @@ Feature: Add the glossary random block when main feature is disabled
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Course 1 | C1 | topics |
|
||||
And I am on the "C1" "course" page logged in as "admin"
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| glossary_random | Course | C1 | course-view-* | site-post |
|
||||
|
||||
Scenario: The glossary random block is displayed even when glossary module is disabled
|
||||
Given I turn editing mode on
|
||||
And I add the "Random glossary entry" block to the default region with:
|
||||
| Title | Random glossary entry |
|
||||
When I navigate to "Plugins > Activity modules > Manage activities" in site administration
|
||||
When I log in as "admin"
|
||||
And I navigate to "Plugins > Activity modules > Manage activities" in site administration
|
||||
And I click on "Disable Glossary" "icon" in the "Glossary" "table_row"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
Then I should see "Random glossary entry"
|
||||
Then "Random glossary entry" "block" should exist
|
||||
|
||||
Scenario: The glossary random block can be removed even when glossary module is disabled
|
||||
Given I turn editing mode on
|
||||
And I add the "Random glossary entry" block to the default region with:
|
||||
| Title | Random glossary entry |
|
||||
When I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I open the "Random glossary entry" blocks action menu
|
||||
And I click on "Delete Random glossary entry block" "link" in the "Random glossary entry" "block"
|
||||
And "Delete block?" "dialogue" should exist
|
||||
And I click on "Cancel" "button" in the "Delete block?" "dialogue"
|
||||
And I should see "Random glossary entry"
|
||||
And "Random glossary entry" "block" should exist
|
||||
When I navigate to "Plugins > Activity modules > Manage activities" in site administration
|
||||
And I click on "Disable Glossary" "icon" in the "Glossary" "table_row"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I open the "Random glossary entry" blocks action menu
|
||||
And I click on "Delete Random glossary entry block" "link" in the "Random glossary entry" "block"
|
||||
And "Delete block?" "dialogue" should exist
|
||||
And I click on "Delete" "button" in the "Delete block?" "dialogue"
|
||||
Then I should not see "Random glossary entry"
|
||||
Then "Random glossary entry" "block" should not exist
|
||||
|
||||
@@ -42,5 +42,8 @@ function xmldb_block_html_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -855,9 +855,6 @@ class block_tree extends block_list {
|
||||
$this->get_required_javascript();
|
||||
$this->get_content();
|
||||
$content = $output->tree_block_contents($this->content->items,array('class'=>'block_tree list'));
|
||||
if (isset($this->id) && !is_numeric($this->id)) {
|
||||
$content = $output->box($content, 'block_tree_box', $this->id);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +152,9 @@ class main implements renderable, templatable {
|
||||
*/
|
||||
private $customfieldvalue;
|
||||
|
||||
/** @var bool true if grouping selector should be shown, otherwise false. */
|
||||
protected $displaygroupingselector;
|
||||
|
||||
/**
|
||||
* main constructor.
|
||||
* Initialize the user preferences
|
||||
|
||||
@@ -81,5 +81,8 @@ function xmldb_block_myoverview_upgrade($oldversion) {
|
||||
// Automatically generated Moodle v4.1.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Automatically generated Moodle v4.2.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user