diff --git a/.github/workflows/close-pull-requests.yml b/.github/workflows/close-pull-requests.yml
index eb439f8380a3a..839af0b02422c 100644
--- a/.github/workflows/close-pull-requests.yml
+++ b/.github/workflows/close-pull-requests.yml
@@ -16,6 +16,7 @@ jobs:
with:
process-only: prs
close-pr: true
+ skip-closed-pr-comment: true
pr-comment: >
**Please, don't open pull requests via GitHub.**
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index cf983d5606f08..dd1a04048c748 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -16,7 +16,7 @@ on:
default: ''
env:
- php: 8.2
+ php: 8.3
jobs:
Grunt:
@@ -68,7 +68,7 @@ jobs:
db: mysqli
# PostgreSQL builds always run with the highest PHP supported version.
- os: ubuntu-22.04
- php: 8.2
+ php: 8.3
db: pgsql
steps:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index d2777d00268f5..4179ff8ad8d1a 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -8,7 +8,7 @@ on:
required: false
default: ''
env:
- php: 8.2
+ php: 8.3
jobs:
Grunt:
@@ -51,7 +51,7 @@ jobs:
matrix:
include:
- os: windows-latest
- php: 8.2
+ php: 8.3
# 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.
diff --git a/.grunt/tasks/javascript.js b/.grunt/tasks/javascript.js
index 34b57bc755b95..23c9caab58149 100644
--- a/.grunt/tasks/javascript.js
+++ b/.grunt/tasks/javascript.js
@@ -21,7 +21,7 @@
*/
/**
- * Function to generate the destination for the uglify task
+ * Function to generate the destination for the minification task
* (e.g. build/file.min.js). This function will be passed to
* the rename property of files array when building dynamically:
* http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
@@ -60,7 +60,6 @@ module.exports = grunt => {
grunt.registerTask('js', ['amd', 'yui']);
// Register NPM tasks.
- grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-rollup');
@@ -104,6 +103,7 @@ module.exports = grunt => {
// The queue runner will run the next `size` items in the queue.
const runQueue = (size = 1) => {
queue.splice(0, size).forEach(resolve => {
+ grunt.log.debug(`Item resolved. Kicking off next one.`);
resolve();
});
};
@@ -113,15 +113,17 @@ module.exports = grunt => {
// The options hook is run in parallel.
// We can return an unresolved Promise which is queued for later resolution.
- options: async() => {
+ options: async(options) => {
return new Promise(resolve => {
queue.push(resolve);
startQueue();
+ return options;
});
},
// When an item in the queue completes, start the next item in the queue.
- buildEnd: () => {
+ generateBundle: (options, bundle) => {
+ grunt.log.debug(`Finished output phase for ${Object.keys(bundle).join(', ')}`);
runQueue();
},
};
@@ -155,16 +157,6 @@ module.exports = grunt => {
],
presets: [
['@babel/preset-env', {
- targets: {
- browsers: [
- ">0.3%",
- "last 2 versions",
- "not ie >= 0",
- "not op_mini all",
- "not Opera > 0",
- "not dead"
- ]
- },
modules: false,
useBuiltIns: false
}]
diff --git a/.grunt/tasks/jsdoc.js b/.grunt/tasks/jsdoc.js
index e2f0680d17beb..e4ea713e76caf 100644
--- a/.grunt/tasks/jsdoc.js
+++ b/.grunt/tasks/jsdoc.js
@@ -20,17 +20,33 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-module.exports = grunt => {
- // Project configuration.
- grunt.config.merge({
- jsdoc: {
- dist: {
- options: {
- configure: ".grunt/jsdoc/jsdoc.conf.js",
- },
- },
- },
- });
+module.exports = (grunt) => {
+ const path = require('path');
+
+ grunt.registerTask('jsdoc', 'Generate JavaScript documentation using jsdoc', function() {
+ const done = this.async();
+ const configuration = path.resolve('.grunt/jsdoc/jsdoc.conf.js');
- grunt.loadNpmTasks('grunt-jsdoc');
+ grunt.util.spawn({
+ cmd: 'jsdoc',
+ args: [
+ '--configure',
+ configuration,
+ ]
+ }, function(error, result, code) {
+ if (result.stdout) {
+ grunt.log.write(result.stdout);
+ }
+
+ if (result.stderr) {
+ grunt.log.error(result.stderr);
+ }
+ if (error) {
+ grunt.fail.fatal(`JSDoc failed with error code ${code}`);
+ } else {
+ grunt.log.write('JSDoc completed successfully'.green);
+ }
+ done();
+ });
+ });
};
diff --git a/.grunt/tasks/stylelint.js b/.grunt/tasks/stylelint.js
index 0891d4231418f..864e46151d150 100644
--- a/.grunt/tasks/stylelint.js
+++ b/.grunt/tasks/stylelint.js
@@ -29,6 +29,7 @@ module.exports = grunt => {
// Use a fully-qualified path.
src: files,
options: {
+ quietDeprecationWarnings: true,
configOverrides: {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
@@ -45,7 +46,10 @@ module.exports = grunt => {
return {
stylelint: {
scss: {
- options: {syntax: 'scss'},
+ options: {
+ quietDeprecationWarnings: true,
+ customSyntax: 'postcss-scss',
+ },
src: files,
},
},
diff --git a/.nvmrc b/.nvmrc
index 53d838af2152f..9de2256827aef 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-lts/gallium
+lts/iron
diff --git a/.stylelintrc b/.stylelintrc
index ae818b0bf39a3..c3c4a4ad730c0 100644
--- a/.stylelintrc
+++ b/.stylelintrc
@@ -1,9 +1,14 @@
{
+ "customSyntax": "postcss-scss",
"plugins": [
"stylelint-csstree-validator"
],
"rules": {
- "csstree/validator": true,
+ "csstree/validator": {
+ "syntaxExtensions": [
+ "sass"
+ ]
+ },
"at-rule-empty-line-before": [ "always",
{"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
],
@@ -45,7 +50,7 @@
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
- "function-url-scheme-blacklist": ["data"],
+ "function-url-scheme-disallowed-list": ["data"],
"function-whitespace-after": "always",
"indentation": 4,
"keyframe-declaration-no-important": true,
@@ -84,12 +89,19 @@
"selector-type-no-unknown": true,
"string-no-newline": true,
"time-min-milliseconds": 100,
- "unit-blacklist": ["pt"],
+ "unit-disallowed-list": ["pt"],
"unit-case": "lower",
"unit-no-unknown": true,
"value-keyword-case": ["lower", {"ignoreKeywords": ["/(@|$)/"]}],
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
- }
+ },
+ "overrides": [
+ {
+ "files": ["**/yui/**/*.css"],
+ "rules": {
+ }
+ }
+ ]
}
diff --git a/admin/amd/build/bulk_user_actions.min.js b/admin/amd/build/bulk_user_actions.min.js
new file mode 100644
index 0000000000000..df8e7b09bb03a
--- /dev/null
+++ b/admin/amd/build/bulk_user_actions.min.js
@@ -0,0 +1,10 @@
+define("core_admin/bulk_user_actions",["exports","core_reportbuilder/local/selectors","core_table/local/dynamic/events","core_form/changechecker","core/custom_interaction_events","jquery"],(function(_exports,reportSelectors,tableEvents,FormChangeChecker,CustomEvents,_jquery){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
+/**
+ * Add bulk actions to the users list report
+ *
+ * @module core_admin/bulk_user_actions
+ * @copyright 2024 Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,reportSelectors=_interopRequireWildcard(reportSelectors),tableEvents=_interopRequireWildcard(tableEvents),FormChangeChecker=_interopRequireWildcard(FormChangeChecker),CustomEvents=_interopRequireWildcard(CustomEvents),_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};const Selectors_bulkActionsForm="form#user-bulk-action-form",Selectors_userReportWrapper='[data-region="report-user-list-wrapper"]',Selectors_checkbox='input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',Selectors_masterCheckbox='input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',Selectors_checkedRows='[data-togglegroup="report-select-all"][data-toggle="slave"]:checked';_exports.init=()=>{var _userBulkForm$closest;const userBulkForm=document.querySelector(Selectors_bulkActionsForm),userReport=null==userBulkForm||null===(_userBulkForm$closest=userBulkForm.closest(Selectors_userReportWrapper))||void 0===_userBulkForm$closest?void 0:_userBulkForm$closest.querySelector(reportSelectors.regions.report);if(!userBulkForm||!userReport)return;const actionSelect=userBulkForm.querySelector("select");CustomEvents.define(actionSelect,[CustomEvents.events.accessibleChange]),(0,_jquery.default)(actionSelect).on(CustomEvents.events.accessibleChange,(event=>{if(event.target.value&&"0"!=="".concat(event.target.value)){const e=new Event("submit",{cancelable:!0});userBulkForm.dispatchEvent(e),e.defaultPrevented||(FormChangeChecker.markFormSubmitted(userBulkForm),userBulkForm.submit())}}));const updateUserIds=()=>{const selectedUsers=[...userReport.querySelectorAll(Selectors_checkedRows)],selectedUserIds=selectedUsers.map((check=>parseInt(check.value)));userBulkForm.querySelector('[name="userids"]').value=selectedUserIds.join(","),actionSelect.disabled=0===selectedUsers.length;const selectedUsersNames=selectedUsers.map((check=>document.querySelector('label[for="'.concat(check.id,'"]')).textContent));userBulkForm.data={userids:selectedUserIds,usernames:selectedUsersNames}};updateUserIds(),document.addEventListener("change",(event=>{(event.target.matches(Selectors_checkbox)||event.target.matches(Selectors_masterCheckbox))&&userReport.contains(event.target)&&updateUserIds()})),document.addEventListener(tableEvents.tableContentRefreshed,(event=>{userReport.contains(event.target)&&updateUserIds()}))}}));
+
+//# sourceMappingURL=bulk_user_actions.min.js.map
\ No newline at end of file
diff --git a/admin/amd/build/bulk_user_actions.min.js.map b/admin/amd/build/bulk_user_actions.min.js.map
new file mode 100644
index 0000000000000..84606bc2486b2
--- /dev/null
+++ b/admin/amd/build/bulk_user_actions.min.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"bulk_user_actions.min.js","sources":["../src/bulk_user_actions.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Add bulk actions to the users list report\n *\n * @module core_admin/bulk_user_actions\n * @copyright 2024 Marina Glancy\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as reportSelectors from 'core_reportbuilder/local/selectors';\nimport * as tableEvents from 'core_table/local/dynamic/events';\nimport * as FormChangeChecker from 'core_form/changechecker';\nimport * as CustomEvents from 'core/custom_interaction_events';\nimport jQuery from 'jquery';\n\nconst Selectors = {\n bulkActionsForm: 'form#user-bulk-action-form',\n userReportWrapper: '[data-region=\"report-user-list-wrapper\"]',\n checkbox: 'input[type=\"checkbox\"][data-togglegroup=\"report-select-all\"][data-toggle=\"slave\"]',\n masterCheckbox: 'input[type=\"checkbox\"][data-togglegroup=\"report-select-all\"][data-toggle=\"master\"]',\n checkedRows: '[data-togglegroup=\"report-select-all\"][data-toggle=\"slave\"]:checked',\n};\n\n/**\n * Initialise module\n */\nexport const init = () => {\n\n const userBulkForm = document.querySelector(Selectors.bulkActionsForm);\n const userReport = userBulkForm?.closest(Selectors.userReportWrapper)?.querySelector(reportSelectors.regions.report);\n if (!userBulkForm || !userReport) {\n return;\n }\n const actionSelect = userBulkForm.querySelector('select');\n CustomEvents.define(actionSelect, [CustomEvents.events.accessibleChange]);\n\n jQuery(actionSelect).on(CustomEvents.events.accessibleChange, event => {\n if (event.target.value && `${event.target.value}` !== \"0\") {\n const e = new Event('submit', {cancelable: true});\n userBulkForm.dispatchEvent(e);\n if (!e.defaultPrevented) {\n FormChangeChecker.markFormSubmitted(userBulkForm);\n userBulkForm.submit();\n }\n }\n });\n\n // Every time the checkboxes in the report are changed, update the list of users in the form values\n // and enable/disable the action select.\n const updateUserIds = () => {\n const selectedUsers = [...userReport.querySelectorAll(Selectors.checkedRows)];\n const selectedUserIds = selectedUsers.map(check => parseInt(check.value));\n userBulkForm.querySelector('[name=\"userids\"]').value = selectedUserIds.join(',');\n actionSelect.disabled = selectedUsers.length === 0;\n const selectedUsersNames = selectedUsers.map(check => document.querySelector(`label[for=\"${check.id}\"]`).textContent);\n // Add the user ids and names to the form data attributes so they can be available from the\n // other JS modules that listen to the form submit event.\n userBulkForm.data = {userids: selectedUserIds, usernames: selectedUsersNames};\n };\n\n updateUserIds();\n\n document.addEventListener('change', event => {\n // When checkboxes are checked next to individual users or the master toggle (Select all/none).\n if ((event.target.matches(Selectors.checkbox) || event.target.matches(Selectors.masterCheckbox))\n && userReport.contains(event.target)) {\n updateUserIds();\n }\n });\n\n document.addEventListener(tableEvents.tableContentRefreshed, event => {\n // When the report contents is updated (i.e. page is changed, filters applied, etc).\n if (userReport.contains(event.target)) {\n updateUserIds();\n }\n });\n};\n"],"names":["Selectors","userBulkForm","document","querySelector","userReport","closest","_userBulkForm$closest","reportSelectors","regions","report","actionSelect","CustomEvents","define","events","accessibleChange","on","event","target","value","e","Event","cancelable","dispatchEvent","defaultPrevented","FormChangeChecker","markFormSubmitted","submit","updateUserIds","selectedUsers","querySelectorAll","selectedUserIds","map","check","parseInt","join","disabled","length","selectedUsersNames","id","textContent","data","userids","usernames","addEventListener","matches","contains","tableEvents","tableContentRefreshed"],"mappings":";;;;;;;0WA6BMA,0BACe,6BADfA,4BAEiB,2CAFjBA,mBAGQ,oFAHRA,yBAIc,qFAJdA,sBAKW,oFAMG,qCAEVC,aAAeC,SAASC,cAAcH,2BACtCI,WAAaH,MAAAA,4CAAAA,aAAcI,QAAQL,qEAAtBM,sBAAoDH,cAAcI,gBAAgBC,QAAQC,YACxGR,eAAiBG,wBAGhBM,aAAeT,aAAaE,cAAc,UAChDQ,aAAaC,OAAOF,aAAc,CAACC,aAAaE,OAAOC,uCAEhDJ,cAAcK,GAAGJ,aAAaE,OAAOC,kBAAkBE,WACtDA,MAAMC,OAAOC,OAAqC,MAA5B,UAAGF,MAAMC,OAAOC,OAAiB,OACjDC,EAAI,IAAIC,MAAM,SAAU,CAACC,YAAY,IAC3CpB,aAAaqB,cAAcH,GACtBA,EAAEI,mBACHC,kBAAkBC,kBAAkBxB,cACpCA,aAAayB,oBAOnBC,cAAgB,WACZC,cAAgB,IAAIxB,WAAWyB,iBAAiB7B,wBAChD8B,gBAAkBF,cAAcG,KAAIC,OAASC,SAASD,MAAMd,SAClEjB,aAAaE,cAAc,oBAAoBe,MAAQY,gBAAgBI,KAAK,KAC5ExB,aAAayB,SAAoC,IAAzBP,cAAcQ,aAChCC,mBAAqBT,cAAcG,KAAIC,OAAS9B,SAASC,mCAA4B6B,MAAMM,UAAQC,cAGzGtC,aAAauC,KAAO,CAACC,QAASX,gBAAiBY,UAAWL,qBAG9DV,gBAEAzB,SAASyC,iBAAiB,UAAU3B,SAE3BA,MAAMC,OAAO2B,QAAQ5C,qBAAuBgB,MAAMC,OAAO2B,QAAQ5C,4BAC3DI,WAAWyC,SAAS7B,MAAMC,SACjCU,mBAIRzB,SAASyC,iBAAiBG,YAAYC,uBAAuB/B,QAErDZ,WAAWyC,SAAS7B,MAAMC,SAC1BU"}
\ No newline at end of file
diff --git a/admin/amd/src/bulk_user_actions.js b/admin/amd/src/bulk_user_actions.js
new file mode 100644
index 0000000000000..6e1a07565c3ca
--- /dev/null
+++ b/admin/amd/src/bulk_user_actions.js
@@ -0,0 +1,91 @@
+// 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 .
+
+/**
+ * Add bulk actions to the users list report
+ *
+ * @module core_admin/bulk_user_actions
+ * @copyright 2024 Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+import * as reportSelectors from 'core_reportbuilder/local/selectors';
+import * as tableEvents from 'core_table/local/dynamic/events';
+import * as FormChangeChecker from 'core_form/changechecker';
+import * as CustomEvents from 'core/custom_interaction_events';
+import jQuery from 'jquery';
+
+const Selectors = {
+ bulkActionsForm: 'form#user-bulk-action-form',
+ userReportWrapper: '[data-region="report-user-list-wrapper"]',
+ checkbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',
+ masterCheckbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',
+ checkedRows: '[data-togglegroup="report-select-all"][data-toggle="slave"]:checked',
+};
+
+/**
+ * Initialise module
+ */
+export const init = () => {
+
+ const userBulkForm = document.querySelector(Selectors.bulkActionsForm);
+ const userReport = userBulkForm?.closest(Selectors.userReportWrapper)?.querySelector(reportSelectors.regions.report);
+ if (!userBulkForm || !userReport) {
+ return;
+ }
+ const actionSelect = userBulkForm.querySelector('select');
+ CustomEvents.define(actionSelect, [CustomEvents.events.accessibleChange]);
+
+ jQuery(actionSelect).on(CustomEvents.events.accessibleChange, event => {
+ if (event.target.value && `${event.target.value}` !== "0") {
+ const e = new Event('submit', {cancelable: true});
+ userBulkForm.dispatchEvent(e);
+ if (!e.defaultPrevented) {
+ FormChangeChecker.markFormSubmitted(userBulkForm);
+ userBulkForm.submit();
+ }
+ }
+ });
+
+ // Every time the checkboxes in the report are changed, update the list of users in the form values
+ // and enable/disable the action select.
+ const updateUserIds = () => {
+ const selectedUsers = [...userReport.querySelectorAll(Selectors.checkedRows)];
+ const selectedUserIds = selectedUsers.map(check => parseInt(check.value));
+ userBulkForm.querySelector('[name="userids"]').value = selectedUserIds.join(',');
+ actionSelect.disabled = selectedUsers.length === 0;
+ const selectedUsersNames = selectedUsers.map(check => document.querySelector(`label[for="${check.id}"]`).textContent);
+ // Add the user ids and names to the form data attributes so they can be available from the
+ // other JS modules that listen to the form submit event.
+ userBulkForm.data = {userids: selectedUserIds, usernames: selectedUsersNames};
+ };
+
+ updateUserIds();
+
+ document.addEventListener('change', event => {
+ // When checkboxes are checked next to individual users or the master toggle (Select all/none).
+ if ((event.target.matches(Selectors.checkbox) || event.target.matches(Selectors.masterCheckbox))
+ && userReport.contains(event.target)) {
+ updateUserIds();
+ }
+ });
+
+ document.addEventListener(tableEvents.tableContentRefreshed, event => {
+ // When the report contents is updated (i.e. page is changed, filters applied, etc).
+ if (userReport.contains(event.target)) {
+ updateUserIds();
+ }
+ });
+};
diff --git a/admin/classes/privacy/provider.php b/admin/classes/privacy/provider.php
index 118308d59cfb9..a2a277db097c4 100644
--- a/admin/classes/privacy/provider.php
+++ b/admin/classes/privacy/provider.php
@@ -35,7 +35,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
- public static function get_reason() : string {
+ public static function get_reason(): string {
return 'privacy:metadata';
}
}
diff --git a/admin/classes/reportbuilder/local/systemreports/users.php b/admin/classes/reportbuilder/local/systemreports/users.php
index 680b1c5f047b0..b3ae4c5643468 100644
--- a/admin/classes/reportbuilder/local/systemreports/users.php
+++ b/admin/classes/reportbuilder/local/systemreports/users.php
@@ -67,6 +67,13 @@ protected function initialise(): void {
$this->add_base_fields("{$entityuseralias}.id, {$entityuseralias}.confirmed, {$entityuseralias}.mnethostid,
{$entityuseralias}.suspended, {$entityuseralias}.username, " . implode(', ', $fullnamefields));
+ if ($this->get_parameter('withcheckboxes', false, PARAM_BOOL)) {
+ $canviewfullnames = has_capability('moodle/site:viewfullnames', \context_system::instance());
+ $this->set_checkbox_toggleall(static function(\stdClass $row) use ($canviewfullnames): array {
+ return [$row->id, fullname($row, $canviewfullnames)];
+ });
+ }
+
$paramguest = database::generate_param_name();
$this->add_base_condition_sql("{$entityuseralias}.deleted <> 1 AND {$entityuseralias}.id <> :{$paramguest}",
[$paramguest => $CFG->siteguest]);
diff --git a/admin/classes/table/hook_list_table.php b/admin/classes/table/hook_list_table.php
index 1f95002703e88..1ffc092708b69 100644
--- a/admin/classes/table/hook_list_table.php
+++ b/admin/classes/table/hook_list_table.php
@@ -154,11 +154,7 @@ protected function col_deprecates(stdClass $row): string {
return '';
}
- $rc = new \ReflectionClass($row->classname);
- if (!$rc->implementsInterface(\core\hook\deprecated_callback_replacement::class)) {
- return '';
- }
- $deprecates = call_user_func([$row->classname, 'get_deprecated_plugin_callbacks']);
+ $deprecates = \core\hook\manager::get_replaced_callbacks($row->classname);
if (count($deprecates) === 0) {
return '';
}
diff --git a/admin/environment.xml b/admin/environment.xml
index 45d774ed111ef..4925aafb1c80d 100644
--- a/admin/environment.xml
+++ b/admin/environment.xml
@@ -3939,6 +3939,7 @@
+
@@ -4128,6 +4129,7 @@
+
diff --git a/admin/presets/classes/helper.php b/admin/presets/classes/helper.php
index 99d41581cd785..b081c49b1e5de 100644
--- a/admin/presets/classes/helper.php
+++ b/admin/presets/classes/helper.php
@@ -301,14 +301,12 @@ public static function create_default_presets(): void {
// Set Activity chooser tabs to the default value ("Starred, Recommended, All, Activities, Resources").
static::add_item($presetid, 'activitychoosertabmode', '3');
- // Modules: Enable chat, database, external tool (lti), IMS content package (imscp), lesson, SCORM, survey, wiki, workshop.
- static::add_plugin($presetid, 'mod', 'chat', true);
+ // Modules: Enable database, external tool (lti), IMS content package (imscp), lesson, SCORM, wiki, workshop.
static::add_plugin($presetid, 'mod', 'data', true);
static::add_plugin($presetid, 'mod', 'lti', true);
static::add_plugin($presetid, 'mod', 'imscp', true);
static::add_plugin($presetid, 'mod', 'lesson', true);
static::add_plugin($presetid, 'mod', 'scorm', true);
- static::add_plugin($presetid, 'mod', 'survey', true);
static::add_plugin($presetid, 'mod', 'wiki', true);
static::add_plugin($presetid, 'mod', 'workshop', true);
diff --git a/admin/presets/classes/privacy/provider.php b/admin/presets/classes/privacy/provider.php
index 81b955d972f55..11a719f649e13 100644
--- a/admin/presets/classes/privacy/provider.php
+++ b/admin/presets/classes/privacy/provider.php
@@ -41,7 +41,7 @@ class provider implements
* @param collection $collection A list of information about this component
* @return collection The collection object filled out with information about this component.
*/
- public static function get_metadata(collection $collection) : collection {
+ public static function get_metadata(collection $collection): collection {
// These tables are really data about site configuration and not user data.
// The adminpresets includes information about which user performed a configuration change using the admin_presets
@@ -74,7 +74,7 @@ public static function get_metadata(collection $collection) : collection {
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
- public static function get_contexts_for_userid(int $userid) : contextlist {
+ public static function get_contexts_for_userid(int $userid): contextlist {
return new contextlist();
}
diff --git a/admin/presets/tests/helper_test.php b/admin/presets/tests/helper_test.php
index 0a4c6ed05954c..f0e39c1ed9782 100644
--- a/admin/presets/tests/helper_test.php
+++ b/admin/presets/tests/helper_test.php
@@ -344,7 +344,7 @@ public function change_default_preset_provider(): array {
],
'plugins' => [
'assign' => 1,
- 'chat' => 1,
+ 'book' => 1,
'data' => 1,
'lesson' => 1,
],
diff --git a/admin/renderer.php b/admin/renderer.php
index 7e7ef8d30bc89..184a7ba759a2b 100644
--- a/admin/renderer.php
+++ b/admin/renderer.php
@@ -617,7 +617,7 @@ public function cron_overdue_warning($cronoverdue) {
* @param bool $croninfrequent
* @return string HTML to output.
*/
- public function cron_infrequent_warning(bool $croninfrequent) : string {
+ public function cron_infrequent_warning(bool $croninfrequent): string {
global $CFG;
if (!$croninfrequent) {
diff --git a/admin/roles/classes/allow_role_page.php b/admin/roles/classes/allow_role_page.php
index b32946b456a8a..b1c708912ea4e 100644
--- a/admin/roles/classes/allow_role_page.php
+++ b/admin/roles/classes/allow_role_page.php
@@ -99,7 +99,7 @@ public function process_submission() {
* @param int $fromroleid
* @param int $targetroleid
*/
- protected abstract function set_allow($fromroleid, $targetroleid);
+ abstract protected function set_allow($fromroleid, $targetroleid);
/**
* Load the current allows from the database.
@@ -183,11 +183,11 @@ public function get_table() {
* Snippet of text displayed above the table, telling the admin what to do.
* @return string
*/
- public abstract function get_intro_text();
+ abstract public function get_intro_text();
/**
* Returns the allow class respective event class name.
* @return string
*/
- protected abstract function get_eventclass();
+ abstract protected function get_eventclass();
}
diff --git a/admin/roles/classes/capability_table_base.php b/admin/roles/classes/capability_table_base.php
index ab45e085861e5..c95cf363c0b9f 100644
--- a/admin/roles/classes/capability_table_base.php
+++ b/admin/roles/classes/capability_table_base.php
@@ -142,12 +142,12 @@ protected function print_heading_row($capability) {
/**
* For subclasses to override, output header cells, after the initial capability one.
*/
- protected abstract function add_header_cells();
+ abstract protected function add_header_cells();
/**
* For subclasses to override, return the number of cells that add_header_cells/add_row_cells output.
*/
- protected abstract function num_extra_columns();
+ abstract protected function num_extra_columns();
/**
* For subclasses to override. Allows certain capabilties
@@ -191,5 +191,5 @@ protected function get_row_attributes($capability) {
* @param stdClass $capability the capability this row relates to.
* @return string html of row cells
*/
- protected abstract function add_row_cells($capability);
+ abstract protected function add_row_cells($capability);
}
diff --git a/admin/roles/classes/capability_table_with_risks.php b/admin/roles/classes/capability_table_with_risks.php
index 4e597f472f4da..9ff7da475a508 100644
--- a/admin/roles/classes/capability_table_with_risks.php
+++ b/admin/roles/classes/capability_table_with_risks.php
@@ -84,7 +84,7 @@ protected function load_current_permissions() {
}
}
- protected abstract function load_parent_permissions();
+ abstract protected function load_parent_permissions();
/**
* Update $this->permissions based on submitted data, while making a list of
@@ -156,7 +156,7 @@ protected function get_row_classes($capability) {
return $rowclasses;
}
- protected abstract function add_permission_cells($capability);
+ abstract protected function add_permission_cells($capability);
protected function add_row_cells($capability) {
$cells = $this->add_permission_cells($capability);
diff --git a/admin/roles/classes/define_role_table_advanced.php b/admin/roles/classes/define_role_table_advanced.php
index f230e0eb905c7..632cb3e39a6a2 100644
--- a/admin/roles/classes/define_role_table_advanced.php
+++ b/admin/roles/classes/define_role_table_advanced.php
@@ -645,7 +645,7 @@ protected function get_role_risks_info() {
protected function print_field($name, $caption, $field, $helpicon = null) {
global $OUTPUT;
// Attempt to generate HTML like formslib.
- echo '