Compare commits
309 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b69c11978 | |||
| 2d628ba8d6 | |||
| 3528887bb6 | |||
| 217a32f033 | |||
| d24c201b6d | |||
| 4d9960ace2 | |||
| 4e1c4f4483 | |||
| b4e7d5300a | |||
| 313d44f83a | |||
| 6a6f5b79dd | |||
| f3c335b376 | |||
| 5eb91a54c3 | |||
| 1e72ef978a | |||
| 28ccae3b7a | |||
| f06b222aa8 | |||
| a4aeb20a30 | |||
| b50964d2e2 | |||
| 2ea89b98a7 | |||
| 833bc53bbb | |||
| 5123d2bf53 | |||
| acd82d3a86 | |||
| 152bbd76c5 | |||
| 02df248fbd | |||
| f5844e80fd | |||
| a789bf5b24 | |||
| ff5fc3820a | |||
| 66dcb1683b | |||
| 9cdafb6cad | |||
| 89c59f32cf | |||
| 8280476728 | |||
| 4fc9c3bba1 | |||
| 74f1a285a1 | |||
| d9ae9e51cd | |||
| cd42aa554f | |||
| e8ea4916e9 | |||
| d1f75e4dce | |||
| 1b54b120ad | |||
| 3c5413f02a | |||
| 4ea254faf2 | |||
| d71ada1952 | |||
| 29efbedc8b | |||
| 8ea2421cd4 | |||
| 1361e6ad92 | |||
| 3387060fe1 | |||
| 5d27f595d7 | |||
| 6f2d09dc5a | |||
| e101b6f195 | |||
| 934d8a2866 | |||
| 6a7668e350 | |||
| d2bacb04ff | |||
| 77a0f1b129 | |||
| ca841d1489 | |||
| c2216eefa6 | |||
| 241da816db | |||
| 18302e1244 | |||
| 2080ba7c83 | |||
| b99d68087d | |||
| 93d95cf1fe | |||
| 13a6018b6d | |||
| ee507d22ec | |||
| 145317b2b3 | |||
| c3fdfc996c | |||
| 6ee2865fcc | |||
| 4943d24d50 | |||
| 64b8061180 | |||
| b24414554f | |||
| 325ca6568b | |||
| cd072308e5 | |||
| 3e0ad5831a | |||
| a5430f1022 | |||
| 46fca91bc4 | |||
| f8b463e394 | |||
| 717e049627 | |||
| 6e286481e0 | |||
| 1cf0f78b9a | |||
| d95ab775ac | |||
| 56a3828cf7 | |||
| 4ecd652189 | |||
| 9c4b8bf7e8 | |||
| c380811bb2 | |||
| 3e175706ff | |||
| db3bc708c4 | |||
| 87b3be343e | |||
| a25f2d0d7e | |||
| 0eb65f27ba | |||
| a4dfd67aed | |||
| 3a5820f3c4 | |||
| a9abcf1af7 | |||
| 72f4f8ec7c | |||
| 9fd77db89a | |||
| c6a1770682 | |||
| 3e4ba8af5c | |||
| dcb0de7c92 | |||
| e2c8f3db7c | |||
| b7b2097f50 | |||
| 0dbc7187ff | |||
| 7e1aa845c7 | |||
| 810cffb702 | |||
| 5271bd9237 | |||
| f84d8e3c37 | |||
| a3a3fd451c | |||
| 52d5ebbb21 | |||
| c72b7b7edc | |||
| c4960a2adf | |||
| 510bf00643 | |||
| d3fca5e689 | |||
| 1be732e913 | |||
| d2f55155a8 | |||
| 430c7ff4e7 | |||
| 181cab2fbd | |||
| f4f0207693 | |||
| ad8a10e7b6 | |||
| 9d822d41d8 | |||
| e89ed4b463 | |||
| 5db1ac4e98 | |||
| c22b39a650 | |||
| 9d64ad1416 | |||
| 11816b9e41 | |||
| 178aa05227 | |||
| 9f2e81004c | |||
| 0b7102abcc | |||
| fe16fea153 | |||
| 86f9ffc274 | |||
| a439461f03 | |||
| 5c15c1f211 | |||
| 86d02a9239 | |||
| 68706da86a | |||
| 296fd70a2c | |||
| 0c448af668 | |||
| 1f7bb3a50d | |||
| 744e1dbaea | |||
| 5b47024f13 | |||
| dcf4a4629b | |||
| bb7cce1e56 | |||
| 27cc23ca7a | |||
| e8123832fb | |||
| 6b47dc3b29 | |||
| a77b23cdb7 | |||
| 7708594e89 | |||
| 1dda343f05 | |||
| 4f19d454ea | |||
| 24c009f222 | |||
| 5556693437 | |||
| b874e20b55 | |||
| 06383b0b8a | |||
| 4979a5e988 | |||
| 76ce30ca98 | |||
| 1e54868139 | |||
| a33d1c8903 | |||
| c5213c103b | |||
| 4ce5c57547 | |||
| 7496e9df75 | |||
| fe094a3705 | |||
| 93bd773ee9 | |||
| 0d20d1e8aa | |||
| 361ebe960b | |||
| 0d5d3a0c49 | |||
| 4d94f7e677 | |||
| 6f68abf715 | |||
| ac21fa9a1c | |||
| f954848667 | |||
| a42c52bf4e | |||
| 987542f609 | |||
| 959b58e132 | |||
| be5cf43aa4 | |||
| de182b9a22 | |||
| c48f443c32 | |||
| fc67298a27 | |||
| c3db3298dd | |||
| 6bb2b9aa69 | |||
| 187a7f7ac5 | |||
| 6b24f59302 | |||
| 797a20a597 | |||
| 7a1e9ad82c | |||
| bd40bc0341 | |||
| 398fc9b0d3 | |||
| 2a69a46a71 | |||
| 41b48aeea5 | |||
| 3a544f384b | |||
| d8f2ead786 | |||
| 50f06cb2be | |||
| d4abc697b8 | |||
| 10c1a7de42 | |||
| dc444f4634 | |||
| 151de4586d | |||
| 52890694bf | |||
| 95f073453b | |||
| 6661a3eb45 | |||
| 0f8f164a07 | |||
| 4cc96c42fa | |||
| 208c9fb5af | |||
| 8884da3d8b | |||
| e0f34d5049 | |||
| 09e171c522 | |||
| 4426e21204 | |||
| fb7d1b34ef | |||
| 32bb535cb6 | |||
| dd3b92545e | |||
| e572943d21 | |||
| 2d2b2e3244 | |||
| e03c52acbe | |||
| c503238978 | |||
| bc5c812db3 | |||
| d7734740b2 | |||
| ba38d916be | |||
| e7c70fd2c0 | |||
| fa309d0650 | |||
| 1efd88b2c8 | |||
| 20ac0d1626 | |||
| 40ee69ea8b | |||
| 87d5f8eb0f | |||
| 05c53f2c44 | |||
| 1b9bcbf19d | |||
| a3ed6cea5f | |||
| f2dd9867ab | |||
| bbd49c9533 | |||
| bc82295f6a | |||
| 2e1118fa62 | |||
| 272a458099 | |||
| 2370255e4c | |||
| 9cf6e7128e | |||
| ed29852851 | |||
| a7e9836173 | |||
| add1d29339 | |||
| 68dc955abe | |||
| 258fe36e10 | |||
| 76fde950c1 | |||
| d4681259bc | |||
| e6dec9c0fb | |||
| 8b153fb67d | |||
| 1145b8f597 | |||
| 743fc68b4f | |||
| 9d801ab8a0 | |||
| b7f08d7ecc | |||
| 715ec40ad6 | |||
| 1d98d162a1 | |||
| d42189d71a | |||
| 7f5f04dbc2 | |||
| 82d90a8950 | |||
| e581bd6cde | |||
| 68cd224ef3 | |||
| afef05b07c | |||
| d9cd25c2fb | |||
| 960bc4e3c5 | |||
| cf06e4207f | |||
| 9f06111278 | |||
| a8bcb23134 | |||
| 5c96f74a06 | |||
| 7cc3d06276 | |||
| b00f1464a8 | |||
| 88393518f5 | |||
| 57e5cc1588 | |||
| a0efc27d31 | |||
| 0be376fdc0 | |||
| 8bf788a1bd | |||
| 864a2ea990 | |||
| 73f10723b3 | |||
| be11ee3383 | |||
| fbb0fd952d | |||
| 0cc4492303 | |||
| dcc2d22a74 | |||
| 1c2503a6de | |||
| c86d6510ce | |||
| a8f889acbf | |||
| 5a07bcf871 | |||
| 12ac6ce86b | |||
| 2db281b197 | |||
| 805559cb48 | |||
| 19ed64f2d9 | |||
| dcc115786d | |||
| 2ef01c0fdf | |||
| 2696f446ac | |||
| c45c98f6f2 | |||
| 181ecedb11 | |||
| 7e8efa870d | |||
| b363723f9a | |||
| e0ef5d0638 | |||
| 38250aec8e | |||
| 5475fb8a15 | |||
| 5384f872bb | |||
| eb3ee12852 | |||
| dded69ad15 | |||
| 2cfaa895aa | |||
| 60e176b50d | |||
| 530e06da6d | |||
| 4d9c6785ff | |||
| 1b8456dbb1 | |||
| 3e26150eae | |||
| 5cf31d7445 | |||
| 62238568a2 | |||
| 6e9e2be8f4 | |||
| 34f8f82288 | |||
| ac8b7e9f0a | |||
| b50c240ab5 | |||
| 189c4ce4de | |||
| e3840909f5 | |||
| 523b590711 | |||
| b391ed9941 | |||
| a5f92c041e | |||
| cfe0945ffb | |||
| 6989097a3c | |||
| 847f08dcd4 | |||
| 02430ee562 | |||
| a8e90aaae1 | |||
| fac0c27efb | |||
| a7e7cd71cb | |||
| 37be6bfa4d | |||
| d311cab0c0 | |||
| fb5a3dd643 |
@@ -1,12 +1,8 @@
|
||||
{
|
||||
'plugins': [
|
||||
'@babel',
|
||||
'babel',
|
||||
'promise',
|
||||
'jsdoc'
|
||||
],
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:promise/recommended'
|
||||
'jsdoc',
|
||||
],
|
||||
'env': {
|
||||
'browser': true,
|
||||
@@ -20,19 +16,42 @@
|
||||
'M': true,
|
||||
'Y': true
|
||||
},
|
||||
// Warn about unused eslint-disable statements.
|
||||
'reportUnusedDisableDirectives': true,
|
||||
'rules': {
|
||||
// See http://eslint.org/docs/rules/ for all rules and explanations of all
|
||||
// rules.
|
||||
|
||||
// === Possible Errors ===
|
||||
'comma-dangle': 'off',
|
||||
'no-compare-neg-zero': 'error',
|
||||
'no-cond-assign': 'error',
|
||||
'no-console': 'error',
|
||||
'no-constant-condition': 'error',
|
||||
'no-control-regex': 'error',
|
||||
'no-debugger': 'error',
|
||||
'no-dupe-args': 'error',
|
||||
'no-dupe-keys': 'error',
|
||||
'no-duplicate-case': 'error',
|
||||
'no-empty': 'warn',
|
||||
'no-empty-character-class': 'error',
|
||||
'no-ex-assign': 'error',
|
||||
'no-extra-boolean-cast': 'error',
|
||||
'no-extra-parens': 'off',
|
||||
'no-extra-semi': 'error',
|
||||
'no-func-assign': 'error',
|
||||
'no-inner-declarations': 'error',
|
||||
'no-invalid-regexp': 'error',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-obj-calls': 'error',
|
||||
'no-prototype-builtins': 'off',
|
||||
'no-regex-spaces': 'error',
|
||||
'no-sparse-arrays': 'error',
|
||||
'no-unexpected-multiline': 'error',
|
||||
'no-unreachable': 'warn',
|
||||
'no-unsafe-finally': 'error',
|
||||
'no-unsafe-negation': 'error',
|
||||
'use-isnan': 'error',
|
||||
'valid-jsdoc': ['warn', { 'requireReturn': false, 'requireParamDescription': false, 'requireReturnDescription': false }],
|
||||
'valid-typeof': 'error',
|
||||
|
||||
// === Best Practices ===
|
||||
// (these mostly match our jshint config)
|
||||
@@ -44,12 +63,15 @@
|
||||
'dot-notation': 'warn',
|
||||
'no-alert': 'warn',
|
||||
'no-caller': 'error',
|
||||
'no-case-declarations': 'error',
|
||||
'no-div-regex': 'error',
|
||||
'no-empty-pattern': 'error',
|
||||
'no-empty-function': 'warn',
|
||||
'no-eq-null': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-extend-native': 'error',
|
||||
'no-extra-bind': 'warn',
|
||||
'no-fallthrough': 'error',
|
||||
'no-floating-decimal': 'warn',
|
||||
'no-global-assign': 'warn',
|
||||
'no-implied-eval': 'error',
|
||||
@@ -61,22 +83,28 @@
|
||||
'no-multi-str': 'error',
|
||||
'no-new-func': 'error',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-octal': 'error',
|
||||
'no-octal-escape': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-redeclare': 'warn',
|
||||
'no-restricted-globals': ['error', { 'name': 'Notification' }],
|
||||
'no-return-assign': 'error',
|
||||
'no-script-url': 'error',
|
||||
'no-self-assign': 'error',
|
||||
'no-self-compare': 'error',
|
||||
'no-sequences': 'warn',
|
||||
'no-throw-literal': 'warn',
|
||||
'no-unmodified-loop-condition': 'error',
|
||||
'no-unused-expressions': 'error',
|
||||
'no-unused-labels': 'error',
|
||||
'no-useless-call': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
'no-with': 'error',
|
||||
'wrap-iife': ['error', 'any'],
|
||||
|
||||
// === Variables ===
|
||||
'no-delete-var': 'error',
|
||||
'no-undef': 'error',
|
||||
'no-undef-init': 'error',
|
||||
'no-unused-vars': ['error', { 'caughtErrors': 'none' }],
|
||||
|
||||
@@ -109,6 +137,8 @@
|
||||
'max-statements-per-line': ['warn', { max: 2 }],
|
||||
'new-cap': ['warn', { 'properties': false }],
|
||||
'new-parens': 'warn',
|
||||
'newline-after-var': 'off',
|
||||
'newline-before-return': 'off',
|
||||
'newline-per-chained-call': 'off',
|
||||
'no-array-constructor': 'off',
|
||||
'no-bitwise': 'error',
|
||||
@@ -116,6 +146,7 @@
|
||||
'no-inline-comments': 'off',
|
||||
'no-lonely-if': 'off',
|
||||
'no-mixed-operators': 'off',
|
||||
'no-mixed-spaces-and-tabs': 'error',
|
||||
'no-multiple-empty-lines': 'warn',
|
||||
'no-negated-condition': 'off',
|
||||
'no-nested-ternary': 'warn',
|
||||
@@ -137,6 +168,7 @@
|
||||
'padded-blocks': 'off',
|
||||
'quote-props': ['warn', 'as-needed', {'unnecessary': false, 'keywords': true, 'numbers': true}],
|
||||
'quotes': 'off',
|
||||
'require-jsdoc': 'warn',
|
||||
'semi': 'error',
|
||||
'semi-spacing': ['warn', {'before': false, 'after': true}],
|
||||
'sort-vars': 'off',
|
||||
@@ -149,19 +181,21 @@
|
||||
'unicode-bom': 'error',
|
||||
'wrap-regex': 'off',
|
||||
|
||||
// === Promises (override plugin:promise/recommended) ===
|
||||
// === Promises ===
|
||||
'promise/always-return': 'warn',
|
||||
'promise/no-return-wrap': 'warn',
|
||||
'promise/param-names': 'warn',
|
||||
'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail', 'always'], allowFinally: true}],
|
||||
'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail']}],
|
||||
'promise/no-native': 'warn',
|
||||
'promise/no-promise-in-callback': 'warn',
|
||||
'promise/no-callback-in-promise': 'warn',
|
||||
'promise/avoid-new': 'warn',
|
||||
|
||||
// === Deprecations ===
|
||||
"no-restricted-properties": ['warn', {
|
||||
'object': 'M',
|
||||
'property': 'str',
|
||||
'message': 'Use "core/str" module or M.util.get_string()'
|
||||
'message': 'Use AMD module "core/str" or M.util.get_string()'
|
||||
}],
|
||||
},
|
||||
overrides: [
|
||||
@@ -201,6 +235,7 @@
|
||||
parser: '@babel/eslint-parser',
|
||||
// Check AMD with some slightly stricter rules.
|
||||
rules: {
|
||||
'no-unused-vars': 'error',
|
||||
'no-implicit-globals': 'error',
|
||||
// Disable all of the rules that have babel versions.
|
||||
'new-cap': 'off',
|
||||
@@ -212,37 +247,65 @@
|
||||
'semi': 'off',
|
||||
'no-unused-expressions': 'off',
|
||||
// Enable all of the babel version of these rules.
|
||||
'@babel/new-cap': ['warn', { 'properties': false }],
|
||||
'babel/new-cap': ['warn', { 'properties': false }],
|
||||
// Not using this rule for the time being because it isn't
|
||||
// compatible with jQuery and ES6.
|
||||
'@babel/no-invalid-this': 'off',
|
||||
'@babel/object-curly-spacing': 'warn',
|
||||
'@babel/semi': 'error',
|
||||
'@babel/no-unused-expressions': 'error',
|
||||
'babel/no-invalid-this': 'off',
|
||||
'babel/object-curly-spacing': 'warn',
|
||||
// This is off in the original style int.
|
||||
'babel/quotes': 'off',
|
||||
'babel/semi': 'error',
|
||||
'babel/no-unused-expressions': 'error',
|
||||
// === Promises ===
|
||||
// We have Promise now that we're using ES6.
|
||||
'promise/no-native': 'off',
|
||||
'promise/avoid-new': 'off',
|
||||
|
||||
// === JSDocs ===
|
||||
'jsdoc/check-access': 'error',
|
||||
'jsdoc/check-alignment': 1, // Recommended.
|
||||
'jsdoc/check-param-names': 'error',
|
||||
'jsdoc/check-property-names': 'error',
|
||||
'jsdoc/empty-tags': 'error',
|
||||
'jsdoc/implements-on-classes': 'error',
|
||||
'jsdoc/multiline-blocks': 'error',
|
||||
'jsdoc/require-jsdoc': 'error',
|
||||
'jsdoc/require-param': 'error',
|
||||
'jsdoc/require-param-name': 'error',
|
||||
'jsdoc/require-param-type': 'error',
|
||||
'jsdoc/require-property': 'error',
|
||||
'jsdoc/require-property-name': 'error',
|
||||
'jsdoc/require-property-type': 'error'
|
||||
"jsdoc/check-access": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/check-alignment": 1, // Recommended.
|
||||
"jsdoc/check-param-names": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/check-property-names": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/empty-tags": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/implements-on-classes": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/multiline-blocks": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-jsdoc": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-param": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-param-name": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-param-type": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-property": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-property-name": [
|
||||
'error',
|
||||
],
|
||||
"jsdoc/require-property-type": [
|
||||
'error',
|
||||
],
|
||||
},
|
||||
parserOptions: {
|
||||
'sourceType': 'module',
|
||||
'requireConfigFile': false
|
||||
'requireConfigFile': false,
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
|
||||
|
||||
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
|
||||
|
||||
See CONTRIBUTING.md guidelines for how to contribute patches for Moodle. Thank you.
|
||||
|
||||
--
|
||||
@@ -1,6 +0,0 @@
|
||||
> [!IMPORTANT]
|
||||
> PLEASE DO NOT PUBLISH SECURITY FINDINGS PUBLICLY.
|
||||
|
||||
If you discover a potential security issue, please report it via our [Security Submission Form](https://moodle.org/security/report).
|
||||
|
||||
For more information about our security processes and responsible disclosure policy, see the [Security Procedures documentation](https://moodledev.io/general/development/process/security).
|
||||
@@ -1 +0,0 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1231.24 314.44" preserveAspectRatio="xMinYMid meet"><defs><style>.cls-1{fill:#f48020;}.cls-2,.cls-3{fill:#383738;stroke:#4a4a4c;}.cls-2{stroke-width:2.37px;}.cls-3{stroke-width:2.38px;}.cls-4{fill:#585858;}</style></defs><title>Moodle_Logo_UseonBlack_RGB</title><path class="cls-1" d="M1086.3,235.34a53.42,53.42,0,0,0,16.71,29q13.26,12.27,29.48,12.27,11.29,0,24.56-5.89,16.23-6.88,16.22-16.22l58-.49q-12.29,29-41.76,45.2-27.52,15.23-60.43,15.24-42.25,0-70-26.29t-27.75-68.54q0-43.73,27.75-69.51t72-25.8q48.15,0,75.17,31.94,25.07,29.47,25.06,79.1Zm89.91-33.91q-3.43-17.69-14.73-29-12.8-12.28-29.49-12.29-17.21,0-28.74,11.79t-15.47,29.48Z"/><path class="cls-1" d="M965.45,308.54V0h55V308.54Z"/><path class="cls-1" d="M892.69,308.54V290.36q-7.38,9.83-25.06,15.72a92.31,92.31,0,0,1-30,5.41q-39.31,0-63.13-27T750.7,217.65q0-39.3,23.34-65.84t62.15-26.53q43.71,0,56.5,23.58V0h53.55V308.54Zm0-102.68q0-14.75-14-28.26t-28.74-13.51q-21.12,0-33.41,17.2-10.8,15.24-10.8,37.33,0,21.63,10.8,36.85,12.29,17.71,33.41,17.69,12.78,0,27.76-12t15-24.81Z"/><path class="cls-1" d="M647,313.45q-41.77,0-69-26.53t-27.27-68.3q0-41.73,27.27-68.28t69-26.53q41.75,0,69.27,26.53t27.52,68.28q0,41.79-27.52,68.3T647,313.45ZM647,168q-19.89,0-30.58,15.07t-10.68,35.79q0,20.73,9.94,35.05,11.43,16.31,31.32,16.28t31.32-16.28q10.44-14.31,10.44-35.05t-9.94-35Q667.42,168,647,168Z"/><path class="cls-1" d="M448.07,313.45q-41.76,0-69-26.53t-27.27-68.3q0-41.73,27.27-68.28t69-26.53q41.74,0,69.28,26.53t27.5,68.28q0,41.79-27.5,68.3T448.07,313.45Zm0-145.43q-19.89,0-30.59,15.07t-10.69,35.79q0,20.73,9.94,35.05,11.43,16.31,31.34,16.28t31.32-16.28q10.42-14.31,10.44-35.05t-9.94-35Q468.45,168,448.07,168Z"/><path class="cls-1" d="M288.89,309.11V201q0-33.9-28-33.9t-28,33.9V309.11h-55V201q0-33.9-27.52-33.9-28,0-28,33.9V309.11h-55V194.65q0-35.37,24.56-53.54,21.61-16.22,58.46-16.22,37.35,0,55,19.16,15.23-19.16,55.51-19.16,36.86,0,58.45,16.22,24.57,18.16,24.57,53.54V309.11Z"/><path class="cls-2" d="M.76,145.76"/><path class="cls-3" d="M1.73,145.32"/><path class="cls-4" d="M173.86,116.85l55.08-40.1-.7-2.44C135,83.92,80.42,96.44,0,144.13l.73,2.38,21-.67c15.17.52,30.85,1.26,46,1.32-1,24.09.83,32.65.83,32.65,51.92,17.58,101.22,1.53,127.14-43.9A248.72,248.72,0,0,0,173.86,116.85Z"/><path class="cls-4" d="M113.78,110c-.3-1.08-2.23-1.48-4.28-.9a4.73,4.73,0,0,0-3.14,2.19c-18.53,5-49.16,13.72-70.73,21l-1.33.45c-16.68,5.61-24.73,8.49-25.22,12.55-2.29,18.44-.87,42.18-.86,42.48l.19,6.4c-9.74,27.56.06,49.6,8.38,69.77.06-24.92,1.07-45.22-6-71-.2-3.82-1.49-30.36.61-47.34.34-2.75,11.65-6.56,23.63-10.59l1.33-.44c22-7.42,53.57-16.39,71.9-21.29a6.75,6.75,0,0,0,2.29-.25C112.64,112.43,114.08,111.09,113.78,110Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,31 +0,0 @@
|
||||
name: 'Close Pull Requests'
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: opened
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
close:
|
||||
# Avoid forks to run this job
|
||||
if: github.repository_owner == 'moodle'
|
||||
name: Close Pull Requests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/repo-lockdown@v4
|
||||
with:
|
||||
process-only: prs
|
||||
close-pr: true
|
||||
skip-closed-pr-comment: true
|
||||
pr-comment: >
|
||||
**Please, don't open pull requests via GitHub.**
|
||||
|
||||
|
||||
This repository (moodle.git) at GitHub is just a mirror of the official Moodle repository.
|
||||
|
||||
|
||||
For how to contribute patches for Moodle see
|
||||
[CONTRIBUTING.md](https://github.com/moodle/moodle/blob/main/CONTRIBUTING.md).
|
||||
|
||||
|
||||
Closing this pull request.
|
||||
+11
-21
@@ -3,20 +3,13 @@ name: Core
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
- master
|
||||
- MOODLE_[0-9]+_STABLE
|
||||
tags-ignore:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
phpunit_extra_options:
|
||||
description: Additional options to apply to PHPUnit
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
env:
|
||||
php: 8.3
|
||||
php: 8.0
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
@@ -24,10 +17,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
@@ -61,35 +54,32 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# MySQL builds always run with the lowest PHP supported version.
|
||||
- os: ubuntu-22.04
|
||||
php: 8.1
|
||||
php: 7.4
|
||||
extensions:
|
||||
db: mysqli
|
||||
# PostgreSQL builds always run with the highest PHP supported version.
|
||||
- os: ubuntu-22.04
|
||||
php: 8.3
|
||||
php: 8.0
|
||||
db: pgsql
|
||||
extensions: xmlrpc-beta
|
||||
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: moodlehq/mysql-action@v1
|
||||
uses: johanmeiring/mysql-action@tmpfs-patch
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 8.0
|
||||
mysql version: 5.7
|
||||
mysql database: test
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
use tmpfs: true
|
||||
tmpfs size: '1024M'
|
||||
extra conf: --skip-log-bin
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
uses: m4nu56/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: 13
|
||||
postgresql version: 12
|
||||
postgresql db: test
|
||||
postgresql user: test
|
||||
postgresql password: test
|
||||
@@ -106,7 +96,7 @@ jobs:
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
@@ -122,4 +112,4 @@ jobs:
|
||||
env:
|
||||
dbtype: ${{ matrix.db }}
|
||||
phpunit_options: ${{ secrets.phpunit_options }}
|
||||
run: vendor/bin/phpunit $phpunit_options ${{ inputs.phpunit_extra_options }}
|
||||
run: vendor/bin/phpunit $phpunit_options
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
name: Windows Testing
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
phpunit_extra_options:
|
||||
description: Additional options to apply to PHPUnit
|
||||
required: false
|
||||
default: ''
|
||||
env:
|
||||
php: 8.3
|
||||
|
||||
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@v4
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v4
|
||||
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.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.
|
||||
# db: mysqli
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
|
||||
- os: windows-latest
|
||||
php: 8.1
|
||||
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@v4
|
||||
|
||||
# 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 ${{ inputs.phpunit_extra_options }}
|
||||
+1
-1
@@ -20,13 +20,13 @@
|
||||
*~
|
||||
#
|
||||
/config.php
|
||||
/lib/editor/tinymce/extra/tools/temp/
|
||||
/tags
|
||||
/TAGS
|
||||
/cscope.*
|
||||
/.patches/
|
||||
/.idea/
|
||||
.phpstorm.*
|
||||
!.phpstorm.meta.php
|
||||
/nbproject/
|
||||
CVS
|
||||
.DS_Store
|
||||
|
||||
+1
-151
@@ -156,7 +156,7 @@ const getThirdPartyLibsList = relativeTo => {
|
||||
* @returns {array}
|
||||
*/
|
||||
const getThirdPartyPaths = () => {
|
||||
const DOMParser = require('@xmldom/xmldom').DOMParser;
|
||||
const DOMParser = require('xmldom').DOMParser;
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const xpath = require('xpath');
|
||||
@@ -232,155 +232,6 @@ const getOwningComponentDirectory = checkPath => {
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the latest tag in a remote GitHub repository.
|
||||
*
|
||||
* @param {string} url The remote repository.
|
||||
* @returns {Array}
|
||||
*/
|
||||
const getRepositoryTags = async(url) => {
|
||||
const gtr = require('git-tags-remote');
|
||||
try {
|
||||
const tags = await gtr.get(url);
|
||||
if (tags !== undefined) {
|
||||
return tags;
|
||||
}
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of thirdparty libraries that could be upgraded.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
const getThirdPartyLibsUpgradable = async() => {
|
||||
const libraries = getThirdPartyLibsData().filter((library) => !!library.repository);
|
||||
const upgradableLibraries = [];
|
||||
const versionCompare = (a, b) => {
|
||||
if (a === b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const aParts = a.split('.');
|
||||
const bParts = b.split('.');
|
||||
|
||||
for (let i = 0; i < Math.min(aParts.length, bParts.length); i++) {
|
||||
const aPart = parseInt(aParts[i], 10);
|
||||
const bPart = parseInt(bParts[i], 10);
|
||||
if (aPart > bPart) {
|
||||
// 1.1.0 > 1.0.9
|
||||
return 1;
|
||||
} else if (aPart < bPart) {
|
||||
// 1.0.9 < 1.1.0
|
||||
return -1;
|
||||
} else {
|
||||
// Same version.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (aParts.length > bParts.length) {
|
||||
// 1.0.1 > 1.0
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1.0 < 1.0.1
|
||||
return -1;
|
||||
};
|
||||
|
||||
for (let library of libraries) {
|
||||
upgradableLibraries.push(
|
||||
getRepositoryTags(library.repository).then((tagMap) => {
|
||||
library.version = library.version.replace(/^v/, '');
|
||||
const currentVersion = library.version.replace(/moodle-/, '');
|
||||
const currentMajorVersion = library.version.split('.')[0];
|
||||
const tags = [...tagMap]
|
||||
.map((tagData) => tagData[0])
|
||||
.filter((tag) => !tag.match(/(alpha|beta|rc)/))
|
||||
.map((tag) => tag.replace(/^v/, ''))
|
||||
.sort((a, b) => versionCompare(b, a));
|
||||
if (!tags.length) {
|
||||
library.warning = "Unable to find any comparable tags.";
|
||||
return library;
|
||||
}
|
||||
|
||||
library.latestVersion = tags[0];
|
||||
tags.some((tag) => {
|
||||
if (!tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See if the version part matches.
|
||||
const majorVersion = tag.split('.')[0];
|
||||
if (majorVersion === currentMajorVersion) {
|
||||
library.latestSameMajorVersion = tag;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
if (versionCompare(currentVersion, library.latestVersion) > 0) {
|
||||
// Moodle somehow has a newer version than the latest version.
|
||||
library.warning = `Newer version found: ${currentVersion} > ${library.latestVersion} for ${library.name}`;
|
||||
return library;
|
||||
}
|
||||
|
||||
|
||||
if (library.version !== library.latestVersion) {
|
||||
// Delete version and add it again at the end of the array. That way, current and new will stay closer.
|
||||
delete library.version;
|
||||
library.version = currentVersion;
|
||||
return library;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return (await Promise.all(upgradableLibraries)).filter((library) => !!library);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the list of thirdparty libraries.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
const getThirdPartyLibsData = () => {
|
||||
const DOMParser = require('@xmldom/xmldom').DOMParser;
|
||||
const fs = require('fs');
|
||||
const xpath = require('xpath');
|
||||
const path = require('path');
|
||||
|
||||
const libraryList = [];
|
||||
const libraryFields = [
|
||||
'location',
|
||||
'name',
|
||||
'version',
|
||||
'repository',
|
||||
];
|
||||
|
||||
const thirdpartyfiles = getThirdPartyLibsList(fs.realpathSync('./'));
|
||||
thirdpartyfiles.forEach(function(libraryPath) {
|
||||
const xmlContent = fs.readFileSync(libraryPath, 'utf8');
|
||||
const doc = new DOMParser().parseFromString(xmlContent);
|
||||
const libraries = xpath.select("/libraries/library", doc);
|
||||
for (const library of libraries) {
|
||||
const libraryData = [];
|
||||
for (const field of libraryFields) {
|
||||
libraryData[field] = xpath.select(`${field}/text()`, library)?.toString();
|
||||
}
|
||||
libraryData.location = path.join(path.dirname(libraryPath), libraryData.location);
|
||||
libraryList.push(libraryData);
|
||||
}
|
||||
});
|
||||
|
||||
return libraryList.sort((a, b) => a.location.localeCompare(b.location));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
fetchComponentData,
|
||||
getAmdSrcGlobList,
|
||||
@@ -390,5 +241,4 @@ module.exports = {
|
||||
getYuiSrcGlobList,
|
||||
getThirdPartyLibsList,
|
||||
getThirdPartyPaths,
|
||||
getThirdPartyLibsUpgradable,
|
||||
};
|
||||
|
||||
@@ -16,4 +16,4 @@ Moodle - the world's open source learning platform
|
||||
This generated documentation includes API documentation for JavaScript written in the AMD and ES2015 module formats within Moodle.
|
||||
|
||||
## Related information
|
||||
See [https://moodledev.io](https://moodledev.io) for other related Developer Documentation.
|
||||
See [https://docs.moodle.org/dev](https://docs.moodle.org/dev) for other related Developer Documentation.
|
||||
|
||||
@@ -114,7 +114,7 @@ module.exports = {
|
||||
],
|
||||
"menu": {
|
||||
"Developer Docs": {
|
||||
href: "https://moodledev.io",
|
||||
href: "https://docs.moodle.org/dev",
|
||||
target: "_blank",
|
||||
"class": "menu-item",
|
||||
id: "devdocs"
|
||||
|
||||
@@ -45,7 +45,6 @@ module.exports = grunt => {
|
||||
grunt.log.write(result);
|
||||
|
||||
if (error) {
|
||||
grunt.log.error(result.stdout);
|
||||
process.exit(code);
|
||||
}
|
||||
done();
|
||||
@@ -57,7 +56,7 @@ module.exports = grunt => {
|
||||
* @param {array} args
|
||||
* @returns {object}
|
||||
*/
|
||||
const spawnNodeCall = (args) => grunt.util.spawn({
|
||||
const spawnNodeCall = args => grunt.util.spawn({
|
||||
cmd: 'node',
|
||||
args,
|
||||
}, getSpawnHandler(grunt.task.current.async()));
|
||||
@@ -92,14 +91,13 @@ module.exports = grunt => {
|
||||
* @returns {Object} Reference to the spawned task
|
||||
*/
|
||||
const cssBuild = () => spawnNodeCall([
|
||||
'node_modules/sass/sass.js',
|
||||
'--style', 'expanded',
|
||||
'--source-map',
|
||||
'--embed-sources',
|
||||
'node_modules/node-sass/bin/node-sass',
|
||||
'--output-style', 'expanded',
|
||||
'--source-map', true,
|
||||
'--source-map-contents', true,
|
||||
'--precision', 6,
|
||||
'--load-path', process.cwd(),
|
||||
getCLPath('hugo/scss/docs.scss'),
|
||||
getCLPath('hugo/dist/css/docs.css'),
|
||||
'-o', getCLPath('hugo/dist/css/'),
|
||||
]);
|
||||
|
||||
// Register the various component library tasks.
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to generate the destination for the minification task
|
||||
* Function to generate the destination for the uglify 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
|
||||
@@ -30,9 +30,10 @@
|
||||
* @param {String} srcPath the matched src path
|
||||
* @return {String} The rewritten destination path.
|
||||
*/
|
||||
|
||||
const babelRename = function(destPath, srcPath) {
|
||||
destPath = srcPath.replace(`amd/src`, `amd/build`);
|
||||
destPath = destPath.replace(/\.js$/, '.min.js');
|
||||
destPath = srcPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
return destPath;
|
||||
};
|
||||
|
||||
@@ -60,6 +61,7 @@ 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');
|
||||
|
||||
@@ -103,7 +105,6 @@ 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,17 +114,15 @@ 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) => {
|
||||
options: async() => {
|
||||
return new Promise(resolve => {
|
||||
queue.push(resolve);
|
||||
startQueue();
|
||||
return options;
|
||||
});
|
||||
},
|
||||
|
||||
// When an item in the queue completes, start the next item in the queue.
|
||||
generateBundle: (options, bundle) => {
|
||||
grunt.log.debug(`Finished output phase for ${Object.keys(bundle).join(', ')}`);
|
||||
buildEnd: () => {
|
||||
runQueue();
|
||||
},
|
||||
};
|
||||
@@ -153,10 +152,24 @@ module.exports = grunt => {
|
||||
//
|
||||
// It also adds the Moodle plugin name to the AMD module definition
|
||||
// so that it can be imported as expected in other modules.
|
||||
path.resolve('.grunt/babel-plugin-add-module-to-define.js')
|
||||
path.resolve('.grunt/babel-plugin-add-module-to-define.js'),
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-syntax-import-meta',
|
||||
['@babel/plugin-proposal-class-properties', {'loose': false}],
|
||||
'@babel/plugin-proposal-json-strings'
|
||||
],
|
||||
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
|
||||
}]
|
||||
|
||||
+12
-28
@@ -20,33 +20,17 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
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.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();
|
||||
});
|
||||
module.exports = grunt => {
|
||||
// Project configuration.
|
||||
grunt.config.merge({
|
||||
jsdoc: {
|
||||
dist: {
|
||||
options: {
|
||||
configure: ".grunt/jsdoc/jsdoc.conf.js",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-jsdoc');
|
||||
};
|
||||
|
||||
@@ -32,7 +32,7 @@ module.exports = grunt => {
|
||||
}
|
||||
},
|
||||
options: {
|
||||
implementation: require('sass'),
|
||||
implementation: require('node-sass'),
|
||||
includePaths: ["theme/boost/scss/", "theme/classic/scss/"]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -29,7 +29,6 @@ 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.
|
||||
@@ -46,10 +45,7 @@ module.exports = grunt => {
|
||||
return {
|
||||
stylelint: {
|
||||
scss: {
|
||||
options: {
|
||||
quietDeprecationWarnings: true,
|
||||
customSyntax: 'postcss-scss',
|
||||
},
|
||||
options: {syntax: 'scss'},
|
||||
src: files,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/* jshint node: true, browser: false */
|
||||
/* eslint-env node */
|
||||
|
||||
/**
|
||||
* @copyright 2023 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
module.exports = grunt => {
|
||||
/**
|
||||
* Generate upgradable third-party libraries (utilising thirdpartylibs.xml data)
|
||||
*/
|
||||
grunt.registerTask('upgradablelibs', 'Generate upgradable third-party libraries', async function() {
|
||||
const done = this.async();
|
||||
|
||||
const path = require('path');
|
||||
const ComponentList = require(path.join(process.cwd(), '.grunt', 'components.js'));
|
||||
|
||||
// An array of third party libraries that have a newer version in their repositories.
|
||||
const thirdPartyLibs = await ComponentList.getThirdPartyLibsUpgradable({progress: true});
|
||||
for (let library of thirdPartyLibs) {
|
||||
grunt.log.ok(JSON.stringify(Object.assign({}, library), null, 4));
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Helper file for PhpStorm, and other IDEs, to provide better code completion.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2024 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace PHPSTORM_META;
|
||||
|
||||
// Assume that anything returned by \core\di::get('...') is an instance of the first argument.
|
||||
override(\core\di::get(0), map([
|
||||
'' => '@',
|
||||
]));
|
||||
|
||||
// Assume that anything returned by \Psr\Container\ContainerInterface::get('...') is an instance of the first argument.
|
||||
override(\Psr\Container\ContainerInterface::get(0), map([
|
||||
'' => '@',
|
||||
]));
|
||||
|
||||
// Assume that anything returned by \DI\Container::get('...') is an instance of the first argument.
|
||||
override(\DI\Container::get(0), map([
|
||||
'' => '@',
|
||||
]));
|
||||
+4
-16
@@ -1,14 +1,9 @@
|
||||
{
|
||||
"customSyntax": "postcss-scss",
|
||||
"plugins": [
|
||||
"stylelint-csstree-validator"
|
||||
],
|
||||
"rules": {
|
||||
"csstree/validator": {
|
||||
"syntaxExtensions": [
|
||||
"sass"
|
||||
]
|
||||
},
|
||||
"csstree/validator": true,
|
||||
"at-rule-empty-line-before": [ "always",
|
||||
{"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
|
||||
],
|
||||
@@ -50,7 +45,7 @@
|
||||
"function-name-case": "lower",
|
||||
"function-parentheses-newline-inside": "always-multi-line",
|
||||
"function-parentheses-space-inside": "never-single-line",
|
||||
"function-url-scheme-disallowed-list": ["data"],
|
||||
"function-url-scheme-blacklist": ["data"],
|
||||
"function-whitespace-after": "always",
|
||||
"indentation": 4,
|
||||
"keyframe-declaration-no-important": true,
|
||||
@@ -89,19 +84,12 @@
|
||||
"selector-type-no-unknown": true,
|
||||
"string-no-newline": true,
|
||||
"time-min-milliseconds": 100,
|
||||
"unit-disallowed-list": ["pt"],
|
||||
"unit-blacklist": ["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": {
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
# PLEASE NOTE: Travis is not currently utilised by the Moodle core integration
|
||||
# process (which uses our internal CI system) this file is here for the benefit
|
||||
# of community developers git clones - see MDL-51458.
|
||||
|
||||
notifications:
|
||||
email:
|
||||
if: env(MOODLE_EMAIL) != no
|
||||
|
||||
language: php
|
||||
|
||||
os: linux
|
||||
|
||||
dist: focal
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- docker
|
||||
|
||||
addons:
|
||||
postgresql: "12"
|
||||
apt:
|
||||
packages:
|
||||
- postgresql-12
|
||||
- postgresql-client-12
|
||||
|
||||
branches:
|
||||
except:
|
||||
- master
|
||||
- /MOODLE_[0-9]+_STABLE/
|
||||
- /^v[0-9]+\.[0-9]+\.[0-9]+.*/
|
||||
|
||||
jobs:
|
||||
# Enable fast finish.
|
||||
# This will fail the build if a single job fails (except those in allow_failures).
|
||||
# It will not stop the jobs from running.
|
||||
fast_finish: true
|
||||
|
||||
include:
|
||||
# First all the lowest php ones (7.4)
|
||||
- php: 7.4
|
||||
env: DB=none TASK=CITEST
|
||||
- php: 7.4
|
||||
env: DB=none TASK=GRUNT
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present
|
||||
php: 7.4
|
||||
env: DB=pgsql TASK=PHPUNIT
|
||||
|
||||
- if: env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all"
|
||||
php: 7.4
|
||||
env: DB=mysqli TASK=PHPUNIT
|
||||
|
||||
# Then, conditionally, all the highest php ones (8.0)
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 8.0
|
||||
env: DB=none TASK=CITEST
|
||||
- if: env(MOODLE_PHP) = "all"
|
||||
php: 8.0
|
||||
env: DB=none TASK=GRUNT
|
||||
|
||||
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present)
|
||||
php: 8.0
|
||||
env: DB=pgsql TASK=PHPUNIT
|
||||
|
||||
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all")
|
||||
php: 8.0
|
||||
env: DB=mysqli TASK=PHPUNIT
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
- $HOME/.npm
|
||||
|
||||
before_install:
|
||||
- docker run -d -p 127.0.0.1:8080:80 --name exttests moodlehq/moodle-exttests
|
||||
# Avoid IPv6 default binding as service (causes redis not to start).
|
||||
- sudo service redis-server start --bind 127.0.0.1
|
||||
|
||||
env:
|
||||
global:
|
||||
- PGVER=12
|
||||
- PGPORT=5433
|
||||
|
||||
install:
|
||||
- >
|
||||
if [ "$DB" = 'mysqli' ];
|
||||
then
|
||||
sudo mkdir /mnt/ramdisk
|
||||
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
|
||||
sudo service mysql stop
|
||||
sudo mv /var/lib/mysql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
|
||||
sudo service mysql restart
|
||||
fi
|
||||
- >
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
then
|
||||
sudo mkdir /mnt/ramdisk
|
||||
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
|
||||
sudo service postgresql stop
|
||||
sudo mv /var/lib/postgresql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
|
||||
sudo service postgresql start
|
||||
fi
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
if [ -n "$GITHUB_APITOKEN" ]; then
|
||||
composer config github-oauth.github.com $GITHUB_APITOKEN;
|
||||
echo 'auth.json' >> .git/info/exclude
|
||||
fi
|
||||
|
||||
echo 'extension="redis.so"' > /tmp/redis.ini
|
||||
phpenv config-add /tmp/redis.ini
|
||||
|
||||
# Install composer dependencies.
|
||||
# We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
|
||||
# Typically it should be able to use the Composer cache if any other job has already completed before we started here.
|
||||
travis_retry composer install --prefer-dist --no-interaction;
|
||||
fi
|
||||
|
||||
- >
|
||||
if [ "$TASK" = 'GRUNT' ];
|
||||
then
|
||||
nvm install
|
||||
nvm use
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- if [[ ${TRAVIS_PHP_VERSION:0:1} -gt 7 ]]; then pecl install xmlrpc-beta; fi
|
||||
- echo 'max_input_vars=5000' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
- phpenv config-rm xdebug.ini
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
# Copy generic configuration in place.
|
||||
cp config-dist.php config.php ;
|
||||
|
||||
# Create the moodledata directory.
|
||||
mkdir -p "$HOME"/roots/base
|
||||
|
||||
# The database name and password.
|
||||
sed -i \
|
||||
-e "s%= 'moodle'%= 'travis_ci_test'%" \
|
||||
-e "s%= 'password'%= ''%" \
|
||||
config.php ;
|
||||
|
||||
# The wwwroot and dataroot.
|
||||
sed -i \
|
||||
-e "s%http://example.com/moodle%https://localhost%" \
|
||||
-e "s%/home/example/moodledata%/home/travis/roots/base%" \
|
||||
config.php ;
|
||||
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
then
|
||||
# Postgres-specific setup.
|
||||
sed -i \
|
||||
-e "s%= 'username'%= 'travis'%" \
|
||||
-e "s%'dbsocket' => false%'dbsocket' => true%" \
|
||||
config.php ;
|
||||
|
||||
psql -c 'CREATE DATABASE travis_ci_test;' -U travis;
|
||||
fi
|
||||
|
||||
if [ "$DB" = 'mysqli' ];
|
||||
then
|
||||
# MySQL-specific setup.
|
||||
sed -i \
|
||||
-e "s%= 'pgsql'%= 'mysqli'%" \
|
||||
-e "s%= 'username'%= 'travis'%" \
|
||||
-e "s%=> 'utf8mb4_unicode_ci'%=> 'utf8mb4_bin'%" \
|
||||
config.php;
|
||||
|
||||
mysql -u root -e 'SET GLOBAL innodb_file_format=barracuda;' ;
|
||||
mysql -u root -e 'SET GLOBAL innodb_file_per_table=ON;' ;
|
||||
mysql -u root -e 'SET GLOBAL innodb_large_prefix=ON;' ;
|
||||
mysql -e 'CREATE DATABASE travis_ci_test DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_bin;' ;
|
||||
fi
|
||||
fi
|
||||
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
# Create a directory for the phpunit dataroot.
|
||||
mkdir -p "$HOME"/roots/phpunit
|
||||
|
||||
# The phpunit dataroot and prefix..
|
||||
sed -i \
|
||||
-e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
|
||||
-e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
|
||||
config.php ;
|
||||
# Enable test external resources
|
||||
sed -i \
|
||||
-e "/require_once/i \\define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://127.0.0.1:8080');" \
|
||||
-e "/require_once/i \\define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://127.0.0.1:8080');" \
|
||||
config.php ;
|
||||
|
||||
# Redis cache store tests
|
||||
sed -i \
|
||||
-e "/require_once/i \\define('TEST_CACHESTORE_REDIS_TESTSERVERS', '127.0.0.1');" \
|
||||
config.php ;
|
||||
# Redis session tests
|
||||
sed -i \
|
||||
-e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
|
||||
config.php ;
|
||||
|
||||
# Initialise PHPUnit for Moodle.
|
||||
php admin/tool/phpunit/cli/init.php
|
||||
fi
|
||||
|
||||
- >
|
||||
if [ "$TASK" = 'GRUNT' ];
|
||||
then
|
||||
npm install --no-spin;
|
||||
npm install --no-spin -g grunt ;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# CI Tests
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$TASK" = 'CITEST' ];
|
||||
then
|
||||
# Note - this is deliberately placed in the script section as we
|
||||
# should not add any code until after phpunit has run.
|
||||
|
||||
# The following repositories are required.
|
||||
# The local_ci repository does the actual checking.
|
||||
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci
|
||||
|
||||
# We need the official upstream for comparison
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
git fetch upstream MOODLE_401_STABLE;
|
||||
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
|
||||
export GIT_COMMIT="$TRAVIS_COMMIT";
|
||||
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
|
||||
|
||||
# Variables required by our linter.
|
||||
export gitcmd=`which git`;
|
||||
export gitdir="$TRAVIS_BUILD_DIR";
|
||||
export phpcmd=`which php`;
|
||||
fi
|
||||
|
||||
script:
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
vendor/bin/phpunit --fail-on-risky --disallow-test-output --verbose;
|
||||
fi
|
||||
|
||||
- >
|
||||
if [ "$TASK" = 'CITEST' ];
|
||||
then
|
||||
bash local/ci/php_lint/php_lint.sh;
|
||||
fi
|
||||
|
||||
- >
|
||||
if [ "$TASK" = 'GRUNT' ];
|
||||
then
|
||||
grunt ;
|
||||
# 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.
|
||||
git add . ;
|
||||
git reset -- npm-shrinkwrap.json ;
|
||||
git diff --cached --exit-code ;
|
||||
fi
|
||||
|
||||
after_script:
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
then
|
||||
EXTTESTS_HITS=$(docker logs exttests 2>&1 | grep -Fv -e 'AH00558' -e '[pid 1]' | wc -l)
|
||||
echo -e "\nTest local resources number of hits: ${EXTTESTS_HITS}.\n"
|
||||
fi
|
||||
@@ -1,52 +0,0 @@
|
||||
# Contributing to Moodle
|
||||
|
||||
[Moodle][1] is made by people like you. We are members of a big worldwide community of developers, designers, teachers, testers, translators and many more. We work in universities, schools, companies and other places. You are very welcome to join us and contribute to the project.
|
||||
|
||||
There are many ways that you can contribute to Moodle, not just through development. See our [community contribution guide][2] for some of the many ways that you can help.
|
||||
|
||||
## Github
|
||||
|
||||
> [!NOTE]
|
||||
> Please do not open pull requests via Github.
|
||||
|
||||
All issues should be reported via, and patched provided to the [Moodle Tracker][3].
|
||||
|
||||
The Moodle [Github][4] repository is a clone of the official Moodle repository, whcih can be found at https://git.moodle.org.
|
||||
|
||||
## Moodle core bug fixes and new features
|
||||
|
||||
Over the years, Moodle has developed a mature process for reporting, reviewing, and accepting patches. This is fully documented in our [documentation on development processes][6], but in summary:
|
||||
|
||||
- Every bug fix or new feature must have a tracker issue.
|
||||
- You publish the branch implementing the fix or new feature in your public clone of the moodle.git repository (typically on Github).
|
||||
- Your patch is peer-reviewed, discussed, integrated, tested and then released as a part of one of our weekly releases.
|
||||
- New features are developed on the `main` branch. Bug fixes are also backported to currently supported maintenance (stable) branches.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Please do not publish security issues, or patches releating to them publicly.
|
||||
> See our [Responsible Disclosure Policy][5] for more information.
|
||||
|
||||
|
||||
## Moodle plugins
|
||||
|
||||
Moodle has a framework for additional plugins to extend its functionality. We
|
||||
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
|
||||
register and maintain your plugin. Plugins hosted in the plugins directory can
|
||||
be easily installed and updated via the Moodle administration interface.
|
||||
|
||||
* You are expected to have a public source code repository with your plugin
|
||||
code.
|
||||
* After registering your plugin in the plugins directory it is reviewed before
|
||||
being published.
|
||||
* You are expected to continuously release updated versions of the plugin via
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://moodledev.io/general/community/plugincontribution>.
|
||||
|
||||
[1]: https://moodle.org
|
||||
[2]: https://moodledev.io/general/community/contribute
|
||||
[3]: https://tracker.moodle.org
|
||||
[4]: https://github.com/moodle/moodle
|
||||
[5]: https://moodledev.io/general/development/process/security
|
||||
[6]: https://moodledev.io/general/development/process
|
||||
@@ -0,0 +1,56 @@
|
||||
CONTRIBUTING TO MOODLE
|
||||
======================
|
||||
|
||||
Moodle is made by people like you. We are members of a big worldwide community
|
||||
of developers, designers, teachers, testers, translators and other users. We
|
||||
work in universities, schools, companies and other places. You are very welcome
|
||||
to join us and contribute to the project.
|
||||
|
||||
See <https://docs.moodle.org/dev/Contributing_to_Moodle> for the many ways you
|
||||
can help, not only with coding.
|
||||
|
||||
Moodle is open to community contributions to core, though all code must go
|
||||
through peer-review, automated behaviour testing, continuous integration and
|
||||
human post-integration checks.
|
||||
|
||||
Pull requests
|
||||
-------------
|
||||
|
||||
Please do not open pull requests via Github. The repository there is just a
|
||||
mirror of the official repository at <https://git.moodle.org>. Issues are
|
||||
reported and patches provided via <https://tracker.moodle.org>. See below for
|
||||
more information.
|
||||
|
||||
Moodle core bug fixes and new features
|
||||
--------------------------------------
|
||||
|
||||
During the years of intensive development, a mature process of including
|
||||
submitted patches has evolved.
|
||||
|
||||
* Every bug fix or new feature must have a tracker issue.
|
||||
* You publish the branch implementing the fix or new feature in your public
|
||||
clone of the moodle.git repository (typically on Github).
|
||||
* Your patch is peer-reviewed, discussed, integrated, tested and then released
|
||||
as a part of moodle.git.
|
||||
* New features are developed on the master branch. Bug fixes are also
|
||||
backported to currently supported maintenance (stable) branches.
|
||||
|
||||
For further details, see <https://docs.moodle.org/dev/Process>.
|
||||
|
||||
Moodle plugins
|
||||
--------------
|
||||
|
||||
Moodle has a framework for additional plugins to extend its functionality. We
|
||||
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
|
||||
register and maintain your plugin. Plugins hosted in the plugins directory can
|
||||
be easily installed and updated via the Moodle administration interface.
|
||||
|
||||
* You are expected to have a public source code repository with your plugin
|
||||
code.
|
||||
* After registering your plugin in the plugins directory it is reviewed before
|
||||
being published.
|
||||
* You are expected to continuously release updated versions of the plugin via
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://docs.moodle.org/dev/Plugin_contribution>.
|
||||
@@ -260,8 +260,6 @@ module.exports = function(grunt) {
|
||||
addTask('watch', grunt);
|
||||
addTask('startup', grunt);
|
||||
|
||||
addTask('upgradablelibs', grunt);
|
||||
|
||||
// Register the default task.
|
||||
grunt.registerTask('default', ['startup']);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
|
||||
|
||||
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
|
||||
|
||||
See CONTRIBUTING.txt guidelines for how to contribute patches for Moodle. Thank you.
|
||||
|
||||
--
|
||||
@@ -1,48 +0,0 @@
|
||||
# Moodle
|
||||
|
||||
<p align="center"><a href="https://moodle.org" target="_blank" title="Moodle Website">
|
||||
<img src="https://raw.githubusercontent.com/moodle/moodle/main/.github/moodlelogo.svg" alt="The Moodle Logo">
|
||||
</a></p>
|
||||
|
||||
[Moodle][1] is the World's Open Source Learning Platform, widely used around the world by countless universities, schools, companies, and all manner of organisations and individuals.
|
||||
|
||||
Moodle is designed to allow educators, administrators and learners to create personalised learning environments with a single robust, secure and integrated system.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Read our [User documentation][3]
|
||||
- Discover our [developer documentation][5]
|
||||
- Take a look at our [demo site][4]
|
||||
|
||||
## Community
|
||||
|
||||
[moodle.org][1] is the central hub for the Moodle Community, with spaces for educators, administrators and developers to meet and work together.
|
||||
|
||||
You may also be interested in:
|
||||
|
||||
- attending a [Moodle Moot][6]
|
||||
- our regular series of [developer meetings][7]
|
||||
- the [Moodle User Association][8]
|
||||
|
||||
## Installation and hosting
|
||||
|
||||
Moodle is Free, and Open Source software. You can easily [download Moodle][9] and run it on your own web server, however you may prefer to work with one of our experienced [Moodle Partners][10].
|
||||
|
||||
Moodle also offers hosting through both [MoodleCloud][11], and our [partner network][10].
|
||||
|
||||
## License
|
||||
|
||||
Moodle is provided freely as open source software, under version 3 of the GNU General Public License. For more information on our license see
|
||||
|
||||
[1]: https://moodle.org
|
||||
[2]: https://moodle.com
|
||||
[3]: https://docs.moodle.org/
|
||||
[4]: https://sandbox.moodledemo.net/
|
||||
[5]: https://moodledev.io
|
||||
[6]: https://moodle.com/events/mootglobal/
|
||||
[7]: https://moodledev.io/general/community/meetings
|
||||
[8]: https://moodleassociation.org/
|
||||
[9]: https://download.moodle.org
|
||||
[10]: https://moodle.com/partners
|
||||
[11]: https://moodle.com/cloud
|
||||
[12]: https://moodledev.io/general/license
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
.-..-.
|
||||
_____ | || |
|
||||
/____/-.---_ .---. .---. .-.| || | .---.
|
||||
| | _ _ |/ _ \/ _ \/ _ || |/ __ \
|
||||
* | | | | | || |_| || |_| || |_| || || |___/
|
||||
|_| |_| |_|\_____/\_____/\_____||_|\_____)
|
||||
|
||||
Moodle - the world's open source learning platform
|
||||
|
||||
Moodle <https://moodle.org> is a learning platform designed to provide
|
||||
educators, administrators and learners with a single robust, secure and
|
||||
integrated system to create personalised learning environments.
|
||||
|
||||
You can download Moodle <https://download.moodle.org> and run it on your own
|
||||
web server, ask one of our Moodle Partners <https://moodle.com/partners/> to
|
||||
assist you, or have a MoodleCloud site <https://moodle.com/cloud/> set up for
|
||||
you.
|
||||
|
||||
Moodle is widely used around the world by universities, schools, companies and
|
||||
all manner of organisations and individuals.
|
||||
|
||||
Moodle is provided freely as open source software, under the GNU General Public
|
||||
License <https://docs.moodle.org/dev/License>.
|
||||
|
||||
Moodle is written in PHP and JavaScript and uses an SQL database for storing
|
||||
the data.
|
||||
|
||||
See <https://docs.moodle.org> for details of Moodle's many features.
|
||||
+35
-53
@@ -1,66 +1,48 @@
|
||||
MOODLE TRADEMARKS POLICY
|
||||
========================
|
||||
|
||||
The Moodle Trademark
|
||||
--------------------
|
||||
The word "Moodle" is trademarked in many countries around the world. The word
|
||||
was originally coined as an acronym: Modular Object-Oriented Dynamic Learning
|
||||
Environment. The trademark is owned by Martin Dougiamas, Founder and Director
|
||||
of Moodle.
|
||||
|
||||
The brand and word "Moodle" has trade mark protection in many countries around
|
||||
the world. Various Moodle™ trade marks are owned by either Moodle Pty Ltd or
|
||||
one of its associated entities. The law obligates trade mark owners to police
|
||||
their trade marks and prevent the use of confusingly similar names by
|
||||
third parties.
|
||||
The law obligates trademark owners to police their marks and prevent the use of
|
||||
confusingly similar names by third parties. Through this policy we’d like to
|
||||
make it clear how Moodle-related projects, organisations, and people can use
|
||||
the Moodle trademark. We’d also like to be clear about how use of the word is
|
||||
restricted when used to promote commercial Moodle services. We do this to
|
||||
protect the very business model that allows us to continue developing Moodle
|
||||
for you.
|
||||
|
||||
We have created a more concise and thorough set of Trademark Guidelines
|
||||
(https://moodle.com/wp-content/uploads/2023/02/Moodle-Trademark-Guidelines-2023-4.pdf)
|
||||
to help you understand how to comply with Moodle's trade mark requirements.
|
||||
The Trademark Guidelines will also assist our Moodle Certified Partners and the
|
||||
community to understand some of the principles that inform Moodle's stance
|
||||
whenever potential infringement has been detected by us or our community.
|
||||
Allowed uses
|
||||
------------
|
||||
|
||||
We need to be clear about use of the word "Moodle" and how we restrict its use
|
||||
when promoting commercial Moodle™ branded services. The proper use of
|
||||
trade marks reliably assures consumers about the quality of the associated
|
||||
products or services and where they have been derived from. Because the
|
||||
Moodle LMS is made available under the open source ‘GNU General Public License'
|
||||
that permits you to modify the copyrighted software, the distribution of such
|
||||
modified software in combination with Moodle trade marks can potentially
|
||||
mislead others in the community. To be clear, the GNU GPL does not include an
|
||||
implied right or licence to use Moodle's trade marks.
|
||||
The following uses don’t require any permission at all:
|
||||
|
||||
We do all this to protect the very business model that allows us to continue
|
||||
developing various Moodle software solutions for you.
|
||||
|
||||
Allowed uses of "Moodle"
|
||||
------------------------
|
||||
|
||||
The following uses don't require any permission at all:
|
||||
|
||||
* Referring to the software or the Moodle project as the "Moodle™ software"
|
||||
or the "Moodle™ project"
|
||||
* Describing your own implementation of the Moodle™ software platform
|
||||
(including within corporate settings).
|
||||
* Referring to the software or the Moodle project.
|
||||
* Describing your own Moodle implementation (including within corporate
|
||||
settings).
|
||||
* Describing a Moodle-based community hub.
|
||||
* Describing certain software you've made that integrates with Moodle™
|
||||
branded software (e.g. a Moodle™ integration feature on another system).
|
||||
* Describing some software you’ve made that integrates with Moodle
|
||||
(eg a Moodle integration feature on another system).
|
||||
|
||||
Restricted uses of "Moodle"
|
||||
---------------------------
|
||||
Restricted uses
|
||||
---------------
|
||||
|
||||
The following uses are generally prohibited without explicit and direct
|
||||
permission being granted to you by Moodle Pty Ltd. We do this to protect the
|
||||
Moodle™ project from software and sites which could confuse people. If in
|
||||
doubt, reach out for clarification at <trademarks@moodle.com>
|
||||
Moodle project from software and sites which could confuse people. Please
|
||||
contact us to ask for permission in writing.
|
||||
|
||||
* You can't use the word "Moodle" or any Moodle logos for commercial purposes
|
||||
without prior written permission from Moodle HQ.
|
||||
* You can't use "Moodle" in the name of your software (including Mobile apps).
|
||||
* You can't use "Moodle" in your company name.
|
||||
* You can't use "Moodle" in your domain name.
|
||||
* You can't use "Moodle" in advertising-related keywords (such as Adsense).
|
||||
* You can't use "Moodle" to describe services around Moodle
|
||||
(such as hosting, training, support, consulting, course creation services,
|
||||
theme development, customisation, installation, integration, analytics
|
||||
and certification) that cause consumers to be confused that you are
|
||||
associated with Moodle HQ if you are not.
|
||||
This applies even if you do not charge for the services.
|
||||
Note that usually only Moodle Partners have this permission.
|
||||
* You can’t use "Moodle" in the name of your software (including Mobile apps)
|
||||
* You can’t use "Moodle" in your company name
|
||||
* You can’t use "Moodle" in your domain name
|
||||
* You can’t use "Moodle" in advertising-related keywords (such as Adsense)
|
||||
* You can’t use "Moodle" to describe services around Moodle (such as hosting,
|
||||
training, support, consulting, course creation services, theme development,
|
||||
customisation, installation, integration and certification). This applies
|
||||
even if you do not charge for the services. Note that usually only Moodle
|
||||
Partners have this permission.
|
||||
|
||||
For information about the Moodle Partner Certification Mark as well as for how
|
||||
to contact us, please see <https://moodle.com/trademarks/>.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
define("core_admin/block_management_table",["exports","./plugin_management_table","core_table/dynamic","core/ajax","core/pending","core/notification"],(function(_exports,_plugin_management_table,_dynamic,_ajax,_pending,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_plugin_management_table=_interopRequireDefault(_plugin_management_table),_pending=_interopRequireDefault(_pending);class _default extends _plugin_management_table.default{constructor(){super(),this.addClickHandler(this.handleBlockProtectToggle)}setBlockProtectState(plugin,state){return(0,_ajax.call)([{methodname:"core_admin_set_block_protection",args:{plugin:plugin,state:state}}])[0]}async handleBlockProtectToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="toggleprotectstate"]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:processAction");await this.setBlockProtectState(stateToggle.dataset.plugin,"1"===stateToggle.dataset.targetState?1:0);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="toggleprotectstate"][data-plugin="'.concat(stateToggle.dataset.plugin,'"]')).focus(),pendingPromise.resolve()}}}return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=block_management_table.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"block_management_table.min.js","sources":["../src/block_management_table.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport PluginManagementTable from './plugin_management_table';\nimport {refreshTableContent} from 'core_table/dynamic';\nimport {call as fetchMany} from 'core/ajax';\nimport Pending from 'core/pending';\nimport {fetchNotifications} from 'core/notification';\n\nexport default class extends PluginManagementTable {\n constructor() {\n super();\n this.addClickHandler(this.handleBlockProtectToggle);\n }\n\n /**\n * Set the block protection state.\n *\n * @param {string} plugin\n * @param {number} state\n * @returns {Promise}\n */\n setBlockProtectState(plugin, state) {\n return fetchMany([{\n methodname: 'core_admin_set_block_protection',\n args: {\n plugin,\n state,\n },\n }])[0];\n }\n\n /**\n * Handle toggling of block protection.\n *\n * @param {HTMLElement} tableRoot\n * @param {Event} e\n */\n async handleBlockProtectToggle(tableRoot, e) {\n const stateToggle = e.target.closest('[data-action=\"toggleprotectstate\"]');\n if (stateToggle) {\n e.preventDefault();\n const pendingPromise = new Pending('core_table/dynamic:processAction');\n\n await this.setBlockProtectState(\n stateToggle.dataset.plugin,\n stateToggle.dataset.targetState === '1' ? 1 : 0\n );\n\n const [updatedRoot] = await Promise.all([\n refreshTableContent(tableRoot),\n fetchNotifications(),\n ]);\n\n // Refocus on the link that as pressed in the first place.\n updatedRoot.querySelector(`[data-action=\"toggleprotectstate\"][data-plugin=\"${stateToggle.dataset.plugin}\"]`).focus();\n pendingPromise.resolve();\n }\n }\n}\n"],"names":["PluginManagementTable","constructor","addClickHandler","this","handleBlockProtectToggle","setBlockProtectState","plugin","state","methodname","args","tableRoot","e","stateToggle","target","closest","preventDefault","pendingPromise","Pending","dataset","targetState","updatedRoot","Promise","all","querySelector","focus","resolve"],"mappings":"uhBAqB6BA,iCACzBC,2BAESC,gBAAgBC,KAAKC,0BAU9BC,qBAAqBC,OAAQC,cAClB,cAAU,CAAC,CACdC,WAAY,kCACZC,KAAM,CACFH,OAAAA,OACAC,MAAAA,UAEJ,kCASuBG,UAAWC,SAChCC,YAAcD,EAAEE,OAAOC,QAAQ,yCACjCF,YAAa,CACbD,EAAEI,uBACIC,eAAiB,IAAIC,iBAAQ,0CAE7Bd,KAAKE,qBACPO,YAAYM,QAAQZ,OACgB,MAApCM,YAAYM,QAAQC,YAAsB,EAAI,SAG3CC,mBAAqBC,QAAQC,IAAI,EACpC,gCAAoBZ,YACpB,wCAIJU,YAAYG,wEAAiEX,YAAYM,QAAQZ,cAAYkB,QAC7GR,eAAeS"}
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
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
|
||||
File diff suppressed because one or more lines are too long
@@ -1,3 +0,0 @@
|
||||
define("core_admin/plugin_management_table",["exports","core_table/dynamic","core_table/local/dynamic/selectors","core/ajax","core/pending","core/notification"],(function(_exports,_dynamic,Selectors,_ajax,_pending,_notification){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)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Selectors=function(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]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};let watching=!1;return _exports.default=class{constructor(){!function(obj,key,value){key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}(this,"clickHandlers",[]),this.addClickHandler(this.handleStateToggle),this.addClickHandler(this.handleMoveUpDown),this.registerEventListeners()}static init(){watching||(watching=!0,new this)}addClickHandler(handler){this.clickHandlers.push(handler.bind(this))}registerEventListeners(){document.addEventListener("click",function(e){const tableRoot=this.getTableRoot(e);tableRoot&&this.clickHandlers.forEach((handler=>handler(tableRoot,e)))}.bind(this))}getTableRoot(e){const tableRoot=e.target.closest(Selectors.main.region);return tableRoot||!1}setPluginState(methodname,plugin,state){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,state:state}}])[0]}setPluginOrder(methodname,plugin,direction){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,direction:direction}}])[0]}async handleStateToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="togglestate"][data-toggle-method]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:togglestate");await this.setPluginState(stateToggle.dataset.toggleMethod,stateToggle.dataset.plugin,"1"===stateToggle.dataset.state?0:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="togglestate"][data-plugin="'.concat(stateToggle.dataset.plugin,'"]')).focus(),pendingPromise.resolve()}}async handleMoveUpDown(tableRoot,e){const actionLink=e.target.closest('[data-action="move"][data-method][data-direction]');if(!actionLink)return;e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:processAction");await this.setPluginOrder(actionLink.dataset.method,actionLink.dataset.plugin,"up"===actionLink.dataset.direction?-1:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]),exactMatch=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"][data-direction="').concat(actionLink.dataset.direction,'"]'));var _updatedRoot$querySel;exactMatch?exactMatch.focus():null===(_updatedRoot$querySel=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"]')))||void 0===_updatedRoot$querySel||_updatedRoot$querySel.focus();pendingPromise.resolve()}},_exports.default}));
|
||||
|
||||
//# sourceMappingURL=plugin_management_table.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
define("core_admin/themeselector/preview_modal",["exports","core/modal_events","core/modal_cancel","core/modal_save_cancel","core/notification","core/templates","core/str"],(function(_exports,_modal_events,_modal_cancel,_modal_save_cancel,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Modal for theme previews.
|
||||
*
|
||||
* @module core_admin/themeselector/preview_modal
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_events=_interopRequireDefault(_modal_events),_modal_cancel=_interopRequireDefault(_modal_cancel),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const SELECTORS_THEMES_CONTAINER="themelist",SELECTORS_PREVIEW='[data-action="preview"]';_exports.init=()=>{registerListenerEvents()};const registerListenerEvents=()=>{document.addEventListener("click",(e=>{const preview=e.target.closest(SELECTORS_PREVIEW);preview&&buildModal(preview).catch(_notification.default.exception)}))},buildModal=async element=>{let description=await(0,_str.getString)("choosereadme","theme_"+element.getAttribute("data-choose"));const themesContainer=document.getElementById(SELECTORS_THEMES_CONTAINER),definedInConfig=parseInt(themesContainer.dataset.definedinconfig),data={name:element.getAttribute("data-name"),image:element.getAttribute("data-image"),description:description.replace(/<[^>]+>/g," "),current:element.getAttribute("data-current"),actionurl:element.getAttribute("data-actionurl"),choose:element.getAttribute("data-choose"),sesskey:element.getAttribute("data-sesskey"),definedinconfig:definedInConfig};let modalTemplate=_modal_save_cancel.default;(data.current||data.definedinconfig)&&(modalTemplate=_modal_cancel.default);const modal=await modalTemplate.create({title:data.name,body:_templates.default.render("core_admin/themeselector/theme_preview_modal",data),large:!0,buttons:{save:(0,_str.getString)("selecttheme","moodle"),cancel:(0,_str.getString)("closebuttontitle","moodle")},show:!0});modal.getRoot().on(_modal_events.default.save,(()=>{modal.getRoot().find("form").submit()}))}}));
|
||||
|
||||
//# sourceMappingURL=preview_modal.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"preview_modal.min.js","sources":["../../src/themeselector/preview_modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Modal for theme previews.\n *\n * @module core_admin/themeselector/preview_modal\n * @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalEvents from 'core/modal_events';\nimport ModalCancel from 'core/modal_cancel';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst SELECTORS = {\n THEMES_CONTAINER: 'themelist',\n PREVIEW: '[data-action=\"preview\"]',\n};\n\n/**\n * Entrypoint of the js.\n *\n * @method init\n */\nexport const init = () => {\n registerListenerEvents();\n};\n\n/**\n * Register theme related event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n document.addEventListener('click', (e) => {\n const preview = e.target.closest(SELECTORS.PREVIEW);\n if (preview) {\n buildModal(preview).catch(Notification.exception);\n }\n });\n};\n\n/**\n * Build the modal with the provided data.\n *\n * @method buildModal\n * @param {object} element\n */\nconst buildModal = async(element) => {\n\n // This string can be long. We will fetch it with JS as opposed to passing it as an attribute.\n let description = await getString('choosereadme', 'theme_' + element.getAttribute('data-choose'));\n\n const themesContainer = document.getElementById(SELECTORS.THEMES_CONTAINER);\n const definedInConfig = parseInt(themesContainer.dataset.definedinconfig);\n // Prepare data for modal.\n const data = {\n name: element.getAttribute('data-name'),\n image: element.getAttribute('data-image'),\n description: description.replace(/<[^>]+>/g, ' '), // Strip out HTML tags.\n current: element.getAttribute('data-current'),\n actionurl: element.getAttribute('data-actionurl'),\n choose: element.getAttribute('data-choose'),\n sesskey: element.getAttribute('data-sesskey'),\n definedinconfig: definedInConfig,\n };\n\n // Determine which modal template we should use.\n let modalTemplate = ModalSaveCancel;\n if (data.current || data.definedinconfig) {\n modalTemplate = ModalCancel;\n }\n\n const modal = await modalTemplate.create({\n title: data.name,\n body: Templates.render('core_admin/themeselector/theme_preview_modal', data),\n large: true,\n buttons: {\n 'save': getString('selecttheme', 'moodle'),\n 'cancel': getString('closebuttontitle', 'moodle'),\n },\n show: true,\n });\n\n modal.getRoot().on(ModalEvents.save, () => {\n modal.getRoot().find('form').submit();\n });\n};\n"],"names":["SELECTORS","registerListenerEvents","document","addEventListener","e","preview","target","closest","buildModal","catch","Notification","exception","async","description","element","getAttribute","themesContainer","getElementById","definedInConfig","parseInt","dataset","definedinconfig","data","name","image","replace","current","actionurl","choose","sesskey","modalTemplate","ModalSaveCancel","ModalCancel","modal","create","title","body","Templates","render","large","buttons","show","getRoot","on","ModalEvents","save","find","submit"],"mappings":";;;;;;;gWA8BMA,2BACgB,YADhBA,kBAEO,wCAQO,KAChBC,gCAQEA,uBAAyB,KAC3BC,SAASC,iBAAiB,SAAUC,UAC1BC,QAAUD,EAAEE,OAAOC,QAAQP,mBAC7BK,SACAG,WAAWH,SAASI,MAAMC,sBAAaC,eAW7CH,WAAaI,MAAAA,cAGXC,kBAAoB,kBAAU,eAAgB,SAAWC,QAAQC,aAAa,sBAE5EC,gBAAkBd,SAASe,eAAejB,4BAC1CkB,gBAAkBC,SAASH,gBAAgBI,QAAQC,iBAEnDC,KAAO,CACTC,KAAMT,QAAQC,aAAa,aAC3BS,MAAOV,QAAQC,aAAa,cAC5BF,YAAaA,YAAYY,QAAQ,WAAY,KAC7CC,QAASZ,QAAQC,aAAa,gBAC9BY,UAAWb,QAAQC,aAAa,kBAChCa,OAAQd,QAAQC,aAAa,eAC7Bc,QAASf,QAAQC,aAAa,gBAC9BM,gBAAiBH,qBAIjBY,cAAgBC,4BAChBT,KAAKI,SAAWJ,KAAKD,mBACrBS,cAAgBE,6BAGdC,YAAcH,cAAcI,OAAO,CACrCC,MAAOb,KAAKC,KACZa,KAAMC,mBAAUC,OAAO,+CAAgDhB,MACvEiB,OAAO,EACPC,QAAS,OACG,kBAAU,cAAe,kBACvB,kBAAU,mBAAoB,WAE5CC,MAAM,IAGVR,MAAMS,UAAUC,GAAGC,sBAAYC,MAAM,KACjCZ,MAAMS,UAAUI,KAAK,QAAQC"}
|
||||
@@ -1,72 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import PluginManagementTable from './plugin_management_table';
|
||||
import {refreshTableContent} from 'core_table/dynamic';
|
||||
import {call as fetchMany} from 'core/ajax';
|
||||
import Pending from 'core/pending';
|
||||
import {fetchNotifications} from 'core/notification';
|
||||
|
||||
export default class extends PluginManagementTable {
|
||||
constructor() {
|
||||
super();
|
||||
this.addClickHandler(this.handleBlockProtectToggle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block protection state.
|
||||
*
|
||||
* @param {string} plugin
|
||||
* @param {number} state
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setBlockProtectState(plugin, state) {
|
||||
return fetchMany([{
|
||||
methodname: 'core_admin_set_block_protection',
|
||||
args: {
|
||||
plugin,
|
||||
state,
|
||||
},
|
||||
}])[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle toggling of block protection.
|
||||
*
|
||||
* @param {HTMLElement} tableRoot
|
||||
* @param {Event} e
|
||||
*/
|
||||
async handleBlockProtectToggle(tableRoot, e) {
|
||||
const stateToggle = e.target.closest('[data-action="toggleprotectstate"]');
|
||||
if (stateToggle) {
|
||||
e.preventDefault();
|
||||
const pendingPromise = new Pending('core_table/dynamic:processAction');
|
||||
|
||||
await this.setBlockProtectState(
|
||||
stateToggle.dataset.plugin,
|
||||
stateToggle.dataset.targetState === '1' ? 1 : 0
|
||||
);
|
||||
|
||||
const [updatedRoot] = await Promise.all([
|
||||
refreshTableContent(tableRoot),
|
||||
fetchNotifications(),
|
||||
]);
|
||||
|
||||
// Refocus on the link that as pressed in the first place.
|
||||
updatedRoot.querySelector(`[data-action="toggleprotectstate"][data-plugin="${stateToggle.dataset.plugin}"]`).focus();
|
||||
pendingPromise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,179 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import {refreshTableContent} from 'core_table/dynamic';
|
||||
import * as Selectors from 'core_table/local/dynamic/selectors';
|
||||
import {call as fetchMany} from 'core/ajax';
|
||||
import Pending from 'core/pending';
|
||||
import {fetchNotifications} from 'core/notification';
|
||||
|
||||
let watching = false;
|
||||
|
||||
export default class {
|
||||
/**
|
||||
* @property {function[]} clickHandlers a list of handlers to call on click.
|
||||
*/
|
||||
clickHandlers = [];
|
||||
|
||||
constructor() {
|
||||
this.addClickHandler(this.handleStateToggle);
|
||||
this.addClickHandler(this.handleMoveUpDown);
|
||||
this.registerEventListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise an instance of the class.
|
||||
*
|
||||
* This is just a way of making it easier to initialise an instance of the class from PHP.
|
||||
*/
|
||||
static init() {
|
||||
if (watching) {
|
||||
return;
|
||||
}
|
||||
watching = true;
|
||||
new this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a click handler to the list of handlers.
|
||||
*
|
||||
* @param {Function} handler A handler to call on a click event
|
||||
*/
|
||||
addClickHandler(handler) {
|
||||
this.clickHandlers.push(handler.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the event listeners for this instance.
|
||||
*/
|
||||
registerEventListeners() {
|
||||
document.addEventListener('click', function(e) {
|
||||
const tableRoot = this.getTableRoot(e);
|
||||
|
||||
if (!tableRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clickHandlers.forEach((handler) => handler(tableRoot, e));
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table root from an event.
|
||||
*
|
||||
* @param {Event} e
|
||||
* @returns {HTMLElement|bool}
|
||||
*/
|
||||
getTableRoot(e) {
|
||||
const tableRoot = e.target.closest(Selectors.main.region);
|
||||
if (!tableRoot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tableRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the plugin state (enabled or disabled)
|
||||
*
|
||||
* @param {string} methodname The web service to call
|
||||
* @param {string} plugin The name of the plugin to set the state for
|
||||
* @param {number} state The state to set
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setPluginState(methodname, plugin, state) {
|
||||
return fetchMany([{
|
||||
methodname,
|
||||
args: {
|
||||
plugin,
|
||||
state,
|
||||
},
|
||||
}])[0];
|
||||
}
|
||||
|
||||
setPluginOrder(methodname, plugin, direction) {
|
||||
return fetchMany([{
|
||||
methodname,
|
||||
args: {
|
||||
plugin,
|
||||
direction,
|
||||
},
|
||||
}])[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle state toggling.
|
||||
*
|
||||
* @param {HTMLElement} tableRoot
|
||||
* @param {Event} e
|
||||
*/
|
||||
async handleStateToggle(tableRoot, e) {
|
||||
const stateToggle = e.target.closest('[data-action="togglestate"][data-toggle-method]');
|
||||
if (stateToggle) {
|
||||
e.preventDefault();
|
||||
const pendingPromise = new Pending('core_table/dynamic:togglestate');
|
||||
|
||||
await this.setPluginState(
|
||||
stateToggle.dataset.toggleMethod,
|
||||
stateToggle.dataset.plugin,
|
||||
stateToggle.dataset.state === '1' ? 0 : 1
|
||||
);
|
||||
|
||||
const [updatedRoot] = await Promise.all([
|
||||
refreshTableContent(tableRoot),
|
||||
fetchNotifications(),
|
||||
]);
|
||||
|
||||
// Refocus on the link that as pressed in the first place.
|
||||
updatedRoot.querySelector(`[data-action="togglestate"][data-plugin="${stateToggle.dataset.plugin}"]`).focus();
|
||||
pendingPromise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async handleMoveUpDown(tableRoot, e) {
|
||||
const actionLink = e.target.closest('[data-action="move"][data-method][data-direction]');
|
||||
if (!actionLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const pendingPromise = new Pending('core_table/dynamic:processAction');
|
||||
|
||||
await this.setPluginOrder(
|
||||
actionLink.dataset.method,
|
||||
actionLink.dataset.plugin,
|
||||
actionLink.dataset.direction === 'up' ? -1 : 1,
|
||||
);
|
||||
|
||||
const [updatedRoot] = await Promise.all([
|
||||
refreshTableContent(tableRoot),
|
||||
fetchNotifications(),
|
||||
]);
|
||||
|
||||
// Refocus on the link that as pressed in the first place.
|
||||
const exactMatch = updatedRoot.querySelector(
|
||||
`[data-action="move"][data-plugin="${actionLink.dataset.plugin}"][data-direction="${actionLink.dataset.direction}"]`
|
||||
);
|
||||
if (exactMatch) {
|
||||
exactMatch.focus();
|
||||
} else {
|
||||
// The move link is not present anymore, so we need to focus on the other one.
|
||||
updatedRoot.querySelector(`[data-action="move"][data-plugin="${actionLink.dataset.plugin}"]`)?.focus();
|
||||
}
|
||||
|
||||
pendingPromise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* Modal for theme previews.
|
||||
*
|
||||
* @module core_admin/themeselector/preview_modal
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import ModalEvents from 'core/modal_events';
|
||||
import ModalCancel from 'core/modal_cancel';
|
||||
import ModalSaveCancel from 'core/modal_save_cancel';
|
||||
import Notification from 'core/notification';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
|
||||
const SELECTORS = {
|
||||
THEMES_CONTAINER: 'themelist',
|
||||
PREVIEW: '[data-action="preview"]',
|
||||
};
|
||||
|
||||
/**
|
||||
* Entrypoint of the js.
|
||||
*
|
||||
* @method init
|
||||
*/
|
||||
export const init = () => {
|
||||
registerListenerEvents();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register theme related event listeners.
|
||||
*
|
||||
* @method registerListenerEvents
|
||||
*/
|
||||
const registerListenerEvents = () => {
|
||||
document.addEventListener('click', (e) => {
|
||||
const preview = e.target.closest(SELECTORS.PREVIEW);
|
||||
if (preview) {
|
||||
buildModal(preview).catch(Notification.exception);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the modal with the provided data.
|
||||
*
|
||||
* @method buildModal
|
||||
* @param {object} element
|
||||
*/
|
||||
const buildModal = async(element) => {
|
||||
|
||||
// This string can be long. We will fetch it with JS as opposed to passing it as an attribute.
|
||||
let description = await getString('choosereadme', 'theme_' + element.getAttribute('data-choose'));
|
||||
|
||||
const themesContainer = document.getElementById(SELECTORS.THEMES_CONTAINER);
|
||||
const definedInConfig = parseInt(themesContainer.dataset.definedinconfig);
|
||||
// Prepare data for modal.
|
||||
const data = {
|
||||
name: element.getAttribute('data-name'),
|
||||
image: element.getAttribute('data-image'),
|
||||
description: description.replace(/<[^>]+>/g, ' '), // Strip out HTML tags.
|
||||
current: element.getAttribute('data-current'),
|
||||
actionurl: element.getAttribute('data-actionurl'),
|
||||
choose: element.getAttribute('data-choose'),
|
||||
sesskey: element.getAttribute('data-sesskey'),
|
||||
definedinconfig: definedInConfig,
|
||||
};
|
||||
|
||||
// Determine which modal template we should use.
|
||||
let modalTemplate = ModalSaveCancel;
|
||||
if (data.current || data.definedinconfig) {
|
||||
modalTemplate = ModalCancel;
|
||||
}
|
||||
|
||||
const modal = await modalTemplate.create({
|
||||
title: data.name,
|
||||
body: Templates.render('core_admin/themeselector/theme_preview_modal', data),
|
||||
large: true,
|
||||
buttons: {
|
||||
'save': getString('selecttheme', 'moodle'),
|
||||
'cancel': getString('closebuttontitle', 'moodle'),
|
||||
},
|
||||
show: true,
|
||||
});
|
||||
|
||||
modal.getRoot().on(ModalEvents.save, () => {
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
/**
|
||||
* Edit configuration for an individual auth plugin
|
||||
*/
|
||||
|
||||
require_once '../config.php';
|
||||
require_once $CFG->libdir.'/adminlib.php';
|
||||
|
||||
$auth = required_param('auth', PARAM_PLUGIN);
|
||||
$PAGE->set_pagetype('admin-auth-' . $auth);
|
||||
|
||||
admin_externalpage_setup('authsetting'.$auth);
|
||||
|
||||
$authplugin = get_auth_plugin($auth);
|
||||
$err = array();
|
||||
|
||||
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageauths";
|
||||
|
||||
debugging("Use of config.html files in authentication plugins have been deprecated. " .
|
||||
" Please migrate your plugin to use the admin settings API", DEBUG_DEVELOPER);
|
||||
|
||||
// save configuration changes
|
||||
if ($frm = data_submitted() and confirm_sesskey()) {
|
||||
|
||||
$authplugin->validate_form($frm, $err);
|
||||
|
||||
if (count($err) == 0) {
|
||||
|
||||
// save plugin config
|
||||
if ($authplugin->process_config($frm)) {
|
||||
|
||||
// save field lock configuration
|
||||
foreach ($frm as $name => $value) {
|
||||
if (preg_match('/^lockconfig_(.+?)$/', $name, $matches)) {
|
||||
$plugin = "auth/$auth";
|
||||
$name = $matches[1];
|
||||
set_config($name, $value, $plugin);
|
||||
}
|
||||
}
|
||||
redirect($returnurl);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
foreach ($err as $key => $value) {
|
||||
$focus = "form.$key";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$frmlegacystyle = get_config('auth/'.$auth);
|
||||
$frmnewstyle = get_config('auth_'.$auth);
|
||||
$frm = (object)array_merge((array)$frmlegacystyle, (array)$frmnewstyle);
|
||||
}
|
||||
|
||||
$user_fields = $authplugin->userfields;
|
||||
//$user_fields = array("firstname", "lastname", "email", "phone1", "phone2", "institution", "department", "address", "city", "country", "description", "idnumber", "lang");
|
||||
|
||||
/// Get the auth title (from core or own auth lang files)
|
||||
$authtitle = $authplugin->get_title();
|
||||
/// Get the auth descriptions (from core or own auth lang files)
|
||||
$authdescription = $authplugin->get_description();
|
||||
|
||||
// output configuration form
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// choose an authentication method
|
||||
echo "<form id=\"authmenu\" method=\"post\" action=\"auth_config.php\">\n";
|
||||
echo "<div>\n";
|
||||
echo "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n";
|
||||
echo "<input type=\"hidden\" name=\"auth\" value=\"".$auth."\" />\n";
|
||||
|
||||
// auth plugin description
|
||||
echo $OUTPUT->box_start();
|
||||
echo $OUTPUT->heading($authtitle);
|
||||
echo $OUTPUT->box_start('informationbox');
|
||||
echo $authdescription;
|
||||
echo $OUTPUT->box_end();
|
||||
echo "<hr />\n";
|
||||
$authplugin->config_form($frm, $err, $user_fields);
|
||||
echo $OUTPUT->box_end();
|
||||
echo '<p style="text-align: center"><input type="submit" value="' . get_string("savechanges") . "\" /></p>\n";
|
||||
echo "</div>\n";
|
||||
echo "</form>\n";
|
||||
|
||||
$PAGE->requires->string_for_js('unmaskpassword', 'core_form');
|
||||
$PAGE->requires->yui_module('moodle-auth-passwordunmask', 'M.auth.passwordunmask');
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
|
||||
/// Functions /////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* auth field locking
|
||||
* Good enough for most auth plugins
|
||||
* but some may want a custom one if they are offering
|
||||
* other options
|
||||
* Note: lockconfig_ fields have special handling.
|
||||
*
|
||||
* @param string $auth authentication plugin shortname
|
||||
* @param array $user_fields user profile fields
|
||||
* @param string $helptext help text to be displayed at top of form
|
||||
* @param boolean $retrieveopts Map fields or lock only.
|
||||
* @param boolean $updateopts Allow remote updates
|
||||
* @param array $customfields list of custom profile fields
|
||||
* @deprecated since Moodle 3.3
|
||||
*/
|
||||
function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts, $updateopts, $customfields = array()) {
|
||||
global $DB, $OUTPUT;
|
||||
debugging("The function 'print_auth_lock_options' has been deprecated, " .
|
||||
"Please migrate your code to use the admin settings API and use the function 'display_auth_lock_options' instead. ",
|
||||
DEBUG_DEVELOPER);
|
||||
|
||||
echo '<tr><td colspan="3">';
|
||||
if ($retrieveopts) {
|
||||
echo $OUTPUT->heading(get_string('auth_data_mapping', 'auth'));
|
||||
} else {
|
||||
echo $OUTPUT->heading(get_string('auth_fieldlocks', 'auth'));
|
||||
}
|
||||
echo '</td></tr>';
|
||||
|
||||
$lockoptions = array ('unlocked' => get_string('unlocked', 'auth'),
|
||||
'unlockedifempty' => get_string('unlockedifempty', 'auth'),
|
||||
'locked' => get_string('locked', 'auth'));
|
||||
$updatelocaloptions = array('oncreate' => get_string('update_oncreate', 'auth'),
|
||||
'onlogin' => get_string('update_onlogin', 'auth'));
|
||||
$updateextoptions = array('0' => get_string('update_never', 'auth'),
|
||||
'1' => get_string('update_onupdate', 'auth'));
|
||||
|
||||
$pluginconfig = get_config("auth/$auth");
|
||||
|
||||
// Helptext is on a field with rowspan.
|
||||
if (empty($helptext)) {
|
||||
$helptext = ' ';
|
||||
}
|
||||
|
||||
// If we have custom fields then merge them with user fields.
|
||||
if (!empty($customfields)) {
|
||||
$user_fields = array_merge($user_fields, $customfields);
|
||||
}
|
||||
|
||||
if (!empty($customfields)) {
|
||||
$customfieldname = $DB->get_records('user_info_field', null, '', 'shortname, name');
|
||||
}
|
||||
foreach ($user_fields as $field) {
|
||||
// Define some vars we'll work with.
|
||||
if (!isset($pluginconfig->{"field_map_$field"})) {
|
||||
$pluginconfig->{"field_map_$field"} = '';
|
||||
}
|
||||
if (!isset($pluginconfig->{"field_updatelocal_$field"})) {
|
||||
$pluginconfig->{"field_updatelocal_$field"} = '';
|
||||
}
|
||||
if (!isset($pluginconfig->{"field_updateremote_$field"})) {
|
||||
$pluginconfig->{"field_updateremote_$field"} = '';
|
||||
}
|
||||
if (!isset($pluginconfig->{"field_lock_$field"})) {
|
||||
$pluginconfig->{"field_lock_$field"} = '';
|
||||
}
|
||||
|
||||
// Define the fieldname we display to the user.
|
||||
$fieldname = $field;
|
||||
if ($fieldname === 'lang') {
|
||||
$fieldname = get_string('language');
|
||||
} elseif (!empty($customfields) && in_array($field, $customfields)) {
|
||||
// If custom field then pick name from database.
|
||||
$fieldshortname = str_replace('profile_field_', '', $fieldname);
|
||||
$fieldname = $customfieldname[$fieldshortname]->name;
|
||||
if (core_text::strlen($fieldshortname) > 67) {
|
||||
// If custom profile field name is longer than 67 characters we will not be able to store the setting
|
||||
// such as 'field_updateremote_profile_field_NOTSOSHORTSHORTNAME' in the database because the character
|
||||
// limit for the setting name is 100.
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$fieldname = get_string($fieldname);
|
||||
}
|
||||
if ($retrieveopts) {
|
||||
$varname = 'field_map_' . $field;
|
||||
|
||||
echo '<tr valign="top"><td align="right">';
|
||||
echo '<label for="lockconfig_'.$varname.'">'.$fieldname.'</label>';
|
||||
echo '</td><td>';
|
||||
|
||||
echo "<input id=\"lockconfig_{$varname}\" name=\"lockconfig_{$varname}\" type=\"text\" size=\"30\" value=\"{$pluginconfig->$varname}\" />";
|
||||
echo '<div style="text-align: right">';
|
||||
echo '<label for="menulockconfig_field_updatelocal_'.$field.'">'.get_string('auth_updatelocal', 'auth') . '</label> ';
|
||||
echo html_writer::select($updatelocaloptions, "lockconfig_field_updatelocal_{$field}", $pluginconfig->{"field_updatelocal_$field"}, false);
|
||||
echo '<br />';
|
||||
if ($updateopts) {
|
||||
echo '<label for="menulockconfig_field_updateremote_'.$field.'">'.get_string('auth_updateremote', 'auth') . '</label> ';
|
||||
echo html_writer::select($updateextoptions, "lockconfig_field_updateremote_{$field}", $pluginconfig->{"field_updateremote_$field"}, false);
|
||||
echo '<br />';
|
||||
}
|
||||
echo '<label for="menulockconfig_field_lock_'.$field.'">'.get_string('auth_fieldlock', 'auth') . '</label> ';
|
||||
echo html_writer::select($lockoptions, "lockconfig_field_lock_{$field}", $pluginconfig->{"field_lock_$field"}, false);
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<tr valign="top"><td align="right">';
|
||||
echo '<label for="menulockconfig_field_lock_'.$field.'">'.$fieldname.'</label>';
|
||||
echo '</td><td>';
|
||||
echo html_writer::select($lockoptions, "lockconfig_field_lock_{$field}", $pluginconfig->{"field_lock_$field"}, false);
|
||||
}
|
||||
echo '</td>';
|
||||
if (!empty($helptext)) {
|
||||
echo '<td rowspan="' . count($user_fields) . '">' . $helptext . '</td>';
|
||||
$helptext = '';
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
+222
-77
@@ -1,94 +1,239 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Allows the admin to configure blocks (hide/show, uninstall and configure)
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
// Allows the admin to configure blocks (hide/show, uninstall and configure)
|
||||
|
||||
require_once('../config.php');
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
require_once("{$CFG->libdir}/blocklib.php");
|
||||
require_once("{$CFG->libdir}/tablelib.php");
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/blocklib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
admin_externalpage_setup('manageblocks');
|
||||
admin_externalpage_setup('manageblocks');
|
||||
|
||||
$plugin = optional_param('plugin', '', PARAM_PLUGIN);
|
||||
$action = optional_param('action', '', PARAM_ALPHA);
|
||||
$unprotect = optional_param('unprotect', 0, PARAM_PLUGIN);
|
||||
$protect = optional_param('protect', 0, PARAM_PLUGIN);
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
$hide = optional_param('hide', 0, PARAM_INT);
|
||||
$show = optional_param('show', 0, PARAM_INT);
|
||||
$unprotect = optional_param('unprotect', 0, PARAM_INT);
|
||||
$protect = optional_param('protect', 0, PARAM_INT);
|
||||
|
||||
$strmanageblocks = get_string('manageblocks');
|
||||
/// Print headings
|
||||
|
||||
// If data submitted, then process and store.
|
||||
if (!empty($plugin) && !empty($action) && confirm_sesskey()) {
|
||||
$manager = \core_plugin_manager::resolve_plugininfo_class('block');
|
||||
$pluginname = get_string('pluginname', "block_{$plugin}");
|
||||
$strmanageblocks = get_string('manageblocks');
|
||||
$struninstall = get_string('uninstallplugin', 'core_admin');
|
||||
$strversion = get_string('version');
|
||||
$strhide = get_string('hide');
|
||||
$strshow = get_string('show');
|
||||
$strsettings = get_string('settings');
|
||||
$strcourses = get_string('blockinstances', 'admin');
|
||||
$strname = get_string('name');
|
||||
$strshowblockcourse = get_string('showblockcourse');
|
||||
$strprotecthdr = get_string('blockprotect', 'admin'). $OUTPUT->help_icon('blockprotect','admin');
|
||||
$strprotect = get_string('blockprotect', 'admin');
|
||||
$strunprotect = get_string('blockunprotect', 'admin');
|
||||
|
||||
if ($action === 'disable' && $manager::enable_plugin($plugin, 0)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_disabled', 'core_admin', $pluginname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
} else if ($action === 'enable' && $manager::enable_plugin($plugin, 1)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_enabled', 'core_admin', $pluginname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
|
||||
// If data submitted, then process and store.
|
||||
if (!empty($hide) && confirm_sesskey()) {
|
||||
if (!$block = $DB->get_record('block', ['id' => $hide])) {
|
||||
throw new \moodle_exception('blockdoesnotexist', 'error');
|
||||
}
|
||||
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('block');
|
||||
$class::enable_plugin($block->name, false);
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
}
|
||||
|
||||
// Redirect back to the page with out any params.
|
||||
redirect(new moodle_url('/admin/blocks.php'));
|
||||
}
|
||||
if (!empty($show) && confirm_sesskey() ) {
|
||||
if (!$block = $DB->get_record('block', ['id' => $show])) {
|
||||
throw new \moodle_exception('blockdoesnotexist', 'error');
|
||||
}
|
||||
|
||||
if (!empty($protect) && confirm_sesskey()) {
|
||||
block_manager::protect_block($protect);
|
||||
$pluginname = get_string('pluginname', "block_{$protect}");
|
||||
\core\notification::add(
|
||||
get_string('blockprotected', 'core_admin', $pluginname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
}
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('block');
|
||||
$class::enable_plugin($block->name, true);
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
}
|
||||
|
||||
if (!empty($unprotect) && confirm_sesskey()) {
|
||||
block_manager::unprotect_block($unprotect);
|
||||
$pluginname = get_string('pluginname', "block_{$unprotect}");
|
||||
\core\notification::add(
|
||||
get_string('blockunprotected', 'core_admin', $pluginname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
}
|
||||
if (!empty($protect) && confirm_sesskey()) {
|
||||
block_manager::protect_block((int)$protect);
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strmanageblocks);
|
||||
echo $OUTPUT->notification(get_string('noteunneededblocks', 'admin'), 'info', false);
|
||||
if (!empty($unprotect) && confirm_sesskey()) {
|
||||
block_manager::unprotect_block((int)$unprotect);
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
}
|
||||
|
||||
// Print the table of all blocks.
|
||||
$table = new \core_admin\table\block_management_table();
|
||||
$table->out();
|
||||
echo $OUTPUT->footer();
|
||||
$undeletableblocktypes = block_manager::get_undeletable_block_types();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strmanageblocks);
|
||||
|
||||
echo $OUTPUT->notification(get_string('noteunneededblocks', 'admin'), 'info');
|
||||
/// Main display starts here
|
||||
|
||||
/// Get and sort the existing blocks
|
||||
|
||||
if (!$blocks = $DB->get_records('block', array(), 'name ASC')) {
|
||||
throw new \moodle_exception('noblocks', 'error'); // Should never happen.
|
||||
}
|
||||
|
||||
$incompatible = array();
|
||||
|
||||
/// Print the table of all blocks
|
||||
|
||||
$table = new flexible_table('admin-blocks-compatible');
|
||||
|
||||
$table->define_columns(array('name', 'instances', 'version', 'hideshow', 'undeletable', 'settings', 'uninstall'));
|
||||
$table->define_headers(array($strname, $strcourses, $strversion, $strhide.'/'.$strshow, $strprotecthdr, $strsettings, $struninstall));
|
||||
$table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/blocks.php');
|
||||
$table->set_attribute('class', 'admintable blockstable generaltable');
|
||||
$table->set_attribute('id', 'compatibleblockstable');
|
||||
$table->setup();
|
||||
$tablerows = array();
|
||||
|
||||
// Sort blocks using current locale.
|
||||
$blocknames = array();
|
||||
foreach ($blocks as $blockid=>$block) {
|
||||
$blockname = $block->name;
|
||||
if (file_exists("$CFG->dirroot/blocks/$blockname/block_$blockname.php")) {
|
||||
$blocknames[$blockid] = get_string('pluginname', 'block_'.$blockname);
|
||||
} else {
|
||||
$blocknames[$blockid] = $blockname;
|
||||
}
|
||||
}
|
||||
core_collator::asort($blocknames);
|
||||
|
||||
foreach ($blocknames as $blockid=>$strblockname) {
|
||||
$block = $blocks[$blockid];
|
||||
$blockname = $block->name;
|
||||
$dbversion = get_config('block_'.$block->name, 'version');
|
||||
|
||||
if (!file_exists("$CFG->dirroot/blocks/$blockname/block_$blockname.php")) {
|
||||
$blockobject = false;
|
||||
$strblockname = '<span class="notifyproblem">'.$strblockname.' ('.get_string('missingfromdisk').')</span>';
|
||||
$plugin = new stdClass();
|
||||
$plugin->version = $dbversion;
|
||||
|
||||
} else {
|
||||
$plugin = new stdClass();
|
||||
$plugin->version = '???';
|
||||
if (file_exists("$CFG->dirroot/blocks/$blockname/version.php")) {
|
||||
include("$CFG->dirroot/blocks/$blockname/version.php");
|
||||
}
|
||||
|
||||
if (!$blockobject = block_instance($block->name)) {
|
||||
$incompatible[] = $block;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('block_'.$blockname, 'manage')) {
|
||||
$uninstall = html_writer::link($uninstallurl, $struninstall);
|
||||
} else {
|
||||
$uninstall = '';
|
||||
}
|
||||
|
||||
$settings = ''; // By default, no configuration
|
||||
if ($blockobject and $blockobject->has_config()) {
|
||||
$blocksettings = admin_get_root()->locate('blocksetting' . $block->name);
|
||||
|
||||
if ($blocksettings instanceof admin_externalpage) {
|
||||
$settings = '<a href="' . $blocksettings->url . '">' . get_string('settings') . '</a>';
|
||||
} else if ($blocksettings instanceof admin_settingpage) {
|
||||
$settings = '<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksetting'.$block->name.'">'.$strsettings.'</a>';
|
||||
} else if (!file_exists($CFG->dirroot.'/blocks/'.$block->name.'/settings.php')) {
|
||||
// If the block's settings node was not found, we check that the block really provides the settings.php file.
|
||||
// Note that blocks can inject their settings to other nodes in the admin tree without using the default locations.
|
||||
// This can be done by assigning null to $setting in settings.php and it is a valid case.
|
||||
debugging('Warning: block_'.$block->name.' returns true in has_config() but does not provide a settings.php file',
|
||||
DEBUG_DEVELOPER);
|
||||
}
|
||||
}
|
||||
|
||||
// MDL-11167, blocks can be placed on mymoodle, or the blogs page
|
||||
// and it should not show up on course search page
|
||||
|
||||
$totalcount = $DB->count_records('block_instances', array('blockname'=>$blockname));
|
||||
$count = $DB->count_records('block_instances', array('blockname'=>$blockname, 'pagetypepattern'=>'course-view-*'));
|
||||
|
||||
if ($count>0) {
|
||||
$blocklist = "<a href=\"{$CFG->wwwroot}/course/search.php?blocklist=$blockid&sesskey=".sesskey()."\" ";
|
||||
$blocklist .= "title=\"$strshowblockcourse\" >$totalcount</a>";
|
||||
}
|
||||
else {
|
||||
$blocklist = "$totalcount";
|
||||
}
|
||||
$class = ''; // Nothing fancy, by default
|
||||
|
||||
if (!$blockobject) {
|
||||
// ignore
|
||||
$visible = '';
|
||||
} else if ($blocks[$blockid]->visible) {
|
||||
$visible = '<a href="blocks.php?hide='.$blockid.'&sesskey='.sesskey().'" title="'.$strhide.'">'.
|
||||
$OUTPUT->pix_icon('t/hide', $strhide) . '</a>';
|
||||
} else {
|
||||
$visible = '<a href="blocks.php?show='.$blockid.'&sesskey='.sesskey().'" title="'.$strshow.'">'.
|
||||
$OUTPUT->pix_icon('t/show', $strshow) . '</a>';
|
||||
$class = 'dimmed_text';
|
||||
}
|
||||
|
||||
if ($dbversion == $plugin->version) {
|
||||
$version = $dbversion;
|
||||
} else {
|
||||
$version = "$dbversion ($plugin->version)";
|
||||
}
|
||||
|
||||
if (!$blockobject) {
|
||||
// ignore
|
||||
$undeletable = '';
|
||||
} else if (in_array($blockname, $undeletableblocktypes)) {
|
||||
$undeletable = '<a href="blocks.php?unprotect='.$blockid.'&sesskey='.sesskey().'" title="'.$strunprotect.'">'.
|
||||
$OUTPUT->pix_icon('t/unlock', $strunprotect) . '</a>';
|
||||
} else {
|
||||
$undeletable = '<a href="blocks.php?protect='.$blockid.'&sesskey='.sesskey().'" title="'.$strprotect.'">'.
|
||||
$OUTPUT->pix_icon('t/lock', $strprotect) . '</a>';
|
||||
}
|
||||
|
||||
$row = array(
|
||||
$strblockname,
|
||||
$blocklist,
|
||||
$version,
|
||||
$visible,
|
||||
$undeletable,
|
||||
$settings,
|
||||
$uninstall,
|
||||
);
|
||||
$table->add_data($row, $class);
|
||||
}
|
||||
|
||||
$table->print_html();
|
||||
|
||||
if (!empty($incompatible)) {
|
||||
echo $OUTPUT->heading(get_string('incompatibleblocks', 'blockstable', 'admin'));
|
||||
|
||||
$table = new flexible_table('admin-blocks-incompatible');
|
||||
|
||||
$table->define_columns(array('block', 'uninstall'));
|
||||
$table->define_headers(array($strname, $struninstall));
|
||||
$table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/blocks.php');
|
||||
|
||||
$table->set_attribute('class', 'incompatibleblockstable generaltable');
|
||||
|
||||
$table->setup();
|
||||
|
||||
foreach ($incompatible as $block) {
|
||||
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('block_'.$block->name, 'manage')) {
|
||||
$uninstall = html_writer::link($uninstallurl, $struninstall);
|
||||
} else {
|
||||
$uninstall = '';
|
||||
}
|
||||
$table->add_data(array(
|
||||
$block->name,
|
||||
$uninstall,
|
||||
));
|
||||
}
|
||||
$table->print_html();
|
||||
}
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
+2
-1
@@ -131,7 +131,8 @@ if ($savebutton) {
|
||||
$outputhtml .= html_writer::end_tag('div');
|
||||
}
|
||||
|
||||
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $settingspage->visiblepath));
|
||||
$visiblepathtosection = array_reverse($settingspage->visiblepath);
|
||||
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
if ($buttons) {
|
||||
$PAGE->set_button($buttons);
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
<?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 core_admin\admin;
|
||||
|
||||
use admin_setting;
|
||||
use core_plugin_manager;
|
||||
use core_text;
|
||||
|
||||
/**
|
||||
* Admin setting plugin manager.
|
||||
*
|
||||
* @package core_admin
|
||||
* @subpackage admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class admin_setting_plugin_manager extends admin_setting {
|
||||
/** @var core_plugin_manager The plugin manager instance */
|
||||
protected core_plugin_manager $pluginmanager;
|
||||
|
||||
/** @var string The plugintype that this manager covers */
|
||||
protected string $plugintype;
|
||||
|
||||
/** @var string The class of the management table to use */
|
||||
protected string $tableclass;
|
||||
|
||||
public function __construct(
|
||||
string $plugintype,
|
||||
string $tableclass,
|
||||
string $name,
|
||||
string $visiblename,
|
||||
string $description = '',
|
||||
string $defaultsetting = '',
|
||||
) {
|
||||
$this->nosave = true;
|
||||
$this->pluginmanager = core_plugin_manager::instance();
|
||||
$this->plugintype = $plugintype;
|
||||
$this->tableclass = $tableclass;
|
||||
|
||||
parent::__construct($name, $visiblename, $description, $defaultsetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns true, does nothing
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function get_setting(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns true, does nothing
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function get_defaultsetting(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns '', does not write anything
|
||||
*
|
||||
* @return string Always returns ''
|
||||
*/
|
||||
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
public function write_setting($data): string {
|
||||
// Do not write any setting.
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if $query is one of the available editors
|
||||
*
|
||||
* @param string $query The string to search for
|
||||
* @return bool Returns true if found, false if not
|
||||
*/
|
||||
public function is_related($query) {
|
||||
if (parent::is_related($query)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$plugins = $this->pluginmanager->get_installed_plugins($this->plugintype);
|
||||
foreach (array_keys($plugins) as $plugin) {
|
||||
$plugin = "{$this->plugintype}_{$plugin}";
|
||||
if (str_contains($plugin, $query)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$pluginname = get_string('pluginname', $plugin);
|
||||
if (strpos(core_text::strtolower($pluginname), $query) !== false) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the XHTML to display the control
|
||||
*
|
||||
* @param string $data Unused
|
||||
* @param string $query
|
||||
* @return string
|
||||
*/
|
||||
public function output_html($data, $query = ''): string {
|
||||
$table = new $this->tableclass();
|
||||
if (!($table instanceof \core_admin\table\plugin_management_table)) {
|
||||
throw new \coding_exception("{$this->tableclass} must be an instance of \\core_admin\\table\\plugin_management_table");
|
||||
}
|
||||
return highlight($query, $table->get_content());
|
||||
}
|
||||
}
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
<?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 core_admin\external;
|
||||
|
||||
use block_manager;
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_value;
|
||||
|
||||
/**
|
||||
* Web Service to control the state of a plugin.
|
||||
*
|
||||
* @package core_admin
|
||||
* @category external
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_block_protection extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'plugin' => new external_value(PARAM_PLUGIN, 'The name of the plugin', VALUE_REQUIRED),
|
||||
'state' => new external_value(PARAM_INT, 'The target state', VALUE_REQUIRED),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block protection state.
|
||||
*
|
||||
* @param string $plugin The name of the plugin
|
||||
* @param int $state The target state
|
||||
* @return null
|
||||
*/
|
||||
public static function execute(
|
||||
string $plugin,
|
||||
int $state,
|
||||
): array {
|
||||
[
|
||||
'plugin' => $plugin,
|
||||
'state' => $state,
|
||||
] = self::validate_parameters(self::execute_parameters(), [
|
||||
'plugin' => $plugin,
|
||||
'state' => $state,
|
||||
]);
|
||||
|
||||
$context = \context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
[, $pluginname] = explode('_', \core_component::normalize_componentname($plugin), 2);
|
||||
$displayname = get_string('pluginname', $plugin);
|
||||
|
||||
if ($state) {
|
||||
block_manager::protect_block($pluginname);
|
||||
\core\notification::add(
|
||||
get_string('blockprotected', 'core_admin', $displayname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
} else {
|
||||
block_manager::unprotect_block($pluginname);
|
||||
\core\notification::add(
|
||||
get_string('blockunprotected', 'core_admin', $displayname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([]);
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
<?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 core_admin\external;
|
||||
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_value;
|
||||
|
||||
/**
|
||||
* Web Service to control the order of a plugin.
|
||||
*
|
||||
* @package core_admin
|
||||
* @category external
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_plugin_order extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'plugin' => new external_value(PARAM_PLUGIN, 'The name of the plugin', VALUE_REQUIRED),
|
||||
'direction' => new external_value(PARAM_INT, 'The direction to move', VALUE_REQUIRED),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the plugin state.
|
||||
*
|
||||
* @param string $plugin The name of the plugin
|
||||
* @param int $direction The direction to move the plugin
|
||||
* @return array
|
||||
*/
|
||||
public static function execute(
|
||||
string $plugin,
|
||||
int $direction,
|
||||
): array {
|
||||
[
|
||||
'plugin' => $plugin,
|
||||
'direction' => $direction,
|
||||
] = self::validate_parameters(self::execute_parameters(), [
|
||||
'plugin' => $plugin,
|
||||
'direction' => $direction,
|
||||
]);
|
||||
|
||||
$context = \context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
[$plugintype, $pluginname] = explode('_', \core_component::normalize_componentname($plugin), 2);
|
||||
|
||||
$manager = \core_plugin_manager::resolve_plugininfo_class($plugintype);
|
||||
$manager::change_plugin_order($pluginname, $direction);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([]);
|
||||
}
|
||||
}
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
<?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 core_admin\external;
|
||||
|
||||
use core_external\external_api;
|
||||
use core_external\external_function_parameters;
|
||||
use core_external\external_single_structure;
|
||||
use core_external\external_value;
|
||||
|
||||
/**
|
||||
* Web Service to control the state of a plugin.
|
||||
*
|
||||
* @package core_admin
|
||||
* @category external
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class set_plugin_state extends external_api {
|
||||
/**
|
||||
* Returns description of method parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
*/
|
||||
public static function execute_parameters(): external_function_parameters {
|
||||
return new external_function_parameters([
|
||||
'plugin' => new external_value(PARAM_PLUGIN, 'The name of the plugin', VALUE_REQUIRED),
|
||||
'state' => new external_value(PARAM_INT, 'The target state', VALUE_REQUIRED),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the plugin state.
|
||||
*
|
||||
* @param string $plugin The name of the plugin
|
||||
* @param int $state The target state
|
||||
* @return null
|
||||
*/
|
||||
public static function execute(
|
||||
string $plugin,
|
||||
int $state,
|
||||
): array {
|
||||
[
|
||||
'plugin' => $plugin,
|
||||
'state' => $state,
|
||||
] = self::validate_parameters(self::execute_parameters(), [
|
||||
'plugin' => $plugin,
|
||||
'state' => $state,
|
||||
]);
|
||||
|
||||
$context = \context_system::instance();
|
||||
self::validate_context($context);
|
||||
require_capability('moodle/site:config', $context);
|
||||
|
||||
[$plugintype, $pluginname] = explode('_', \core_component::normalize_componentname($plugin), 2);
|
||||
|
||||
$manager = \core_plugin_manager::resolve_plugininfo_class($plugintype);
|
||||
$displayname = get_string('pluginname', $plugin);
|
||||
|
||||
if ($manager::enable_plugin($pluginname, $state)) {
|
||||
if (!empty($state)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_enabled', 'core_admin', $displayname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
} else {
|
||||
\core\notification::add(
|
||||
get_string('plugin_disabled', 'core_admin', $displayname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the return structure of the external service.
|
||||
*
|
||||
* @return external_single_structure
|
||||
*/
|
||||
public static function execute_returns(): external_single_structure {
|
||||
return new external_single_structure([]);
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?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 core_admin\output;
|
||||
|
||||
use moodle_url;
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use templatable;
|
||||
|
||||
/**
|
||||
* Theme selector renderable.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class theme_selector implements renderable, templatable {
|
||||
|
||||
/** @var array $themedata Theme data to pass to the template. */
|
||||
private $themedata = null;
|
||||
|
||||
/** @var bool Whether $CFG->theme is defined in config.php. */
|
||||
private $definedinconfig;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $themedata Theme data used for template.
|
||||
* @param bool $definedinconfig Whether $CFG->theme is defined in config.php.
|
||||
*/
|
||||
public function __construct(array $themedata, bool $definedinconfig = false) {
|
||||
$this->themedata = $themedata;
|
||||
$this->definedinconfig = $definedinconfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output Renderer base.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
|
||||
$data = new stdClass();
|
||||
// Theme data used to populate cards and modal.
|
||||
$data->themes = $this->themedata;
|
||||
// Reset theme caches button.
|
||||
$reseturl = new moodle_url('/admin/themeselector.php', ['sesskey' => sesskey(), 'reset' => 1]);
|
||||
$resetbutton = new \single_button($reseturl, get_string('themeresetcaches', 'admin'), 'post',
|
||||
\single_button::BUTTON_SECONDARY);
|
||||
$data->resetbutton = $resetbutton->export_for_template($output);
|
||||
$data->definedinconfig = $this->definedinconfig;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,17 +78,6 @@ class task_logs extends datasource {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column sorting that will be added to the report upon creation
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function get_default_column_sorting(): array {
|
||||
return [
|
||||
'task_log:starttime' => SORT_DESC,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filters that will be added to the report upon creation
|
||||
*
|
||||
|
||||
@@ -46,14 +46,12 @@ class task_log extends base {
|
||||
protected const FAILED = 1;
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return string[]
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_tables(): array {
|
||||
return [
|
||||
'task_log',
|
||||
];
|
||||
protected function get_default_table_aliases(): array {
|
||||
return ['task_log' => 'tl'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
<?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 core_admin\reportbuilder\local\filters;
|
||||
|
||||
use core\context\system;
|
||||
use core_course_category;
|
||||
use MoodleQuickForm;
|
||||
use core_reportbuilder\local\filters\base;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
|
||||
/**
|
||||
* Course role report filter (by role, category, course)
|
||||
*
|
||||
* The provided filter field SQL must refer/return an expression for the user ID (e.g. "{$user}.id")
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class courserole extends base {
|
||||
|
||||
/**
|
||||
* Setup form
|
||||
*
|
||||
* @param MoodleQuickForm $mform
|
||||
*/
|
||||
public function setup_form(MoodleQuickForm $mform): void {
|
||||
$elements = [];
|
||||
|
||||
// Role.
|
||||
$elements['role'] = $mform->createElement('select', "{$this->name}_role", get_string('rolefullname', 'core_role'),
|
||||
[0 => get_string('anyrole', 'core_filters')] + get_default_enrol_roles(system::instance()));
|
||||
|
||||
// Category.
|
||||
$elements['category'] = $mform->createElement('select', "{$this->name}_category", get_string('category'),
|
||||
[0 => get_string('anycategory', 'core_filters')] + core_course_category::make_categories_list());
|
||||
|
||||
// Course.
|
||||
$elements['course'] = $mform->createElement('text', "{$this->name}_course", get_string('shortnamecourse'));
|
||||
$mform->setType("{$this->name}_course", PARAM_RAW_TRIMMED);
|
||||
|
||||
$mform->addGroup($elements, "{$this->name}_group", $this->get_header(), '', false)
|
||||
->setHiddenLabel(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return filter SQL
|
||||
*
|
||||
* @param array $values
|
||||
* @return array
|
||||
*/
|
||||
public function get_sql_filter(array $values): array {
|
||||
[$fieldsql, $params] = $this->filter->get_field_sql_and_params();
|
||||
|
||||
[$contextalias, $rolealias, $coursealias] = database::generate_aliases(3);
|
||||
[$roleparam, $categoryparam, $courseparam] = database::generate_param_names(3);
|
||||
|
||||
// Role.
|
||||
$role = (int) ($values["{$this->name}_role"] ?? 0);
|
||||
if ($role > 0) {
|
||||
$selects[] = "{$rolealias}.roleid = :{$roleparam}";
|
||||
$params[$roleparam] = $role;
|
||||
}
|
||||
|
||||
// Category.
|
||||
$category = (int) ($values["{$this->name}_category"] ?? 0);
|
||||
if ($category > 0) {
|
||||
$selects[] = "{$coursealias}.category = :{$categoryparam}";
|
||||
$params[$categoryparam] = $category;
|
||||
}
|
||||
|
||||
// Course.
|
||||
$course = trim($values["{$this->name}_course"] ?? '');
|
||||
if ($course !== '') {
|
||||
$selects[] = "{$coursealias}.shortname = :{$courseparam}";
|
||||
$params[$courseparam] = $course;
|
||||
}
|
||||
|
||||
// Filter values are not set.
|
||||
if (empty($selects)) {
|
||||
return ['', []];
|
||||
}
|
||||
|
||||
return ["{$fieldsql} IN (
|
||||
SELECT {$rolealias}.userid
|
||||
FROM {role_assignments} {$rolealias}
|
||||
JOIN {context} {$contextalias} ON {$contextalias}.id = {$rolealias}.contextid AND {$contextalias}.contextlevel = 50
|
||||
JOIN {course} {$coursealias} ON {$coursealias}.id = {$contextalias}.instanceid
|
||||
WHERE " . implode(' AND ', $selects) . "
|
||||
)", $params];
|
||||
}
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
<?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 core_admin\reportbuilder\local\systemreports;
|
||||
|
||||
use core_admin\reportbuilder\local\filters\courserole;
|
||||
use core\context\system;
|
||||
use core_cohort\reportbuilder\local\entities\cohort;
|
||||
use core_cohort\reportbuilder\local\entities\cohort_member;
|
||||
use core_reportbuilder\local\entities\user;
|
||||
use core_reportbuilder\local\filters\boolean_select;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
use core_reportbuilder\local\helpers\user_profile_fields;
|
||||
use core_reportbuilder\local\report\action;
|
||||
use core_reportbuilder\local\report\filter;
|
||||
use core_reportbuilder\system_report;
|
||||
use core_role\reportbuilder\local\entities\role;
|
||||
use core_user\fields;
|
||||
use lang_string;
|
||||
use moodle_url;
|
||||
use pix_icon;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/authlib.php');
|
||||
require_once($CFG->libdir.'/enrollib.php');
|
||||
require_once($CFG->dirroot.'/user/lib.php');
|
||||
|
||||
/**
|
||||
* Browse users system report class implementation
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 David Carrillo <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class users extends system_report {
|
||||
|
||||
/**
|
||||
* Initialise report, we need to set the main table, load our entities and set columns/filters
|
||||
*/
|
||||
protected function initialise(): void {
|
||||
global $CFG;
|
||||
|
||||
// Our main entity, it contains all of the column definitions that we need.
|
||||
$entityuser = new user();
|
||||
$entityuseralias = $entityuser->get_table_alias('user');
|
||||
|
||||
$this->set_main_table('user', $entityuseralias);
|
||||
$this->add_entity($entityuser);
|
||||
|
||||
// Any columns required by actions should be defined here to ensure they're always available.
|
||||
$fullnamefields = array_map(fn($field) => "{$entityuseralias}.{$field}", fields::get_name_fields());
|
||||
$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]);
|
||||
|
||||
$entitycohortmember = new cohort_member();
|
||||
$entitycohortmemberalias = $entitycohortmember->get_table_alias('cohort_members');
|
||||
$this->add_entity($entitycohortmember
|
||||
->add_joins($entitycohortmember->get_joins())
|
||||
->add_join("LEFT JOIN {cohort_members} {$entitycohortmemberalias}
|
||||
ON {$entityuseralias}.id = {$entitycohortmemberalias}.userid")
|
||||
);
|
||||
|
||||
$entitycohort = new cohort();
|
||||
$entitycohortalias = $entitycohort->get_table_alias('cohort');
|
||||
$this->add_entity($entitycohort
|
||||
->add_joins($entitycohort->get_joins())
|
||||
->add_joins($entitycohortmember->get_joins())
|
||||
->add_join("LEFT JOIN {cohort} {$entitycohortalias}
|
||||
ON {$entitycohortalias}.id = {$entitycohortmemberalias}.cohortid")
|
||||
);
|
||||
|
||||
// Join the role entity (Needed for the system role filter).
|
||||
$roleentity = new role();
|
||||
$role = $roleentity->get_table_alias('role');
|
||||
$this->add_entity($roleentity
|
||||
->add_join("LEFT JOIN (
|
||||
SELECT DISTINCT r0.id, ras.userid
|
||||
FROM {role} r0
|
||||
JOIN {role_assignments} ras ON ras.roleid = r0.id
|
||||
WHERE ras.contextid = ".SYSCONTEXTID."
|
||||
) {$role} ON {$role}.userid = {$entityuseralias}.id")
|
||||
);
|
||||
|
||||
// Now we can call our helper methods to add the content we want to include in the report.
|
||||
$this->add_columns();
|
||||
$this->add_filters();
|
||||
$this->add_actions();
|
||||
|
||||
// Set if report can be downloaded.
|
||||
$this->set_downloadable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates access to view this report
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function can_view(): bool {
|
||||
return has_any_capability(['moodle/user:update', 'moodle/user:delete'], system::instance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the columns we want to display in the report
|
||||
*
|
||||
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
|
||||
* unique identifier
|
||||
*/
|
||||
public function add_columns(): void {
|
||||
$entityuser = $this->get_entity('user');
|
||||
$entityuseralias = $entityuser->get_table_alias('user');
|
||||
|
||||
$this->add_column($entityuser->get_column('fullnamewithpicturelink'));
|
||||
|
||||
// Include identity field columns.
|
||||
$identitycolumns = $entityuser->get_identity_columns($this->get_context());
|
||||
foreach ($identitycolumns as $identitycolumn) {
|
||||
$this->add_column($identitycolumn);
|
||||
}
|
||||
|
||||
// Add "Last access" column.
|
||||
$this->add_column(($entityuser->get_column('lastaccess'))
|
||||
->set_callback(static function ($value, \stdClass $row): string {
|
||||
if ($row->lastaccess) {
|
||||
return format_time(time() - $row->lastaccess);
|
||||
}
|
||||
return get_string('never');
|
||||
})
|
||||
);
|
||||
|
||||
if ($column = $this->get_column('user:fullnamewithpicturelink')) {
|
||||
$column
|
||||
->add_fields("{$entityuseralias}.suspended, {$entityuseralias}.confirmed")
|
||||
->add_callback(static function(string $fullname, \stdClass $row): string {
|
||||
if ($row->suspended) {
|
||||
$fullname .= ' ' . \html_writer::tag('span', get_string('suspended', 'moodle'),
|
||||
['class' => 'badge badge-secondary ml-1']);
|
||||
}
|
||||
if (!$row->confirmed) {
|
||||
$fullname .= ' ' . \html_writer::tag('span', get_string('confirmationpending', 'admin'),
|
||||
['class' => 'badge badge-danger ml-1']);
|
||||
}
|
||||
return $fullname;
|
||||
});
|
||||
}
|
||||
|
||||
$this->set_initial_sort_column('user:fullnamewithpicturelink', SORT_ASC);
|
||||
$this->set_default_no_results_notice(new lang_string('nousersfound', 'moodle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the filters we want to display in the report
|
||||
*
|
||||
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$entityuser = $this->get_entity('user');
|
||||
$entityuseralias = $entityuser->get_table_alias('user');
|
||||
|
||||
$filters = [
|
||||
'user:firstname',
|
||||
'user:lastname',
|
||||
'user:username',
|
||||
'user:idnumber',
|
||||
'user:email',
|
||||
'user:department',
|
||||
'user:institution',
|
||||
'user:city',
|
||||
'user:country',
|
||||
'user:confirmed',
|
||||
'user:suspended',
|
||||
'user:timecreated',
|
||||
'user:lastaccess',
|
||||
'user:timemodified',
|
||||
'user:auth',
|
||||
'user:lastip',
|
||||
'cohort:idnumber',
|
||||
'role:name',
|
||||
];
|
||||
$this->add_filters_from_entities($filters);
|
||||
|
||||
// Enrolled in any course filter.
|
||||
$ue = database::generate_alias();
|
||||
[$now1, $now2] = database::generate_param_names(2);
|
||||
$now = time();
|
||||
$sql = "CASE WHEN ({$entityuseralias}.id IN (
|
||||
SELECT userid FROM {user_enrolments} {$ue}
|
||||
WHERE {$ue}.status = " . ENROL_USER_ACTIVE . "
|
||||
AND ({$ue}.timestart = 0 OR {$ue}.timestart < :{$now1})
|
||||
AND ({$ue}.timeend = 0 OR {$ue}.timeend > :{$now2})
|
||||
)) THEN 1 ELSE 0 END";
|
||||
|
||||
$this->add_filter((new filter(
|
||||
boolean_select::class,
|
||||
'enrolledinanycourse',
|
||||
new lang_string('anycourses', 'filters'),
|
||||
$this->get_entity('user')->get_entity_name(),
|
||||
))
|
||||
->set_field_sql($sql, [
|
||||
$now1 => $now,
|
||||
$now2 => $now,
|
||||
])
|
||||
);
|
||||
|
||||
// Course role filter.
|
||||
$this->add_filter((new filter(
|
||||
courserole::class,
|
||||
'courserole',
|
||||
new lang_string('courserole', 'filters'),
|
||||
$this->get_entity('user')->get_entity_name(),
|
||||
))
|
||||
->set_field_sql("{$entityuseralias}.id")
|
||||
);
|
||||
|
||||
// Add user profile fields filters.
|
||||
$userprofilefields = new user_profile_fields($entityuseralias . '.id', $entityuser->get_entity_name());
|
||||
foreach ($userprofilefields->get_filters() as $filter) {
|
||||
$this->add_filter($filter);
|
||||
}
|
||||
|
||||
// Set options for system role filter.
|
||||
if ($filter = $this->get_filter('role:name')) {
|
||||
$filter
|
||||
->set_header(new lang_string('globalrole', 'role'))
|
||||
->set_options(get_assignable_roles(system::instance()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the system report actions. An extra column will be appended to each row, containing all actions added here
|
||||
*
|
||||
* Note the use of ":id" placeholder which will be substituted according to actual values in the row
|
||||
*/
|
||||
protected function add_actions(): void {
|
||||
global $DB, $USER;
|
||||
|
||||
$contextsystem = system::instance();
|
||||
|
||||
// Action to edit users.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/user/editadvanced.php', ['id' => ':id', 'course' => get_site()->id]),
|
||||
new pix_icon('t/edit', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('edit', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && (is_siteadmin($USER) || !is_siteadmin($row));
|
||||
}));
|
||||
|
||||
// Action to suspend users (non mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['suspend' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/show', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('suspenduser', 'admin'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended && !is_mnet_remote_user($row) &&
|
||||
!($row->id == $USER->id || is_siteadmin($row));
|
||||
}));
|
||||
|
||||
// Action to unsuspend users (non mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['unsuspend' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/hide', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('unsuspenduser', 'admin'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && $row->suspended && !is_mnet_remote_user($row) &&
|
||||
!($row->id == $USER->id || is_siteadmin($row));
|
||||
}));
|
||||
|
||||
// Action to unlock users (non mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['unlock' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/unlock', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('unlockaccount', 'admin'),
|
||||
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && !is_mnet_remote_user($row) &&
|
||||
login_is_lockedout($row);
|
||||
}));
|
||||
|
||||
// Action to suspend users (mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'deny']),
|
||||
new pix_icon('t/show', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('denyaccess', 'mnet'),
|
||||
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
|
||||
if (!$accessctrl = $DB->get_field(table: 'mnet_sso_access_control', return: 'accessctrl',
|
||||
conditions: ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]
|
||||
)) {
|
||||
$accessctrl = 'allow';
|
||||
}
|
||||
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
|
||||
is_mnet_remote_user($row) && $accessctrl == 'allow';
|
||||
}));
|
||||
|
||||
// Action to unsuspend users (mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'allow']),
|
||||
new pix_icon('t/hide', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('allowaccess', 'mnet'),
|
||||
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
|
||||
if (!$accessctrl = $DB->get_field(table: 'mnet_sso_access_control', return: 'accessctrl',
|
||||
conditions: ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]
|
||||
)) {
|
||||
$accessctrl = 'allow';
|
||||
}
|
||||
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
|
||||
is_mnet_remote_user($row) && $accessctrl == 'deny';
|
||||
}));
|
||||
|
||||
// Action to delete users.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['delete' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/delete', ''),
|
||||
[
|
||||
'class' => 'text-danger',
|
||||
'data-modal' => 'confirmation',
|
||||
'data-modal-title-str' => json_encode(['deleteuser', 'admin']),
|
||||
'data-modal-content-str' => ':deletestr',
|
||||
'data-modal-yes-button-str' => json_encode(['delete', 'core']),
|
||||
'data-modal-destination' => ':deleteurl',
|
||||
|
||||
],
|
||||
false,
|
||||
new lang_string('delete', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
|
||||
// Populate deletion modal attributes.
|
||||
$row->deletestr = json_encode([
|
||||
'deletecheckfull',
|
||||
'moodle',
|
||||
fullname($row, true),
|
||||
]);
|
||||
|
||||
$row->deleteurl = (new moodle_url('/admin/user.php', [
|
||||
'delete' => $row->id,
|
||||
'confirm' => md5($row->id),
|
||||
'sesskey' => sesskey(),
|
||||
]))->out(false);
|
||||
|
||||
return has_capability('moodle/user:delete', $contextsystem) &&
|
||||
!is_mnet_remote_user($row) && $row->id != $USER->id && !is_siteadmin($row);
|
||||
}));
|
||||
|
||||
$this->add_action_divider();
|
||||
|
||||
// Action to confirm users.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['confirmuser' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/check', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('confirmaccount', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->confirmed;
|
||||
}));
|
||||
|
||||
// Action to resend email.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['resendemail' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/email', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('resendemail', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row): bool {
|
||||
return !$row->confirmed && !is_mnet_remote_user($row);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Row class
|
||||
*
|
||||
* @param \stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
public function get_row_class(\stdClass $row): string {
|
||||
return $row->suspended ? 'text-muted' : '';
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use core_plugin_manager;
|
||||
use dml_exception;
|
||||
use html_writer;
|
||||
use moodle_url;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Activity Module admin settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class activity_management_table extends plugin_management_table {
|
||||
|
||||
public function setup() {
|
||||
$this->set_attribute('id', 'modules');
|
||||
$this->set_attribute('class', 'admintable generaltable');
|
||||
parent::setup();
|
||||
}
|
||||
|
||||
protected function get_table_id(): string {
|
||||
return 'module-administration-table';
|
||||
}
|
||||
|
||||
protected function get_plugintype(): string {
|
||||
return 'mod';
|
||||
}
|
||||
|
||||
public function guess_base_url(): void {
|
||||
$this->define_baseurl(
|
||||
new moodle_url('/admin/modules.php')
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_action_url(array $params = []): moodle_url {
|
||||
return new moodle_url('/admin/modules.php', $params);
|
||||
}
|
||||
|
||||
protected function get_column_list(): array {
|
||||
$columns = parent::get_column_list();
|
||||
return array_merge(
|
||||
array_slice($columns, 0, 1, true),
|
||||
['activities' => get_string('activities')],
|
||||
array_slice($columns, 1, null, true),
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_name(stdClass $row): string {
|
||||
global $OUTPUT;
|
||||
|
||||
$status = $row->plugininfo->get_status();
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
return html_writer::span(
|
||||
get_string('pluginmissingfromdisk', 'core', $row->plugininfo),
|
||||
'notifyproblem'
|
||||
);
|
||||
}
|
||||
|
||||
return html_writer::span(
|
||||
html_writer::img(
|
||||
$OUTPUT->image_url('monologo', $row->plugininfo->name),
|
||||
'',
|
||||
[
|
||||
'class' => 'icon',
|
||||
],
|
||||
) . get_string('modulename', $row->plugininfo->name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the number of activities present, with a link to courses containing activity if relevant.
|
||||
*
|
||||
* @param mixed $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_activities(stdClass $row): string {
|
||||
global $DB, $OUTPUT;
|
||||
try {
|
||||
$count = $DB->count_records_select($row->plugininfo->name, "course <> 0");
|
||||
} catch (dml_exception $e) {
|
||||
$count = -1;
|
||||
}
|
||||
|
||||
if ($count > 0) {
|
||||
return $OUTPUT->action_link(
|
||||
new moodle_url('/course/search.php', [
|
||||
'modulelist' => $row->plugininfo->name,
|
||||
]),
|
||||
$count,
|
||||
null,
|
||||
['title' => get_string('showmodulecourse')]
|
||||
);
|
||||
} else if ($count < 0) {
|
||||
return get_string('error');
|
||||
} else {
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use html_writer;
|
||||
use moodle_url;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Tiny admin settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class block_management_table extends \core_admin\table\plugin_management_table {
|
||||
|
||||
/** @var plugininfo[] A list of blocks which cannot be deleted */
|
||||
protected array $undeletableblocktypes;
|
||||
|
||||
/** @var stdClass[] A list of basic block data */
|
||||
protected array $blockdata;
|
||||
|
||||
/** @var array<string,int> A list of course counts */
|
||||
protected array $courseblocks;
|
||||
|
||||
public function __construct() {
|
||||
global $DB;
|
||||
parent::__construct();
|
||||
$this->undeletableblocktypes = \block_manager::get_undeletable_block_types();
|
||||
|
||||
$sql = 'SELECT b.name,
|
||||
b.id,
|
||||
COUNT(DISTINCT binst.id) as totalcount
|
||||
FROM {block} b
|
||||
LEFT JOIN {block_instances} binst ON binst.blockname = b.name
|
||||
GROUP BY b.id,
|
||||
b.name
|
||||
ORDER BY b.name ASC';
|
||||
$this->blockdata = $DB->get_records_sql($sql);
|
||||
|
||||
$sql = "SELECT blockname
|
||||
FROM {block_instances}
|
||||
WHERE pagetypepattern = 'course-view-*'
|
||||
GROUP BY blockname";
|
||||
$this->courseblocks = $DB->get_records_sql($sql);
|
||||
}
|
||||
|
||||
protected function get_plugintype(): string {
|
||||
return 'block';
|
||||
}
|
||||
|
||||
public function guess_base_url(): void {
|
||||
$this->define_baseurl(
|
||||
new moodle_url('/admin/blocks.php')
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_action_url(array $params = []): moodle_url {
|
||||
return new moodle_url('/admin/blocks.php', $params);
|
||||
}
|
||||
|
||||
|
||||
protected function get_table_js_module(): string {
|
||||
return 'core_admin/block_management_table';
|
||||
}
|
||||
|
||||
protected function get_column_list(): array {
|
||||
$columns = parent::get_column_list();
|
||||
return array_merge(
|
||||
array_slice($columns, 0, 1, true),
|
||||
['instances' => get_string('blockinstances', 'admin')],
|
||||
array_slice($columns, 1, 2, true),
|
||||
['protect' => get_string('blockprotect', 'admin')],
|
||||
array_slice($columns, 3, null, true),
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_columns_with_help(): array {
|
||||
return [
|
||||
'protect' => new \help_icon('blockprotect', 'admin'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the instances column
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_instances(stdClass $row): string {
|
||||
$blockdata = $this->blockdata[$row->plugininfo->name];
|
||||
if (array_key_exists($blockdata->name, $this->courseblocks)) {
|
||||
return html_writer::link(
|
||||
new moodle_url('/course/search.php', [
|
||||
'blocklist' => $blockdata->id,
|
||||
]),
|
||||
$blockdata->totalcount,
|
||||
);
|
||||
}
|
||||
|
||||
return $blockdata->totalcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the protect column.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_protect(stdClass $row): string {
|
||||
global $OUTPUT;
|
||||
|
||||
$params = [
|
||||
'sesskey' => sesskey(),
|
||||
];
|
||||
|
||||
$protected = in_array($row->plugininfo->name, $this->undeletableblocktypes);
|
||||
|
||||
$pluginname = $row->plugininfo->displayname;
|
||||
if ($protected) {
|
||||
$params['unprotect'] = $row->plugininfo->name;
|
||||
$icon = $OUTPUT->pix_icon('t/unlock', get_string('blockunprotectblock', 'admin', $pluginname));
|
||||
} else {
|
||||
$params['protect'] = $row->plugininfo->name;
|
||||
$icon = $OUTPUT->pix_icon('t/lock', get_string('blockprotectblock', 'admin', $pluginname));
|
||||
}
|
||||
|
||||
return html_writer::link(
|
||||
$this->get_action_url($params),
|
||||
$icon,
|
||||
[
|
||||
'data-action' => 'toggleprotectstate',
|
||||
'data-plugin' => $row->plugin,
|
||||
'data-target-state' => $protected ? 0 : 1,
|
||||
],
|
||||
);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Tiny admin settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class editor_management_table extends \core_admin\table\plugin_management_table {
|
||||
protected function get_plugintype(): string {
|
||||
return 'editor';
|
||||
}
|
||||
|
||||
public function guess_base_url(): void {
|
||||
$this->define_baseurl(
|
||||
new moodle_url('/admin/settings.php', ['section' => 'manageeditors'])
|
||||
);
|
||||
}
|
||||
|
||||
protected function get_action_url(array $params = []): moodle_url {
|
||||
return new moodle_url('/admin/editors.php', $params);
|
||||
}
|
||||
|
||||
protected function order_plugins(array $plugins): array {
|
||||
global $CFG;
|
||||
|
||||
// The Editor list is stored in an ordered string.
|
||||
$activeeditors = explode(',', $CFG->texteditors);
|
||||
|
||||
$sortedplugins = [];
|
||||
foreach ($activeeditors as $editor) {
|
||||
if (isset($plugins[$editor])) {
|
||||
$sortedplugins[$editor] = $plugins[$editor];
|
||||
unset($plugins[$editor]);
|
||||
}
|
||||
}
|
||||
|
||||
$otherplugins = parent::order_plugins($plugins);
|
||||
return array_merge(
|
||||
$sortedplugins,
|
||||
$otherplugins
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use core_plugin_manager;
|
||||
use flexible_table;
|
||||
use html_writer;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once("{$CFG->libdir}/tablelib.php");
|
||||
|
||||
/**
|
||||
* Plugin Management table.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class hook_list_table extends flexible_table {
|
||||
|
||||
/** @var \core\plugininfo\base[] The plugin list */
|
||||
protected array $plugins = [];
|
||||
|
||||
/** @var int The number of enabled plugins of this type */
|
||||
protected int $enabledplugincount = 0;
|
||||
|
||||
/** @var core_plugin_manager */
|
||||
protected core_plugin_manager $pluginmanager;
|
||||
|
||||
/** @var string The plugininfo class for this plugintype */
|
||||
protected string $plugininfoclass;
|
||||
|
||||
/** @var stdClass[] The list of emitted hooks with metadata */
|
||||
protected array $emitters;
|
||||
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
|
||||
$this->define_baseurl('/admin/hooks.php');
|
||||
parent::__construct('core_admin-hook_list_table');
|
||||
|
||||
// Add emitted hooks.
|
||||
$this->emitters = \core\hook\manager::discover_known_hooks();
|
||||
|
||||
$this->setup_column_configuration();
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the column configuration for this table.
|
||||
*/
|
||||
protected function setup_column_configuration(): void {
|
||||
$columnlist = [
|
||||
'details' => get_string('hookname', 'core_admin'),
|
||||
'callbacks' => get_string('hookcallbacks', 'core_admin'),
|
||||
'deprecates' => get_string('hookdeprecates', 'core_admin'),
|
||||
];
|
||||
$this->define_columns(array_keys($columnlist));
|
||||
$this->define_headers(array_values($columnlist));
|
||||
|
||||
$columnswithhelp = [
|
||||
'callbacks' => new \help_icon('hookcallbacks', 'admin'),
|
||||
];
|
||||
$columnhelp = array_map(function (string $column) use ($columnswithhelp): ?\renderable {
|
||||
if (array_key_exists($column, $columnswithhelp)) {
|
||||
return $columnswithhelp[$column];
|
||||
}
|
||||
|
||||
return null;
|
||||
}, array_keys($columnlist));
|
||||
$this->define_help_for_headers($columnhelp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the table.
|
||||
*/
|
||||
public function out(): void {
|
||||
// All hook consumers referenced from the db/hooks.php files.
|
||||
$hookmanager = \core\di::get(\core\hook\manager::class);
|
||||
$allhooks = (array)$hookmanager->get_all_callbacks();
|
||||
|
||||
// Add any unused hooks.
|
||||
foreach (array_keys($this->emitters) as $classname) {
|
||||
if (isset($allhooks[$classname])) {
|
||||
continue;
|
||||
}
|
||||
$allhooks[$classname] = [];
|
||||
}
|
||||
|
||||
// Order rows by hook name, putting core first.
|
||||
\core_collator::ksort($allhooks);
|
||||
$corehooks = [];
|
||||
foreach ($allhooks as $classname => $consumers) {
|
||||
if (str_starts_with($classname, 'core\\')) {
|
||||
$corehooks[$classname] = $consumers;
|
||||
unset($allhooks[$classname]);
|
||||
}
|
||||
}
|
||||
$allhooks = array_merge($corehooks, $allhooks);
|
||||
|
||||
foreach ($allhooks as $classname => $consumers) {
|
||||
$this->add_data_keyed(
|
||||
$this->format_row((object) [
|
||||
'classname' => $classname,
|
||||
'callbacks' => $consumers,
|
||||
]),
|
||||
$this->get_row_class($classname),
|
||||
);
|
||||
}
|
||||
|
||||
$this->finish_output(false);
|
||||
}
|
||||
|
||||
protected function col_details(stdClass $row): string {
|
||||
return $row->classname .
|
||||
$this->get_description($row) .
|
||||
html_writer::div($this->get_tags_for_row($row));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the name column content.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function get_description(stdClass $row): string {
|
||||
if (!array_key_exists($row->classname, $this->emitters)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return html_writer::tag(
|
||||
'small',
|
||||
clean_text(markdown_to_html($this->emitters[$row->classname]['description']), FORMAT_HTML),
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_deprecates(stdClass $row): string {
|
||||
if (!class_exists($row->classname)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$deprecates = \core\hook\manager::get_replaced_callbacks($row->classname);
|
||||
if (count($deprecates) === 0) {
|
||||
return '';
|
||||
}
|
||||
$content = html_writer::start_tag('ul');
|
||||
|
||||
foreach ($deprecates as $deprecatedmethod) {
|
||||
$content .= html_writer::tag('li', $deprecatedmethod);
|
||||
}
|
||||
$content .= html_writer::end_tag('ul');
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function col_callbacks(stdClass $row): string {
|
||||
global $CFG;
|
||||
|
||||
$hookclass = $row->classname;
|
||||
$cbinfo = [];
|
||||
foreach ($row->callbacks as $definition) {
|
||||
$iscallable = is_callable($definition['callback'], false, $callbackname);
|
||||
$isoverridden = isset($CFG->hooks_callback_overrides[$hookclass][$definition['callback']]);
|
||||
$info = "{$callbackname} ({$definition['priority']})";
|
||||
if (!$iscallable) {
|
||||
$info .= ' ';
|
||||
$info .= $this->get_tag(
|
||||
get_string('error'),
|
||||
'danger',
|
||||
get_string('hookcallbacknotcallable', 'core_admin', $callbackname),
|
||||
);
|
||||
}
|
||||
if ($isoverridden) {
|
||||
// The lang string meaning should be close enough here.
|
||||
$info .= $this->get_tag(
|
||||
get_string('hookconfigoverride', 'core_admin'),
|
||||
'warning',
|
||||
get_string('hookconfigoverride_help', 'core_admin'),
|
||||
);
|
||||
}
|
||||
|
||||
$cbinfo[] = $info;
|
||||
}
|
||||
|
||||
if ($cbinfo) {
|
||||
$output = html_writer::start_tag('ol');
|
||||
foreach ($cbinfo as $callback) {
|
||||
$class = '';
|
||||
if ($definition['disabled']) {
|
||||
$class = 'dimmed_text';
|
||||
}
|
||||
$output .= html_writer::tag('li', $callback, ['class' => $class]);
|
||||
}
|
||||
$output .= html_writer::end_tag('ol');
|
||||
return $output;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML to display the badge with tooltip.
|
||||
*
|
||||
* @param string $tag The main text to display
|
||||
* @param null|string $type The pill type
|
||||
* @param null|string $tooltip The content of the tooltip
|
||||
* @return string
|
||||
*/
|
||||
protected function get_tag(
|
||||
string $tag,
|
||||
?string $type = null,
|
||||
?string $tooltip = null,
|
||||
): string {
|
||||
$attributes = [];
|
||||
|
||||
if ($type === null) {
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
if ($tooltip) {
|
||||
$attributes['data-toggle'] = 'tooltip';
|
||||
$attributes['title'] = $tooltip;
|
||||
}
|
||||
return html_writer::span($tag, "badge badge-{$type}", $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code to display a set of tags for this table row.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function get_tags_for_row(stdClass $row): string {
|
||||
if (!array_key_exists($row->classname, $this->emitters)) {
|
||||
// This hook has been defined in the db/hooks.php file
|
||||
// but does not refer to a hook in this version of Moodle.
|
||||
return $this->get_tag(
|
||||
get_string('hookunknown', 'core_admin'),
|
||||
'warning',
|
||||
get_string('hookunknown_desc', 'core_admin'),
|
||||
);
|
||||
}
|
||||
|
||||
if (!class_exists($row->classname)) {
|
||||
// This hook has been defined in a hook discovery agent, but the class it refers to could not be found.
|
||||
return $this->get_tag(
|
||||
get_string('hookclassmissing', 'core_admin'),
|
||||
'warning',
|
||||
get_string('hookclassmissing_desc', 'core_admin'),
|
||||
);
|
||||
}
|
||||
|
||||
$tags = $this->emitters[$row->classname]['tags'] ?? [];
|
||||
$taglist = array_map(function($tag): string {
|
||||
if (is_array($tag)) {
|
||||
return $this->get_tag(...$tag);
|
||||
}
|
||||
return $this->get_tag($tag, 'badge bg-info text-white');
|
||||
}, $tags);
|
||||
|
||||
return implode("\n", $taglist);
|
||||
}
|
||||
|
||||
protected function get_row_class(string $classname): string {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use moodle_url;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Media plugin admin settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class media_management_table extends \core_admin\table\plugin_management_table {
|
||||
/** @var array The list of used extensions */
|
||||
protected array $usedextensions = [];
|
||||
|
||||
protected function get_plugintype(): string {
|
||||
return 'media';
|
||||
}
|
||||
|
||||
protected function get_action_url(array $params = []): moodle_url {
|
||||
return new moodle_url('/admin/media.php', $params);
|
||||
}
|
||||
|
||||
protected function get_column_list(): array {
|
||||
$columns = parent::get_column_list();
|
||||
return array_merge(
|
||||
array_slice($columns, 0, 1, true),
|
||||
['supports' => get_string('supports', 'core_media')],
|
||||
array_slice($columns, 1, null, true),
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_name(stdClass $row): string {
|
||||
global $OUTPUT, $PAGE;
|
||||
|
||||
$name = $row->plugininfo->name;
|
||||
if ($PAGE->theme->resolve_image_location('icon', 'media_' . $name, false)) {
|
||||
$icon = $OUTPUT->pix_icon('icon', '', "media_{$name}", ['class' => 'icon pluginicon']);
|
||||
} else {
|
||||
$icon = $OUTPUT->pix_icon('spacer', '', 'moodle', ['class' => 'icon pluginicon noicon']);
|
||||
}
|
||||
|
||||
$help = '';
|
||||
if (get_string_manager()->string_exists('pluginname_help', 'media_' . $name)) {
|
||||
$help = ' ' . $OUTPUT->help_icon('pluginname', 'media_' . $name);
|
||||
}
|
||||
|
||||
return $icon . $row->plugininfo->displayname . $help;
|
||||
}
|
||||
|
||||
protected function col_supports(stdClass $row): string {
|
||||
return $row->plugininfo->supports($this->usedextensions);
|
||||
}
|
||||
}
|
||||
@@ -1,503 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use context_system;
|
||||
use core_plugin_manager;
|
||||
use core_table\dynamic as dynamic_table;
|
||||
use flexible_table;
|
||||
use html_writer;
|
||||
use moodle_url;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once("{$CFG->libdir}/tablelib.php");
|
||||
|
||||
/**
|
||||
* Plugin Management table.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
abstract class plugin_management_table extends flexible_table implements dynamic_table {
|
||||
|
||||
/** @var \core\plugininfo\base[] The plugin list */
|
||||
protected array $plugins = [];
|
||||
|
||||
/** @var int The number of enabled plugins of this type */
|
||||
protected int $enabledplugincount = 0;
|
||||
|
||||
/** @var core_plugin_manager */
|
||||
protected core_plugin_manager $pluginmanager;
|
||||
|
||||
/** @var string The plugininfo class for this plugintype */
|
||||
protected string $plugininfoclass;
|
||||
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
|
||||
parent::__construct($this->get_table_id());
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
// Fetch the plugininfo class.
|
||||
$this->pluginmanager = core_plugin_manager::instance();
|
||||
$this->plugininfoclass = $this->pluginmanager::resolve_plugininfo_class($this->get_plugintype());
|
||||
|
||||
$this->guess_base_url();
|
||||
|
||||
$this->plugins = $this->get_sorted_plugins();
|
||||
$this->enabledplugincount = count(array_filter($this->plugins, function ($plugin) {
|
||||
return $plugin->is_enabled();
|
||||
}));
|
||||
|
||||
$this->setup_column_configuration();
|
||||
$this->set_filterset(new plugin_management_table_filterset());
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of sorted plugins.
|
||||
*
|
||||
* @return \core\plugininfo\base[]
|
||||
*/
|
||||
protected function get_sorted_plugins(): array {
|
||||
if ($this->plugininfoclass::plugintype_supports_ordering()) {
|
||||
return $this->plugininfoclass::get_sorted_plugins();
|
||||
} else {
|
||||
$plugins = $this->pluginmanager->get_plugins_of_type($this->get_plugintype());
|
||||
return self::sort_plugins($plugins);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the plugins list.
|
||||
*
|
||||
* Note: This only applies to plugins which do not support ordering.
|
||||
*
|
||||
* @param \core\plugininfo\base[] $plugins
|
||||
* @return \core\plugininfo\base[]
|
||||
*/
|
||||
protected function sort_plugins(array $plugins): array {
|
||||
// The asort functions work by reference.
|
||||
\core_collator::asort_objects_by_property($plugins, 'displayname');
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the column configuration for this table.
|
||||
*/
|
||||
protected function setup_column_configuration(): void {
|
||||
$columnlist = $this->get_column_list();
|
||||
$this->define_columns(array_keys($columnlist));
|
||||
$this->define_headers(array_values($columnlist));
|
||||
|
||||
$columnswithhelp = $this->get_columns_with_help();
|
||||
$columnhelp = array_map(function (string $column) use ($columnswithhelp): ?\renderable {
|
||||
if (array_key_exists($column, $columnswithhelp)) {
|
||||
return $columnswithhelp[$column];
|
||||
}
|
||||
|
||||
return null;
|
||||
}, array_keys($columnlist));
|
||||
$this->define_help_for_headers($columnhelp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the standard order of the plugins.
|
||||
*
|
||||
* @param array $plugins
|
||||
* @return array
|
||||
*/
|
||||
protected function order_plugins(array $plugins): array {
|
||||
uasort($plugins, function ($a, $b) {
|
||||
if ($a->is_enabled() && !$b->is_enabled()) {
|
||||
return -1;
|
||||
} else if (!$a->is_enabled() && $b->is_enabled()) {
|
||||
return 1;
|
||||
}
|
||||
return strnatcasecmp($a->name, $b->name);
|
||||
});
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugintype for this table.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_plugintype(): string;
|
||||
|
||||
/**
|
||||
* Get the action URL for this table.
|
||||
*
|
||||
* The action URL is used to perform all actions when JS is not available.
|
||||
*
|
||||
* @param array $params
|
||||
* @return moodle_url
|
||||
*/
|
||||
abstract protected function get_action_url(array $params = []): moodle_url;
|
||||
|
||||
/**
|
||||
* Provide a default implementation for guessing the base URL from the action URL.
|
||||
*/
|
||||
public function guess_base_url(): void {
|
||||
$this->define_baseurl($this->get_action_url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the web service method used to toggle state.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function get_toggle_service(): ?string {
|
||||
return 'core_admin_set_plugin_state';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the web service method used to order plugins.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function get_sortorder_service(): ?string {
|
||||
return 'core_admin_set_plugin_order';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the table.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_id(): string {
|
||||
return 'plugin_management_table-' . $this->get_plugintype();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of the column titles
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_column_list(): array {
|
||||
$columns = [
|
||||
'name' => get_string('name', 'core'),
|
||||
'version' => get_string('version', 'core'),
|
||||
];
|
||||
|
||||
if ($this->supports_disabling()) {
|
||||
$columns['enabled'] = get_string('pluginenabled', 'core_plugin');
|
||||
}
|
||||
|
||||
if ($this->supports_ordering()) {
|
||||
$columns['order'] = get_string('order', 'core');
|
||||
}
|
||||
|
||||
$columns['settings'] = get_string('settings', 'core');
|
||||
$columns['uninstall'] = get_string('uninstallplugin', 'core_admin');
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
protected function get_columns_with_help(): array {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context for this table.
|
||||
*
|
||||
* @return context_system
|
||||
*/
|
||||
public function get_context(): context_system {
|
||||
return context_system::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table content.
|
||||
*/
|
||||
public function get_content(): string {
|
||||
ob_start();
|
||||
$this->out();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the table.
|
||||
*/
|
||||
public function out(): void {
|
||||
$plugintype = $this->get_plugintype();
|
||||
foreach ($this->plugins as $plugininfo) {
|
||||
$plugin = "{$plugintype}_{$plugininfo->name}";
|
||||
$rowdata = (object) [
|
||||
'plugin' => $plugin,
|
||||
'plugininfo' => $plugininfo,
|
||||
'name' => $plugininfo->displayname,
|
||||
'version' => $plugininfo->versiondb,
|
||||
];
|
||||
$this->add_data_keyed(
|
||||
$this->format_row($rowdata),
|
||||
$this->get_row_class($rowdata)
|
||||
);
|
||||
}
|
||||
|
||||
$this->finish_output(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This table is not downloadable.
|
||||
* @param bool $downloadable
|
||||
* @return bool
|
||||
*/
|
||||
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
public function is_downloadable($downloadable = null): bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the name column content.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_name(stdClass $row): string {
|
||||
$status = $row->plugininfo->get_status();
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
return html_writer::span(
|
||||
get_string('pluginmissingfromdisk', 'core', $row->plugininfo),
|
||||
'notifyproblem'
|
||||
);
|
||||
}
|
||||
|
||||
if ($row->plugininfo->is_installed_and_upgraded()) {
|
||||
return $row->plugininfo->displayname;
|
||||
}
|
||||
|
||||
return html_writer::span(
|
||||
$row->plugininfo->displayname,
|
||||
'notifyproblem'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the enable/disable column content.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_enabled(stdClass $row): string {
|
||||
global $OUTPUT;
|
||||
|
||||
$enabled = $row->plugininfo->is_enabled();
|
||||
$params = [
|
||||
'sesskey' => sesskey(),
|
||||
'plugin' => $row->plugininfo->name,
|
||||
'action' => $enabled ? 'disable' : 'enable',
|
||||
];
|
||||
|
||||
if ($enabled) {
|
||||
$icon = $OUTPUT->pix_icon('t/hide', get_string('disableplugin', 'core_admin', $row->plugininfo->displayname));
|
||||
} else {
|
||||
$icon = $OUTPUT->pix_icon('t/show', get_string('enableplugin', 'core_admin', $row->plugininfo->displayname));
|
||||
}
|
||||
|
||||
return html_writer::link(
|
||||
$this->get_action_url($params),
|
||||
$icon,
|
||||
[
|
||||
'data-toggle-method' => $this->get_toggle_service(),
|
||||
'data-action' => 'togglestate',
|
||||
'data-plugin' => $row->plugin,
|
||||
'data-state' => $enabled ? 1 : 0,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
protected function col_order(stdClass $row): string {
|
||||
global $OUTPUT;
|
||||
|
||||
if (!$this->supports_ordering()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$row->plugininfo->is_enabled()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($this->enabledplugincount <= 1) {
|
||||
// There is only one row.
|
||||
return '';
|
||||
}
|
||||
|
||||
$hasup = true;
|
||||
$hasdown = true;
|
||||
|
||||
if (empty($this->currentrow)) {
|
||||
// This is the top row.
|
||||
$hasup = false;
|
||||
}
|
||||
|
||||
if ($this->currentrow === ($this->enabledplugincount - 1)) {
|
||||
// This is the last row.
|
||||
$hasdown = false;
|
||||
}
|
||||
|
||||
if ($this->supports_ordering()) {
|
||||
$dataattributes = [
|
||||
'data-method' => $this->get_sortorder_service(),
|
||||
'data-action' => 'move',
|
||||
'data-plugin' => $row->plugin,
|
||||
];
|
||||
} else {
|
||||
$dataattributes = [];
|
||||
}
|
||||
|
||||
if ($hasup) {
|
||||
$upicon = html_writer::link(
|
||||
$this->get_action_url([
|
||||
'sesskey' => sesskey(),
|
||||
'action' => 'up',
|
||||
'plugin' => $row->plugininfo->name,
|
||||
]),
|
||||
$OUTPUT->pix_icon('t/up', get_string('moveup')),
|
||||
array_merge($dataattributes, ['data-direction' => 'up']),
|
||||
);
|
||||
} else {
|
||||
$upicon = $OUTPUT->spacer();
|
||||
}
|
||||
|
||||
if ($hasdown) {
|
||||
$downicon = html_writer::link(
|
||||
$this->get_action_url([
|
||||
'sesskey' => sesskey(),
|
||||
'action' => 'down',
|
||||
'plugin' => $row->plugininfo->name,
|
||||
]),
|
||||
$OUTPUT->pix_icon('t/down', get_string('movedown')),
|
||||
array_merge($dataattributes, ['data-direction' => 'down']),
|
||||
);
|
||||
} else {
|
||||
$downicon = $OUTPUT->spacer();
|
||||
}
|
||||
|
||||
// For now just add the up/down icons.
|
||||
return html_writer::span($upicon . $downicon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the settings column content.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_settings(stdClass $row): string {
|
||||
if ($settingsurl = $row->plugininfo->get_settings_url()) {
|
||||
return html_writer::link($settingsurl, get_string('settings'));
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the Uninstall column content.
|
||||
*
|
||||
* @param stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
protected function col_uninstall(stdClass $row): string {
|
||||
$status = $row->plugininfo->get_status();
|
||||
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
|
||||
return get_string('status_new', 'core_plugin');
|
||||
}
|
||||
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$uninstall = get_string('status_missing', 'core_plugin') . '<br/>';
|
||||
} else {
|
||||
$uninstall = '';
|
||||
}
|
||||
|
||||
if ($uninstallurl = $this->pluginmanager->get_uninstall_url($row->plugin)) {
|
||||
$uninstall .= html_writer::link($uninstallurl, get_string('uninstallplugin', 'core_admin'));
|
||||
}
|
||||
|
||||
return $uninstall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JS module used to manage this table.
|
||||
*
|
||||
* This should be a class which extends 'core_admin/plugin_management_table'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_js_module(): string {
|
||||
return 'core_admin/plugin_management_table';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add JS specific to this implementation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_dynamic_table_html_end(): string {
|
||||
global $PAGE;
|
||||
|
||||
$PAGE->requires->js_call_amd($this->get_table_js_module(), 'init');
|
||||
return parent::get_dynamic_table_html_end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any class to add to the row.
|
||||
*
|
||||
* @param mixed $row
|
||||
* @return string
|
||||
*/
|
||||
protected function get_row_class($row): string {
|
||||
$plugininfo = $row->plugininfo;
|
||||
if ($plugininfo->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$plugininfo->is_enabled()) {
|
||||
return 'dimmed_text';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function get_filterset_class(): string {
|
||||
return self::class . '_filterset';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this plugin type supports the disabling of plugins.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function supports_disabling(): bool {
|
||||
return $this->plugininfoclass::plugintype_supports_disabling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this table should show ordering fields.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function supports_ordering(): bool {
|
||||
return $this->plugininfoclass::plugintype_supports_ordering();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
/**
|
||||
* This file contains the dynamic interface.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class plugin_management_table_filterset extends \core_table\local\filter\filterset {
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?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 core_admin\table;
|
||||
|
||||
use moodle_url;
|
||||
|
||||
/**
|
||||
* Admin tool settings.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_plugin_management_table extends \core_admin\table\plugin_management_table {
|
||||
protected function get_plugintype(): string {
|
||||
return 'tool';
|
||||
}
|
||||
|
||||
protected function get_column_list(): array {
|
||||
$columns = parent::get_column_list();
|
||||
|
||||
unset($columns['settings']);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
protected function get_action_url(array $params = []): moodle_url {
|
||||
return new moodle_url('/admin/settings.php', array_merge(['section' => 'toolsmanagement'], $params));
|
||||
}
|
||||
}
|
||||
+29
-72
@@ -27,28 +27,23 @@ define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once("{$CFG->libdir}/clilib.php");
|
||||
require_once("{$CFG->libdir}/cronlib.php");
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
[
|
||||
'execute' => false,
|
||||
'help' => false,
|
||||
'keep-alive' => 0,
|
||||
'showsql' => false,
|
||||
'showdebugging' => false,
|
||||
'execute' => false,
|
||||
'keep-alive' => 0,
|
||||
'ignorelimits' => false,
|
||||
'force' => false,
|
||||
'id' => null,
|
||||
'classname' => null,
|
||||
'taskslimit' => null,
|
||||
'failed' => false,
|
||||
], [
|
||||
'h' => 'help',
|
||||
'e' => 'execute',
|
||||
'k' => 'keep-alive',
|
||||
'i' => 'ignorelimits',
|
||||
'f' => 'force',
|
||||
'c' => 'classname',
|
||||
'l' => 'taskslimit',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -57,7 +52,8 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
$help = <<<EOT
|
||||
if ($options['help'] or empty($options['execute'])) {
|
||||
$help = <<<EOT
|
||||
Ad hoc cron tasks.
|
||||
|
||||
Options:
|
||||
@@ -68,32 +64,22 @@ Options:
|
||||
-k, --keep-alive=N Keep this script alive for N seconds and poll for new adhoc tasks
|
||||
-i --ignorelimits Ignore task_adhoc_concurrency_limit and task_adhoc_max_runtime limits
|
||||
-f, --force Run even if cron is disabled
|
||||
--id Run (failed) task with id
|
||||
-c, --classname Run tasks with a certain classname (FQN)
|
||||
-l, --taskslimit=N Run at most N tasks
|
||||
--failed Run only tasks that failed, ie those with a fail delay
|
||||
|
||||
Run all queued tasks:
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --execute
|
||||
|
||||
Run all queued tasks of specific class:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --classname=\\\\core_course\\\\task\\\\course_delete_modules
|
||||
|
||||
Double backslash for the shell escape reasons.
|
||||
Run a specific task:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --id=123456
|
||||
|
||||
Run a specific task with debugging:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --id=123456 --showsql --showdebugging
|
||||
|
||||
To profile a long running task:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --taskslimit=1 --classname='\\some\\class\\name' --ignorelimits
|
||||
|
||||
EOT;
|
||||
|
||||
if ($options['help']) {
|
||||
echo $help;
|
||||
exit(0);
|
||||
die;
|
||||
}
|
||||
|
||||
if ($options['showdebugging']) {
|
||||
set_debugging(DEBUG_DEVELOPER, true);
|
||||
}
|
||||
|
||||
if ($options['showsql']) {
|
||||
$DB->set_debug(true);
|
||||
}
|
||||
|
||||
if (CLI_MAINTENANCE) {
|
||||
@@ -106,18 +92,17 @@ if (moodle_needs_upgrading()) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (empty($options['execute'])) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
mtrace('Cron is disabled. Use --force to override.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Common debugging options.
|
||||
if ($options['showdebugging']) {
|
||||
set_debugging(DEBUG_DEVELOPER, true);
|
||||
}
|
||||
|
||||
if ($options['showsql']) {
|
||||
$DB->set_debug(true);
|
||||
if (empty($options['keep-alive'])) {
|
||||
$options['keep-alive'] = 0;
|
||||
}
|
||||
|
||||
if (!empty($CFG->showcronsql)) {
|
||||
@@ -127,48 +112,20 @@ if (!empty($CFG->showcrondebugging)) {
|
||||
set_debugging(DEBUG_DEVELOPER, true);
|
||||
}
|
||||
|
||||
// Process params.
|
||||
$checklimits = empty($options['ignorelimits']);
|
||||
|
||||
core_php_time_limit::raise();
|
||||
|
||||
// Increase memory limit.
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
||||
// Emulate normal session - we use admin account by default.
|
||||
\core\cron::setup_user();
|
||||
cron_setup_user();
|
||||
|
||||
$humantimenow = date('r', time());
|
||||
$keepalive = (int)$options['keep-alive'];
|
||||
|
||||
\core\local\cli\shutdown::script_supports_graceful_exit();
|
||||
$humantimenow = date('r', time());
|
||||
|
||||
mtrace("Server Time: {$humantimenow}\n");
|
||||
|
||||
$classname = $options['classname'];
|
||||
|
||||
// Run a single adhoc task only, if requested.
|
||||
if (!empty($options['id'])) {
|
||||
$taskid = (int) $options['id'];
|
||||
\core\cron::run_adhoc_task($taskid);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Run all failed tasks.
|
||||
if (!empty($options['failed'])) {
|
||||
\core\cron::run_failed_adhoc_tasks($classname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Examine params and determine if we should run.
|
||||
$execute = (bool) $options['execute'];
|
||||
$keepalive = empty($options['keep-alive']) ? 0 : (int) $options['keep-alive'];
|
||||
$taskslimit = empty($options['taskslimit']) ? null : (int) $options['taskslimit'];
|
||||
$checklimits = empty($options['ignorelimits']);
|
||||
|
||||
if ($classname || $keepalive || $taskslimit) {
|
||||
$execute = true;
|
||||
}
|
||||
|
||||
// Output the help text if no criteria for running the adhoc tasks are given.
|
||||
if (!$execute) {
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
\core\cron::run_adhoc_tasks(time(), $keepalive, $checklimits, null, $taskslimit, $classname);
|
||||
cron_run_adhoc_tasks(time(), $keepalive, $checklimits);
|
||||
|
||||
@@ -30,6 +30,7 @@ define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php'); // cli only functions
|
||||
require_once($CFG->libdir.'/cronlib.php');
|
||||
|
||||
// now get cli options
|
||||
list($options, $unrecognized) = cli_get_params(array('help'=>false),
|
||||
@@ -79,10 +80,10 @@ if (!empty($CFG->showcrondebugging)) {
|
||||
|
||||
$starttime = microtime();
|
||||
|
||||
// Emulate normal session.
|
||||
\core\cron::setup_user();
|
||||
/// emulate normal session
|
||||
cron_setup_user();
|
||||
|
||||
// Start output log.
|
||||
/// Start output log
|
||||
$timenow = time();
|
||||
|
||||
mtrace("Server Time: ".date('r',$timenow)."\n\n");
|
||||
@@ -95,4 +96,4 @@ backup_cron_automated_helper::run_automated_backup(backup_cron_automated_helper:
|
||||
mtrace("Automated cron backups completed correctly");
|
||||
|
||||
$difftime = microtime_diff($starttime, microtime());
|
||||
mtrace("Execution took ".$difftime." seconds");
|
||||
mtrace("Execution took ".$difftime." seconds");
|
||||
+7
-23
@@ -33,7 +33,6 @@ require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
list($options, $unrecognized) = cli_get_params(array(
|
||||
'courseid' => false,
|
||||
'courseshortname' => '',
|
||||
'cmid' => false,
|
||||
'destination' => '',
|
||||
'help' => false,
|
||||
), array('h' => 'help'));
|
||||
@@ -43,14 +42,13 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] || !($options['courseid'] || $options['courseshortname'] || $options['cmid'])) {
|
||||
if ($options['help'] || !($options['courseid'] || $options['courseshortname'])) {
|
||||
$help = <<<EOL
|
||||
Perform backup of the given course or course module.
|
||||
Perform backup of the given course.
|
||||
|
||||
Options:
|
||||
--courseid=INTEGER Course ID for backup.
|
||||
--courseshortname=STRING Course shortname for backup. This option is ignored if courseid is set.
|
||||
--cmid=INTEGER Course module ID for backup. This option is ignored if courseid or courseshortname is set.
|
||||
--courseshortname=STRING Course shortname for backup.
|
||||
--destination=STRING Path where to store backup file. If not set the backup
|
||||
will be stored within the course backup file area.
|
||||
-h, --help Print out this help.
|
||||
@@ -78,26 +76,16 @@ if (!empty($dir)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the course or course module exists.
|
||||
// Check that the course exists.
|
||||
if ($options['courseid']) {
|
||||
$course = $DB->get_record('course', array('id' => $options['courseid']), '*', MUST_EXIST);
|
||||
} else if ($options['courseshortname']) {
|
||||
$course = $DB->get_record('course', array('shortname' => $options['courseshortname']), '*', MUST_EXIST);
|
||||
} else if ($options['cmid']) {
|
||||
$cm = $DB->get_record('course_modules', ['id' => $options['cmid']], '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
cli_heading('Performing backup...');
|
||||
if (!empty($course)) {
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
|
||||
} else if (!empty($cm)) {
|
||||
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
}
|
||||
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
|
||||
// Set the default filename.
|
||||
$format = $bc->get_format();
|
||||
$type = $bc->get_type();
|
||||
@@ -125,11 +113,7 @@ if (!empty($dir)) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($course)) {
|
||||
mtrace("Backup completed, the new file is listed in the backup area of the given course");
|
||||
} else {
|
||||
mtrace("Backup completed, the new file is listed in the backup area of the given module");
|
||||
}
|
||||
mtrace("Backup completed, the new file is listed in the backup area of the given course");
|
||||
}
|
||||
$bc->destroy();
|
||||
exit(0);
|
||||
+13
-21
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -29,11 +30,12 @@
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php'); // cli only functions
|
||||
require_once($CFG->libdir.'/cronlib.php');
|
||||
|
||||
// Now get cli option.
|
||||
[$options, $unrecognized] = cli_get_params(
|
||||
// now get cli options
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
[
|
||||
'help' => false,
|
||||
'stop' => false,
|
||||
@@ -42,9 +44,7 @@ require_once($CFG->libdir . '/clilib.php');
|
||||
'enable' => false,
|
||||
'disable' => false,
|
||||
'disable-wait' => false,
|
||||
'keep-alive' => null,
|
||||
],
|
||||
[
|
||||
], [
|
||||
'h' => 'help',
|
||||
's' => 'stop',
|
||||
'l' => 'list',
|
||||
@@ -52,7 +52,6 @@ require_once($CFG->libdir . '/clilib.php');
|
||||
'e' => 'enable',
|
||||
'd' => 'disable',
|
||||
'w' => 'disable-wait',
|
||||
'k' => 'keep-alive',
|
||||
]
|
||||
);
|
||||
|
||||
@@ -63,7 +62,7 @@ if ($unrecognized) {
|
||||
|
||||
if ($options['help']) {
|
||||
$help =
|
||||
"Execute periodic cron actions.
|
||||
"Execute periodic cron actions.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
@@ -73,9 +72,6 @@ Options:
|
||||
-e, --enable Enable cron
|
||||
-d, --disable Disable cron
|
||||
-w, --disable-wait=600 Disable cron and wait until all tasks finished or fail after N seconds (optional param)
|
||||
-k, --keep-alive=N Keep this script alive for N seconds and poll for new tasks
|
||||
The default value can be set by administrators in:
|
||||
Site administration > Server > Tasks > Task processing > Keep alive time
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/cron.php
|
||||
@@ -109,8 +105,7 @@ if ($options['list']) {
|
||||
$tasks = \core\task\manager::get_running_tasks();
|
||||
mtrace('The list of currently running tasks:');
|
||||
$format = "%7s %-12s %-9s %-20s %-52s\n";
|
||||
printf(
|
||||
$format,
|
||||
printf ($format,
|
||||
'PID',
|
||||
'HOST',
|
||||
'TYPE',
|
||||
@@ -118,8 +113,7 @@ if ($options['list']) {
|
||||
'CLASSNAME'
|
||||
);
|
||||
foreach ($tasks as $task) {
|
||||
printf(
|
||||
$format,
|
||||
printf ($format,
|
||||
$task->pid,
|
||||
substr($task->hostname, 0, 12),
|
||||
$task->type,
|
||||
@@ -143,7 +137,7 @@ if ($wait = $options['disable-wait']) {
|
||||
set_config('cron_enabled', 0);
|
||||
\core\task\manager::clear_static_caches();
|
||||
mtrace('Cron has been disabled for the site.');
|
||||
mtrace('Allocating ' . format_time($waitsec) . ' for the tasks to finish.');
|
||||
mtrace('Allocating '. format_time($waitsec) . ' for the tasks to finish.');
|
||||
|
||||
$lastcount = 0;
|
||||
while ($wait) {
|
||||
@@ -157,7 +151,7 @@ if ($wait = $options['disable-wait']) {
|
||||
|
||||
if (time() - $started >= $waitsec) {
|
||||
mtrace('');
|
||||
mtrace('Wait time (' . format_time($waitsec) . ') elapsed, but ' . count($tasks) . ' task(s) still running.');
|
||||
mtrace('Wait time ('. format_time($waitsec) . ') elapsed, but ' . count($tasks) . ' task(s) still running.');
|
||||
mtrace('Exiting with code 1.');
|
||||
exit(1);
|
||||
}
|
||||
@@ -181,6 +175,4 @@ if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
|
||||
\core\local\cli\shutdown::script_supports_graceful_exit();
|
||||
|
||||
|
||||
$keepalive = $options['keep-alive'];
|
||||
\core\cron::run_main_process($keepalive);
|
||||
cron_run();
|
||||
|
||||
@@ -28,6 +28,7 @@ define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require_once($CFG->libdir . '/cronlib.php');
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
[
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This script allows you to view and change the emailstop flag of any user.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage cli
|
||||
* @copyright 2023 Stephan Robotta (stephan.robotta@bfh.ch)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__.'/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php');
|
||||
|
||||
// Define the input options.
|
||||
$longparams = [
|
||||
'email' => '',
|
||||
'help' => false,
|
||||
'id' => '',
|
||||
'quiet' => false,
|
||||
'stop' => '',
|
||||
'username' => '',
|
||||
];
|
||||
|
||||
$shortparams = [
|
||||
'e' => 'email',
|
||||
'h' => 'help',
|
||||
'i' => 'id',
|
||||
'q' => 'quiet',
|
||||
's' => 'stop',
|
||||
'u' => 'username',
|
||||
];
|
||||
|
||||
// Define exit codes.
|
||||
$exitsuccess = 0;
|
||||
$exitunknownoption = 1;
|
||||
$exitmissinguserarg = 2;
|
||||
$exittoomanyuserarg = 3;
|
||||
$exitnosearchargs = 4;
|
||||
$exitnousersfound = 5;
|
||||
$exitinvalidstopflag = 6;
|
||||
$exiterrordb = 7;
|
||||
|
||||
// Now get cli options that are set by the caller.
|
||||
list($options, $unrecognized) = cli_get_params($longparams, $shortparams);
|
||||
|
||||
$verbose = empty($options['quiet']);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
if ($verbose) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized), $exitunknownoption);
|
||||
}
|
||||
exit($exitunknownoption);
|
||||
}
|
||||
|
||||
if ($options['help']) {
|
||||
$help =
|
||||
"Set/unset or show status of emailstop flag for a user, identified by username or email.
|
||||
|
||||
There are no security checks here because anybody who is able to
|
||||
execute this file may execute any PHP too.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
-e, --email=email Specify user by email, separate many users by comma
|
||||
-i, --id=id Specify user by id, separate many users by comma
|
||||
-q, --quiet No output to stdout
|
||||
-s, --stop=0|1|off|on Set new value for emailstop flag
|
||||
-u, --username=username Specify user by username, separate many users by comma
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/emailstop.php --email=student1@example.com --stop=1
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/emailstop.php --email=student1@example.com,student2@example.com
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/emailstop.php --u=student1,student2 -s=on
|
||||
";
|
||||
|
||||
echo $help;
|
||||
exit($exitsuccess);
|
||||
}
|
||||
|
||||
$cntempty = 0;
|
||||
$cntfilled = 0;
|
||||
$searchargs = [];
|
||||
|
||||
// Try to find out which option is used to fetch the users from. Also do sanitize etc.
|
||||
foreach (['email', 'username', 'id'] as $option) {
|
||||
if (empty($options[$option])) {
|
||||
$cntempty++;
|
||||
} else {
|
||||
$cntfilled++;
|
||||
$argname = $option;
|
||||
// The search args must be: split by the comma, trimmed, and empty elements filtered out.
|
||||
$searchargs = array_flip(array_filter(
|
||||
array_map(
|
||||
function ($item) {
|
||||
return trim($item);
|
||||
},
|
||||
explode(',', $options[$option])
|
||||
),
|
||||
function ($item) {
|
||||
return $item !== '';
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
if ($cntempty === 3) {
|
||||
if ($verbose) {
|
||||
cli_error('One of username, email, or id must be set.', $exitmissinguserarg);
|
||||
}
|
||||
exit($exitmissinguserarg);
|
||||
}
|
||||
if ($cntfilled > 1) {
|
||||
if ($verbose) {
|
||||
cli_error('Only one of email, username, or id can be set to identify a user.', $exittoomanyuserarg);
|
||||
}
|
||||
exit($exittoomanyuserarg);
|
||||
}
|
||||
if (empty($searchargs)) {
|
||||
if ($verbose) {
|
||||
cli_error('No values are provided for users.', $exitnosearchargs);
|
||||
}
|
||||
exit($exitnosearchargs);
|
||||
}
|
||||
try {
|
||||
$users = $DB->get_records_list('user', $argname, array_keys($searchargs));
|
||||
} catch (Exception $e) {
|
||||
if ($verbose) {
|
||||
cli_error("Could not fetch data from db by {$argname}: '{$options[$argname]}'.", $exiterrordb);
|
||||
}
|
||||
exit($exiterrordb);
|
||||
}
|
||||
if (empty($users)) {
|
||||
if ($verbose) {
|
||||
cli_error("Can not find any user by {$argname}: '{$options[$argname]}'.", $exitnousersfound);
|
||||
}
|
||||
exit($exitnousersfound);
|
||||
}
|
||||
|
||||
// No stop flag set, then just print the user and the current emailstop flag state.
|
||||
if ($options['stop'] === '') {
|
||||
foreach ($users as $user) {
|
||||
if ($verbose) {
|
||||
echo 'user=' . $user->{$argname} . ' - emailstop=' . (int)$user->emailstop . PHP_EOL;
|
||||
unset($searchargs[$user->{$argname}]);
|
||||
}
|
||||
}
|
||||
if ($verbose) {
|
||||
foreach (array_keys($searchargs) as $arg) {
|
||||
echo 'user=' . $arg . ' - not found' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
exit($exitsuccess);
|
||||
}
|
||||
|
||||
// Allowed values for the stop flag enabled are 1 and on, for disabled are 0 and off.
|
||||
$validvalues = ['0', '1', 'off', 'on'];
|
||||
$stopflag = strtolower($options['stop']);
|
||||
if (!in_array($stopflag, $validvalues)) {
|
||||
if ($verbose) {
|
||||
cli_error('Value for the emailstop flag must be one of: ' . implode(', ', $validvalues) . '.', $exitinvalidstopflag);
|
||||
}
|
||||
exit($exitinvalidstopflag);
|
||||
}
|
||||
|
||||
foreach ($validvalues as $value) {
|
||||
if ($value === $stopflag) {
|
||||
$stopflag = ($value === '1' || $value === 'on') ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Update each user with the stop flag to be set if it is necessary.
|
||||
foreach ($users as $user) {
|
||||
$line = 'Update user ' . $user->{$argname} . ($argname !== 'id' ? ' (' . $user->id . ')' : '') . ' - ';
|
||||
if ((int)$user->emailstop !== $stopflag) {
|
||||
$DB->set_field('user', 'emailstop', $stopflag, ['id' => $user->id]);
|
||||
$line .= 'ok';
|
||||
} else {
|
||||
$line .= 'already done';
|
||||
}
|
||||
if ($verbose) {
|
||||
echo $line . PHP_EOL;
|
||||
unset($searchargs[$user->{$argname}]);
|
||||
}
|
||||
|
||||
}
|
||||
if ($verbose) {
|
||||
foreach (array_keys($searchargs) as $arg) {
|
||||
echo 'user=' . $arg . ' - not found' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
exit($exitsuccess);
|
||||
|
||||
@@ -39,6 +39,8 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
// TODO: MDL-71421 - Remove the openssl alternative once sodium becomes a requirement in Moodle 4.2.
|
||||
|
||||
if ($options['help']) {
|
||||
echo "Generate secure key
|
||||
|
||||
@@ -52,7 +54,9 @@ may be manually installed on multiple servers.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
--method <method> Generate key for specified encryption method instead of default (sodium)
|
||||
--method <method> Generate key for specified encryption method instead of default.
|
||||
* sodium
|
||||
* openssl-aes-256-ctr
|
||||
|
||||
Example:
|
||||
php admin/cli/generate_key.php
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This script allows to import a course from CLI.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage cli
|
||||
* @author Tomo Tsuyuki <tomotsuyuki@catalyst-au.net>
|
||||
* @copyright 2023 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', 1);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
|
||||
|
||||
list($options, $unrecognized) = cli_get_params([
|
||||
'srccourseid' => '',
|
||||
'srccmid' => '',
|
||||
'dstcourseid' => '',
|
||||
'showdebugging' => false,
|
||||
'help' => false,
|
||||
], [
|
||||
's' => 'showdebugging',
|
||||
'h' => 'help',
|
||||
]);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] ||
|
||||
!(($options['srccourseid'] && $options['dstcourseid'])
|
||||
|| ($options['srccmid'] && $options['dstcourseid']))) {
|
||||
$help = <<<EOL
|
||||
Import course or course module into provided course.
|
||||
|
||||
Options:
|
||||
--srccourseid=INT Source course ID to backup.
|
||||
--srccmid=INT Source course module ID to backup.
|
||||
--dstcourseid=INT Destination course ID to restore.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example1: (Import from a course into another course)
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/import.php --srccourseid=12 --dstcourseid=13\n
|
||||
|
||||
Example2: (Import from a course module into a course)
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/import.php --srccmid=21 --dstcourseid=11\n
|
||||
EOL;
|
||||
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($options['showdebugging']) {
|
||||
set_debugging(DEBUG_DEVELOPER, true);
|
||||
}
|
||||
|
||||
if (!$admin = get_admin()) {
|
||||
throw new \moodle_exception('noadmins');
|
||||
}
|
||||
|
||||
if (!empty($options['srccourseid']) && !empty($options['dstcourseid'])) {
|
||||
// Import from course into course.
|
||||
if (!$srccourse = $DB->get_record('course', ['id' => $options['srccourseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
if (!$dstcourse = $DB->get_record('course', ['id' => $options['dstcourseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
|
||||
cli_heading(get_string('importfromcoursetocourse', 'backup', (object)$options));
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $srccourse->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->id);
|
||||
$backupid = $bc->get_backupid();
|
||||
$bc->execute_plan();
|
||||
$bc->destroy();
|
||||
cli_heading(get_string('backupthenrestore', 'backup'));
|
||||
|
||||
$rc = new restore_controller($backupid, $dstcourse->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_SAMESITE, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
cli_heading(get_string('restoredcourseid', 'backup', $dstcourse->id));
|
||||
} else if (!empty($options['srccmid']) && !empty($options['dstcourseid'])) {
|
||||
// Import from course module into course.
|
||||
if (!$cm = $DB->get_record('course_modules', ['id' => $options['srccmid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcoursemoduleid', 'error', '', $options['srccmid']);
|
||||
}
|
||||
if (!$course = $DB->get_record('course', ['id' => $options['dstcourseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
|
||||
cli_heading(get_string('importfromccmidtocourse', 'backup', (object)$options));
|
||||
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->id);
|
||||
$backupid = $bc->get_backupid();
|
||||
$bc->execute_plan();
|
||||
$bc->destroy();
|
||||
cli_heading(get_string('backupthenrestore', 'backup'));
|
||||
|
||||
$rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_SAMESITE, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
cli_heading(get_string('restoredcourseid', 'backup', $course->id));
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
}
|
||||
|
||||
exit(0);
|
||||
@@ -57,7 +57,6 @@ Options:
|
||||
--fullname=STRING Name of the site
|
||||
--shortname=STRING Name of the site
|
||||
--summary=STRING The summary to be displayed on the front page
|
||||
--supportemail=STRING Email address for support and help.
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
@@ -99,7 +98,6 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'fullname' => '',
|
||||
'shortname' => '',
|
||||
'summary' => '',
|
||||
'supportemail' => '',
|
||||
'agree-license' => false,
|
||||
'help' => false
|
||||
),
|
||||
@@ -138,15 +136,6 @@ if (!empty($options['adminemail']) && !validate_email($options['adminemail'])) {
|
||||
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
|
||||
}
|
||||
|
||||
// Validate that the supportemail provided was an e-mail address.
|
||||
if (!empty($options['supportemail']) && !validate_email($options['supportemail'])) {
|
||||
$a = (object) [
|
||||
'option' => 'supportemail',
|
||||
'value' => $options['supportemail']
|
||||
];
|
||||
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
|
||||
}
|
||||
|
||||
$options['lang'] = clean_param($options['lang'], PARAM_SAFEDIR);
|
||||
if (!file_exists($CFG->dirroot.'/install/lang/'.$options['lang'])) {
|
||||
$options['lang'] = 'en';
|
||||
|
||||
@@ -31,7 +31,6 @@ require_once($CFG->libdir.'/clilib.php');
|
||||
$longoptions = [
|
||||
'help' => false,
|
||||
'muc' => false,
|
||||
'courses' => false,
|
||||
'theme' => false,
|
||||
'lang' => false,
|
||||
'js' => false,
|
||||
@@ -56,8 +55,6 @@ all caches will be purged.
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
--muc Purge all MUC caches (includes lang cache)
|
||||
--courses Purge all course caches (or only those specified by a comma-separated list).
|
||||
e.g. --courses=4,67,145
|
||||
--theme Purge theme cache
|
||||
--lang Purge language string cache
|
||||
--js Purge JavaScript cache
|
||||
|
||||
@@ -32,13 +32,11 @@ require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
|
||||
list($options, $unrecognized) = cli_get_params([
|
||||
'file' => '',
|
||||
'categoryid' => '',
|
||||
'courseid' => '',
|
||||
'showdebugging' => false,
|
||||
'help' => false,
|
||||
], [
|
||||
'f' => 'file',
|
||||
'c' => 'categoryid',
|
||||
'C' => 'courseid',
|
||||
's' => 'showdebugging',
|
||||
'h' => 'help',
|
||||
]);
|
||||
@@ -48,17 +46,15 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] || !($options['file']) || !($options['categoryid'] || $options['courseid'])) {
|
||||
if ($options['help'] || !($options['file']) || !($options['categoryid'])) {
|
||||
$help = <<<EOL
|
||||
Restore backup into provided category or course.
|
||||
If courseid is set, course module/s will be added into the course.
|
||||
Restore backup into provided category.
|
||||
|
||||
Options:
|
||||
-f, --file=STRING Path to the backup file.
|
||||
-c, --categoryid=INT ID of the course category to restore to.
|
||||
-C, --courseid=INT ID of the course to restore to. This option is ignored if categoryid is set.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
-f, --file=STRING Path to the backup file.
|
||||
-c, --categoryid=INT ID of the category to restore too.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/file.mbz --categoryid=1\n
|
||||
@@ -80,20 +76,12 @@ if (!file_exists($options['file'])) {
|
||||
throw new \moodle_exception('filenotfound');
|
||||
}
|
||||
|
||||
if ($options['categoryid']) {
|
||||
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcategoryid');
|
||||
}
|
||||
} else if ($options['courseid']) {
|
||||
if (!$course = $DB->get_record('course', ['id' => $options['courseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcategoryid');
|
||||
}
|
||||
|
||||
$backupdir = restore_controller::get_tempdir_name(SITEID, $USER->id);
|
||||
$path = make_backup_temp_directory($backupdir);
|
||||
$backupdir = "restore_" . uniqid();
|
||||
$path = $CFG->tempdir . DIRECTORY_SEPARATOR . "backup" . DIRECTORY_SEPARATOR . $backupdir;
|
||||
|
||||
cli_heading(get_string('extractingbackupfileto', 'backup', $path));
|
||||
$fp = get_file_packer('application/vnd.moodle.backup');
|
||||
@@ -104,29 +92,13 @@ try {
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
|
||||
get_string('restoringcourseshortname', 'backup'));
|
||||
|
||||
if (!empty($course)) {
|
||||
$courseid = $course->id;
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
} else {
|
||||
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
|
||||
}
|
||||
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
|
||||
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
|
||||
// Rename course name if the backup is from course module and restore to category.
|
||||
if (empty($course)) {
|
||||
$course = get_course($courseid);
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoretonewcourse', 'backup'),
|
||||
get_string('newcourse'));
|
||||
$course->fullname = $fullname;
|
||||
$course->shortname = $shortname;
|
||||
$course->visible = 1;
|
||||
$DB->update_record('course', $course);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
cli_heading(get_string('cleaningtempdata'));
|
||||
fulldelete($path);
|
||||
|
||||
@@ -27,6 +27,7 @@ define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once("$CFG->libdir/clilib.php");
|
||||
require_once("$CFG->libdir/cronlib.php");
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
[
|
||||
@@ -36,8 +37,6 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'showsql' => false,
|
||||
'showdebugging' => false,
|
||||
'force' => false,
|
||||
'disable' => false,
|
||||
'enable' => false,
|
||||
], [
|
||||
'h' => 'help',
|
||||
'f' => 'force',
|
||||
@@ -49,15 +48,11 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
$commands = ['list', 'execute', 'disable', 'enable'];
|
||||
$hascommand = count(array_filter($commands, fn($command) => $options[$command])) > 0;
|
||||
if ($options['help'] || !$hascommand) {
|
||||
if ($options['help'] or (!$options['list'] and !$options['execute'])) {
|
||||
$help =
|
||||
"Scheduled cron tasks.
|
||||
|
||||
Options:
|
||||
--disable=\\some\\task Disable scheduled task
|
||||
--enable=\\some\\task Enable scheduled task
|
||||
--execute=\\some\\task Execute scheduled task manually
|
||||
--list List all scheduled tasks
|
||||
--showsql Show sql queries before they are executed
|
||||
@@ -125,43 +120,17 @@ if ($options['list']) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
mtrace("Moodle upgrade pending, cannot manage tasks.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ($disable = $options['disable']) {
|
||||
if (!$task = \core\task\manager::get_scheduled_task($disable)) {
|
||||
mtrace("Task '$disable' not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
$task->disable();
|
||||
mtrace("Disabled '$disable'");
|
||||
} catch (Exception $e) {
|
||||
mtrace("$e->getMessage()");
|
||||
exit(1);
|
||||
}
|
||||
} else if ($enable = $options['enable']) {
|
||||
if (!$task = \core\task\manager::get_scheduled_task($enable)) {
|
||||
mtrace("Task '$enable' not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
$task->enable();
|
||||
mtrace("Enabled '$enable'");
|
||||
} catch (Exception $e) {
|
||||
mtrace("$e->getMessage()");
|
||||
exit(1);
|
||||
}
|
||||
} else if ($execute = $options['execute']) {
|
||||
if ($execute = $options['execute']) {
|
||||
if (!$task = \core\task\manager::get_scheduled_task($execute)) {
|
||||
mtrace("Task '$execute' not found");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (moodle_needs_upgrading()) {
|
||||
mtrace("Moodle upgrade pending, cannot execute tasks.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!get_config('core', 'cron_enabled') && !$options['force']) {
|
||||
mtrace('Cron is disabled. Use --force to override.');
|
||||
exit(1);
|
||||
@@ -173,7 +142,7 @@ if ($disable = $options['disable']) {
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
||||
// Emulate normal session - we use admin account by default.
|
||||
\core\cron::setup_user();
|
||||
cron_setup_user();
|
||||
|
||||
// Execute the task.
|
||||
\core\local\cli\shutdown::script_supports_graceful_exit();
|
||||
@@ -189,7 +158,11 @@ if ($disable = $options['disable']) {
|
||||
}
|
||||
|
||||
$task->set_lock($lock);
|
||||
$cronlock->release();
|
||||
if (!$task->is_blocking()) {
|
||||
$cronlock->release();
|
||||
} else {
|
||||
$task->set_cron_lock($cronlock);
|
||||
}
|
||||
|
||||
\core\cron::run_inner_scheduled_task($task);
|
||||
cron_run_inner_scheduled_task($task);
|
||||
}
|
||||
|
||||
+28
-114
@@ -48,16 +48,12 @@ require_once($CFG->libdir.'/environmentlib.php');
|
||||
$lang = isset($SESSION->lang) ? $SESSION->lang : $CFG->lang;
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array(
|
||||
'allow-unstable' => false,
|
||||
'help' => false,
|
||||
'is-maintenance-required' => false,
|
||||
'is-pending' => false,
|
||||
'lang' => $lang,
|
||||
'maintenance' => true,
|
||||
'non-interactive' => false,
|
||||
'set-ui-upgrade-lock' => false,
|
||||
'unset-ui-upgrade-lock' => false,
|
||||
'verbose-settings' => false,
|
||||
'non-interactive' => false,
|
||||
'allow-unstable' => false,
|
||||
'help' => false,
|
||||
'lang' => $lang,
|
||||
'verbose-settings' => false,
|
||||
'is-pending' => false,
|
||||
),
|
||||
array(
|
||||
'h' => 'help'
|
||||
@@ -83,35 +79,19 @@ Please note you must execute this script with the same uid as apache!
|
||||
Site defaults may be changed via local/defaults.php.
|
||||
|
||||
Options:
|
||||
--allow-unstable Upgrade even if the version is not marked as stable yet,
|
||||
required in non-interactive mode.
|
||||
-h, --help Print out this help.
|
||||
--is-maintenance-required Returns exit code 2 if the upgrade requires maintenance mode.
|
||||
Returns exit code 3 if no maintenance is required for the upgrade.
|
||||
--is-pending Exit with error code 2 if an upgrade is required.
|
||||
--lang=CODE Set preferred language for CLI output. Defaults to the
|
||||
site language if not set. Defaults to 'en' if the lang
|
||||
parameter is invalid or if the language pack is not
|
||||
installed.
|
||||
--maintenance Sets whether this upgrade will use maintenance mode.
|
||||
If not possible, the upgrade will not happen and the script will exit.
|
||||
WARNING: Caches (except theme) will be STALE and MUST be purged after upgrading.
|
||||
DO NOT USE if the upgrade contains known breaking changes to the way data
|
||||
and the database interact.
|
||||
RECOMMENDED for lightweight deployments, to allow for a graceful purge and
|
||||
rebuild of the cache.
|
||||
--non-interactive No interactive questions or confirmations.
|
||||
--set-ui-upgrade-lock Sets the upgrade to CLI only and unable to be triggered from the frontend.
|
||||
If called with --maintenance=false, the lock WILL NOT be released when the
|
||||
upgrade finishes, and MUST be manually removed.
|
||||
If called with --is-maintenance-required before an upgrade,
|
||||
The lock WILL be released when the upgrade finishes.
|
||||
--unset-ui-upgrade-lock Removes the frontend upgrade lock, if the lock exists.
|
||||
Useful when an error during the upgrade leaves the upgrade locked,
|
||||
or there is need to control the time where the unlock happens.
|
||||
--verbose-settings Show new settings values. By default only the name of
|
||||
new core or plugin settings are displayed. This option
|
||||
outputs the new values as well as the setting name.
|
||||
--non-interactive No interactive questions or confirmations
|
||||
--allow-unstable Upgrade even if the version is not marked as stable yet,
|
||||
required in non-interactive mode.
|
||||
--lang=CODE Set preferred language for CLI output. Defaults to the
|
||||
site language if not set. Defaults to 'en' if the lang
|
||||
parameter is invalid or if the language pack is not
|
||||
installed.
|
||||
--verbose-settings Show new settings values. By default only the name of
|
||||
new core or plugin settings are displayed. This option
|
||||
outputs the new values as well as the setting name.
|
||||
--is-pending If an upgrade is needed it exits with an error code of
|
||||
2 so it distinct from other types of errors.
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/upgrade.php
|
||||
@@ -135,58 +115,12 @@ if ($version < $CFG->version) {
|
||||
$oldversion = "$CFG->release ($CFG->version)";
|
||||
$newversion = "$release ($version)";
|
||||
|
||||
if ($options['unset-ui-upgrade-lock']) {
|
||||
// Unconditionally unset this config if requested.
|
||||
set_config('outagelessupgrade', false);
|
||||
cli_writeln(get_string('cliupgradeunsetlock', 'admin'));
|
||||
}
|
||||
|
||||
$allhash = core_component::get_all_component_hash();
|
||||
|
||||
// Initialise allcomponent hash if not set. It will be correctly set after upgrade.
|
||||
$CFG->allcomponenthash = $CFG->allcomponenthash ?? '';
|
||||
if (!$options['maintenance']) {
|
||||
if ($allhash !== $CFG->allcomponenthash) {
|
||||
// Throw an error here, we can't proceed, this needs to set maintenance.
|
||||
cli_error(get_string('cliupgrademaintenancerequired', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// Set a constant to stop any upgrade var from being set during processing.
|
||||
// This protects against the upgrade setting timeouts and maintenance during the upgrade.
|
||||
define('CLI_UPGRADE_RUNNING', true);
|
||||
|
||||
// This database control is the control to block the GUI from doing upgrade related actions.
|
||||
set_config('outagelessupgrade', true);
|
||||
}
|
||||
|
||||
// We should ignore all upgrade locks here.
|
||||
if (!moodle_needs_upgrading(false)) {
|
||||
if (!moodle_needs_upgrading()) {
|
||||
cli_error(get_string('cliupgradenoneed', 'core_admin', $newversion), 0);
|
||||
}
|
||||
|
||||
// Handle exit based options for outputting upgrade state.
|
||||
if ($options['is-pending'] || $options['is-maintenance-required']) {
|
||||
// If we aren't doing a maintenance check, plain pending check.
|
||||
if (!$options['is-maintenance-required']) {
|
||||
cli_error(get_string('cliupgradepending', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// Can we do this safely with no maintenance/outage? Detect if there is a schema or other application state change.
|
||||
if ($allhash !== $CFG->allcomponenthash) {
|
||||
// State change here, we need to do this in maintenance.
|
||||
cli_writeln(get_string('cliupgradepending', 'core_admin'));
|
||||
cli_error(get_string('cliupgrademaintenancerequired', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// If requested, we should always set the upgrade lock here, so this cannot be run from frontend.
|
||||
if ($options['set-ui-upgrade-lock']) {
|
||||
set_config('outagelessupgrade', true);
|
||||
cli_writeln(get_string('cliupgradesetlock', 'admin'));
|
||||
}
|
||||
|
||||
// We can do an upgrade without maintenance!
|
||||
cli_writeln(get_string('cliupgradepending', 'core_admin'));
|
||||
cli_error(get_string('cliupgrademaintenancenotrequired', 'core_admin'), 3);
|
||||
if ($options['is-pending']) {
|
||||
cli_error(get_string('cliupgradepending', 'core_admin'), 2);
|
||||
}
|
||||
|
||||
// Test environment first.
|
||||
@@ -253,18 +187,12 @@ if ($interactive) {
|
||||
}
|
||||
|
||||
if ($version > $CFG->version) {
|
||||
|
||||
// Only purge caches if this is a plain upgrade.
|
||||
// In the case of a no-outage upgrade, we will gracefully roll caches after upgrade.
|
||||
if ($options['maintenance']) {
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
}
|
||||
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
upgrade_core($version, true);
|
||||
}
|
||||
set_config('release', $release);
|
||||
@@ -302,18 +230,4 @@ foreach ($settingsoutput as $setting => $value) {
|
||||
upgrade_themes();
|
||||
|
||||
echo get_string('cliupgradefinished', 'admin', $a)."\n";
|
||||
|
||||
if (!$options['maintenance']) {
|
||||
cli_writeln(get_string('cliupgradecompletenomaintenanceupgrade', 'admin'));
|
||||
|
||||
// Here we check if upgrade lock has not been specifically set during this upgrade run.
|
||||
// This supports wider server orchestration actions happening, which should call with no-maintenance AND set-ui-upgrade-lock,
|
||||
// such as a new docker container deployment, of which the moodle upgrade is only a component.
|
||||
if (!$options['set-ui-upgrade-lock']) {
|
||||
// In this case we should release the lock now, as the upgrade is finished.
|
||||
// We weren't told to keep the lock with set-ui-upgrade-lock, so release.
|
||||
set_config('outagelessupgrade', false);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0); // 0 means success
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Communication and its plugins settings.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage communication
|
||||
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$name = required_param('name', PARAM_PLUGIN);
|
||||
|
||||
$syscontext = context_system::instance();
|
||||
$PAGE->set_url('/admin/communication.php');
|
||||
$PAGE->set_context($syscontext);
|
||||
|
||||
require_admin();
|
||||
require_sesskey();
|
||||
|
||||
$return = new moodle_url('/admin/settings.php', ['section' => 'managecommunicationproviders']);
|
||||
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('communication');
|
||||
$sortorder = array_flip(array_keys($plugins));
|
||||
|
||||
if (!isset($plugins[$name])) {
|
||||
throw new moodle_exception('communicationprovidernotfound', 'core_communication', $return, $name);
|
||||
}
|
||||
|
||||
$plugintypename = $plugins[$name]->type . '_' . $plugins[$name]->name;
|
||||
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
if ($plugins[$name]->is_enabled()) {
|
||||
$class = core_plugin_manager::resolve_plugininfo_class('communication');
|
||||
$class::enable_plugin($name, false);
|
||||
}
|
||||
break;
|
||||
case 'enable':
|
||||
if (!$plugins[$name]->is_enabled()) {
|
||||
$class = core_plugin_manager::resolve_plugininfo_class('communication');
|
||||
$class::enable_plugin($name, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
redirect($return);
|
||||
@@ -1,79 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Reset course indentation
|
||||
*
|
||||
* @copyright 2023 Amaia Anabitarte <amaia@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../../config.php');
|
||||
|
||||
require_admin();
|
||||
|
||||
$format = required_param('format', PARAM_PLUGIN);
|
||||
$confirm = optional_param('confirm', false, PARAM_BOOL);
|
||||
$backurl = new moodle_url('/admin/settings.php', ['section' => 'formatsetting'.$format]);
|
||||
|
||||
$PAGE->set_url('/admin/course/resetindentation.php', ['format' => $format]);
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
if ($confirm) {
|
||||
require_sesskey();
|
||||
$courses = $DB->get_records('course', ['format' => $format], 'id', 'id');
|
||||
if (!empty($courses)) {
|
||||
$courseids = array_keys($courses);
|
||||
list($courseinsql, $courseparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED, 'course');
|
||||
$DB->set_field_select('course_modules', 'indent', '0', "course $courseinsql AND indent <> 0", $courseparams);
|
||||
rebuild_course_cache(0, true);
|
||||
}
|
||||
redirect(
|
||||
$backurl,
|
||||
get_string('resetindentationsuccess', 'admin'),
|
||||
null,
|
||||
\core\output\notification::NOTIFY_SUCCESS
|
||||
);
|
||||
}
|
||||
|
||||
$strtitle = get_string('resetindentation', 'admin');
|
||||
|
||||
$PAGE->set_title($strtitle);
|
||||
$PAGE->set_heading($strtitle);
|
||||
|
||||
navigation_node::override_active_url(new moodle_url(
|
||||
'/admin/course/resetindentation.php',
|
||||
['action' => 'confirm', 'format' => $format]
|
||||
));
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$displayoptions = ['confirmtitle' => get_string('resetindentation_title', 'admin')];
|
||||
$confirmbutton = new single_button(
|
||||
new moodle_url('/admin/course/resetindentation.php', ['confirm' => 1, 'format' => $format, 'sesskey' => sesskey()]),
|
||||
get_string('resetindentation', 'admin'),
|
||||
'post',
|
||||
single_button::BUTTON_DANGER
|
||||
);
|
||||
$cancelbutton = new single_button($backurl, get_string('cancel'));
|
||||
echo $OUTPUT->confirm(
|
||||
get_string('resetindentation_help', 'admin', ['format' => get_string('pluginname', 'format_'.$format)]),
|
||||
$confirmbutton,
|
||||
$cancelbutton,
|
||||
$displayoptions
|
||||
);
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
+7
-6
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -35,7 +36,6 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// phpcs:ignoreFile moodle.Files.MoodleInternal.MoodleInternalGlobalState
|
||||
|
||||
if (defined('STDIN')) {
|
||||
fwrite(STDERR, "ERROR: This script no longer supports CLI, please use admin/cli/cron.php instead\n");
|
||||
@@ -49,7 +49,8 @@ define('WEB_CRON_EMULATED_CLI', 'defined'); // ugly ugly hack, do not use elsewh
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
require('../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require_once($CFG->libdir.'/clilib.php');
|
||||
require_once($CFG->libdir.'/cronlib.php');
|
||||
|
||||
// extra safety
|
||||
\core\session\manager::write_close();
|
||||
@@ -70,11 +71,11 @@ if (!empty($CFG->cronremotepassword)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Send mime type and encoding.
|
||||
// send mime type and encoding
|
||||
@header('Content-Type: text/plain; charset=utf-8');
|
||||
|
||||
// We do not want html markup in emulated CLI.
|
||||
// we do not want html markup in emulated CLI
|
||||
@ini_set('html_errors', 'off');
|
||||
|
||||
// Execute the cron, disabling keepalive.
|
||||
\core\cron::run_main_process(0);
|
||||
// execute the cron
|
||||
cron_run();
|
||||
|
||||
+47
-53
@@ -1,95 +1,87 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* A page to manage editor plugins.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* Allows admin to configure editors.
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$plugin = required_param('plugin', PARAM_PLUGIN);
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$editor = required_param('editor', PARAM_PLUGIN);
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
|
||||
$PAGE->set_url('/admin/editors.php', ['action' => $action, 'editor' => $plugin]);
|
||||
$PAGE->set_url('/admin/editors.php', array('action'=>$action, 'editor'=>$editor));
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
require_admin();
|
||||
require_sesskey();
|
||||
|
||||
$returnurl = new moodle_url('/admin/settings.php', ['section' => 'manageeditors']);
|
||||
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageeditors";
|
||||
|
||||
// Get currently installed and enabled auth plugins.
|
||||
$availableeditors = editors_get_available();
|
||||
if (!empty($plugin) && empty($availableeditors[$plugin])) {
|
||||
redirect($returnurl);
|
||||
// get currently installed and enabled auth plugins
|
||||
$available_editors = editors_get_available();
|
||||
if (!empty($editor) and empty($available_editors[$editor])) {
|
||||
redirect ($returnurl);
|
||||
}
|
||||
|
||||
$activeeditors = explode(',', $CFG->texteditors);
|
||||
foreach ($activeeditors as $key => $active) {
|
||||
if (empty($availableeditors[$active])) {
|
||||
unset($activeeditors[$key]);
|
||||
$active_editors = explode(',', $CFG->texteditors);
|
||||
foreach ($active_editors as $key=>$active) {
|
||||
if (empty($available_editors[$active])) {
|
||||
unset($active_editors[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// process actions
|
||||
|
||||
if (!confirm_sesskey()) {
|
||||
redirect($returnurl);
|
||||
}
|
||||
|
||||
$return = true;
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
// Remove from enabled list.
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('editor');
|
||||
$class::enable_plugin($plugin, false);
|
||||
$class::enable_plugin($editor, false);
|
||||
break;
|
||||
|
||||
case 'enable':
|
||||
// Add to enabled list.
|
||||
if (!in_array($plugin, $activeeditors)) {
|
||||
if (!in_array($editor, $active_editors)) {
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('editor');
|
||||
$class::enable_plugin($plugin, true);
|
||||
$class::enable_plugin($editor, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'down':
|
||||
$key = array_search($plugin, $activeeditors);
|
||||
$key = array_search($editor, $active_editors);
|
||||
// check auth plugin is valid
|
||||
if ($key !== false) {
|
||||
// Move down the list.
|
||||
if ($key < (count($activeeditors) - 1)) {
|
||||
$fsave = $activeeditors[$key];
|
||||
$activeeditors[$key] = $activeeditors[$key + 1];
|
||||
$activeeditors[$key + 1] = $fsave;
|
||||
add_to_config_log('editor_position', $key, $key + 1, $plugin);
|
||||
set_config('texteditors', implode(',', $activeeditors));
|
||||
// move down the list
|
||||
if ($key < (count($active_editors) - 1)) {
|
||||
$fsave = $active_editors[$key];
|
||||
$active_editors[$key] = $active_editors[$key + 1];
|
||||
$active_editors[$key + 1] = $fsave;
|
||||
add_to_config_log('editor_position', $key, $key + 1, $editor);
|
||||
set_config('texteditors', implode(',', $active_editors));
|
||||
core_plugin_manager::reset_caches();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'up':
|
||||
$key = array_search($plugin, $activeeditors);
|
||||
$key = array_search($editor, $active_editors);
|
||||
// check auth is valid
|
||||
if ($key !== false) {
|
||||
// Move up the list.
|
||||
// move up the list
|
||||
if ($key >= 1) {
|
||||
$fsave = $activeeditors[$key];
|
||||
$activeeditors[$key] = $activeeditors[$key - 1];
|
||||
$activeeditors[$key - 1] = $fsave;
|
||||
add_to_config_log('editor_position', $key, $key - 1, $plugin);
|
||||
set_config('texteditors', implode(',', $activeeditors));
|
||||
$fsave = $active_editors[$key];
|
||||
$active_editors[$key] = $active_editors[$key - 1];
|
||||
$active_editors[$key - 1] = $fsave;
|
||||
add_to_config_log('editor_position', $key, $key - 1, $editor);
|
||||
set_config('texteditors', implode(',', $active_editors));
|
||||
core_plugin_manager::reset_caches();
|
||||
}
|
||||
}
|
||||
@@ -99,4 +91,6 @@ switch ($action) {
|
||||
break;
|
||||
}
|
||||
|
||||
redirect($returnurl);
|
||||
if ($return) {
|
||||
redirect ($returnurl);
|
||||
}
|
||||
|
||||
@@ -3751,7 +3751,6 @@
|
||||
<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>
|
||||
@@ -3923,589 +3922,6 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.2" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_83" message="unsupportedphpversion83" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.3" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_83" message="unsupportedphpversion83" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.4" requires="4.1.2">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.1.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Hooks overview page.
|
||||
*
|
||||
* @package core
|
||||
* @author Petr Skoda
|
||||
* @copyright 2022 Open LMS
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
admin_externalpage_setup('hooksoverview');
|
||||
require_capability('moodle/site:config', \core\context\system::instance());
|
||||
|
||||
$hookmanager = \core\di::get(\core\hook\manager::class);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('hooksoverview', 'core_admin'));
|
||||
|
||||
$table = new \core_admin\table\hook_list_table();
|
||||
$table->out();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
+319
-326
@@ -224,7 +224,7 @@ if (!core_tables_exist()) {
|
||||
$strlicense = get_string('license');
|
||||
|
||||
$PAGE->navbar->add($strlicense);
|
||||
$PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . 'Moodle ' . $CFG->target_release, false);
|
||||
$PAGE->set_title($strinstallation.' - Moodle '.$CFG->target_release);
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
@@ -267,7 +267,7 @@ if (!core_tables_exist()) {
|
||||
upgrade_init_javascript();
|
||||
|
||||
$PAGE->navbar->add($strdatabasesetup);
|
||||
$PAGE->set_title($strinstallation . moodle_page::TITLE_SEPARATOR . $CFG->target_release, false);
|
||||
$PAGE->set_title($strinstallation.' - Moodle '.$CFG->target_release);
|
||||
$PAGE->set_heading($strinstallation);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
@@ -302,77 +302,262 @@ if (empty($CFG->version)) {
|
||||
throw new \moodle_exception('missingconfigversion', 'debug');
|
||||
}
|
||||
|
||||
// If an upgrade is running, an admin page starting a frontend upgrade could corrupt the
|
||||
// DB if the upgrade collided with an already running upgrade process at the wrong time.
|
||||
// Pull the value direct from the DB, this needs to *always* be correct.
|
||||
$outagelessupgrade = !empty($DB->get_field('config', 'value', ['name' => 'outagelessupgrade']));
|
||||
if (!$outagelessupgrade) {
|
||||
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name' => 'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url($PAGE->url), 'Config cache inconsistency detected, resetting caches...');
|
||||
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
|
||||
if ($CFG->version != $DB->get_field('config', 'value', array('name'=>'version'))) {
|
||||
purge_all_caches();
|
||||
redirect(new moodle_url($PAGE->url), 'Config cache inconsistency detected, resetting caches...');
|
||||
}
|
||||
|
||||
if (!$cache and $version > $CFG->version) { // upgrade
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => $confirmupgrade,
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
// Warning about upgrading a test site.
|
||||
$testsite = false;
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
$testsite = 'behat';
|
||||
}
|
||||
|
||||
if (!$cache && $version > $CFG->version && !$outagelessupgrade) { // Upgrade.
|
||||
if (isset($CFG->themerev)) {
|
||||
// Store the themerev to restore after purging caches.
|
||||
$themerev = $CFG->themerev;
|
||||
}
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmupgrade' => $confirmupgrade,
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
// We then purge the regular caches.
|
||||
purge_all_caches();
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
if (isset($themerev)) {
|
||||
// Restore the themerev
|
||||
set_config('themerev', $themerev);
|
||||
}
|
||||
|
||||
// Warning about upgrading a test site.
|
||||
$testsite = false;
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
$testsite = 'behat';
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (upgrade_stale_php_files_present()) {
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_stale_php_files_page();
|
||||
die();
|
||||
}
|
||||
|
||||
if (empty($confirmupgrade)) {
|
||||
$a = new stdClass();
|
||||
$a->oldversion = "$CFG->release (".sprintf('%.2f', $CFG->version).")";
|
||||
$a->newversion = "$release (".sprintf('%.2f', $version).")";
|
||||
$strdatabasechecking = get_string('databasechecking', '', $a);
|
||||
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_heading($strdatabasechecking);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir.'/environmentlib.php');
|
||||
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
|
||||
$strcurrentrelease = get_string('currentrelease');
|
||||
|
||||
$PAGE->navbar->add($strcurrentrelease);
|
||||
$PAGE->set_title($strcurrentrelease);
|
||||
$PAGE->set_heading($strcurrentrelease);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmplugins)) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
$PAGE->set_title($strplugincheck);
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
if (isset($CFG->themerev)) {
|
||||
// Store the themerev to restore after purging caches.
|
||||
$themerev = $CFG->themerev;
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
foreach ($abortables as $plugin) {
|
||||
$pluginman->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx, 'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// We purge all of MUC's caches here.
|
||||
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
|
||||
// This ensures a real config object is loaded and the stores will be purged.
|
||||
// This is the only way we can purge custom caches such as memcache or APC.
|
||||
// Note: all other calls to caches will still used the disabled API.
|
||||
cache_helper::purge_all(true);
|
||||
// We then purge the regular caches.
|
||||
purge_all_caches();
|
||||
|
||||
if (isset($themerev)) {
|
||||
// Restore the themerev.
|
||||
set_config('themerev', $themerev);
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
|
||||
$abortable = $pluginman->get_plugin_info($abortinstall);
|
||||
if ($pluginman->can_cancel_plugin_installation($abortable)) {
|
||||
echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
|
||||
die();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
|
||||
die();
|
||||
|
||||
} else {
|
||||
// Always verify plugin dependencies!
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
|
||||
// Launch main upgrade.
|
||||
upgrade_core($version, true);
|
||||
}
|
||||
} else if ($version < $CFG->version) {
|
||||
// better stop here, we can not continue with plugin upgrades or anything else
|
||||
throw new moodle_exception('downgradedcore', 'error', new moodle_url('/admin/'));
|
||||
}
|
||||
|
||||
// Updated human-readable release version if necessary
|
||||
if (!$cache and $release <> $CFG->release) { // Update the release version
|
||||
set_config('release', $release);
|
||||
}
|
||||
|
||||
if (!$cache and $branch <> $CFG->branch) { // Update the branch
|
||||
set_config('branch', $branch);
|
||||
}
|
||||
|
||||
if (!$cache and moodle_needs_upgrading()) {
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (upgrade_stale_php_files_present()) {
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_cacheable(false);
|
||||
if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir . '/environmentlib.php');
|
||||
|
||||
echo $output->upgrade_stale_php_files_page();
|
||||
die();
|
||||
}
|
||||
|
||||
if (empty($confirmupgrade)) {
|
||||
$a = new stdClass();
|
||||
$a->oldversion = "$CFG->release (".sprintf('%.2f', $CFG->version).")";
|
||||
$a->newversion = "$release (".sprintf('%.2f', $version).")";
|
||||
$strdatabasechecking = get_string('databasechecking', '', $a);
|
||||
|
||||
$PAGE->set_title($stradministration);
|
||||
$PAGE->set_heading($strdatabasechecking);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir.'/environmentlib.php');
|
||||
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
|
||||
$strcurrentrelease = get_string('currentrelease');
|
||||
|
||||
@@ -384,7 +569,7 @@ if (!$outagelessupgrade) {
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
|
||||
die();
|
||||
|
||||
} else if (empty($confirmplugins)) {
|
||||
} else if (!$confirmplugins) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
@@ -392,11 +577,9 @@ if (!$outagelessupgrade) {
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
@@ -406,7 +589,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
@@ -415,7 +598,8 @@ if (!$outagelessupgrade) {
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, ['abortinstallx' => $abortinstallx, 'confirmabortinstall' => 1]);
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx,
|
||||
'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
@@ -425,7 +609,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
@@ -442,7 +626,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
@@ -455,7 +639,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
@@ -469,7 +653,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
@@ -479,7 +663,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
@@ -492,7 +676,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
@@ -502,7 +686,7 @@ if (!$outagelessupgrade) {
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate and $installupdateversion) {
|
||||
// No sesskey support guaranteed here, because sessions might not work yet.
|
||||
require_sesskey();
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
@@ -514,280 +698,89 @@ if (!$outagelessupgrade) {
|
||||
}
|
||||
}
|
||||
|
||||
echo $output->upgrade_plugin_check_page(core_plugin_manager::instance(), \core\update\checker::instance(),
|
||||
$version, $showallplugins, $PAGE->url, new moodle_url($PAGE->url, array('confirmplugincheck' => 1)));
|
||||
// Show plugins info.
|
||||
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
|
||||
$version, $showallplugins,
|
||||
new moodle_url($PAGE->url),
|
||||
new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
|
||||
die();
|
||||
|
||||
} else {
|
||||
// Always verify plugin dependencies!
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
|
||||
// Launch main upgrade.
|
||||
upgrade_core($version, true);
|
||||
}
|
||||
} else if ($version < $CFG->version) {
|
||||
// Better stop here, we can not continue with plugin upgrades or anything else.
|
||||
throw new moodle_exception('downgradedcore', 'error', new moodle_url('/admin/'));
|
||||
}
|
||||
|
||||
// Updated human-readable release version if necessary.
|
||||
if (!$cache && $release <> $CFG->release ) { // Update the release version.
|
||||
set_config('release', $release);
|
||||
}
|
||||
|
||||
if (!$cache && $branch <> $CFG->branch) { // Update the branch.
|
||||
set_config('branch', $branch);
|
||||
}
|
||||
|
||||
if (!$cache && moodle_needs_upgrading()) {
|
||||
|
||||
$PAGE->set_url(new moodle_url($PAGE->url, array(
|
||||
'confirmrelease' => $confirmrelease,
|
||||
'confirmplugincheck' => $confirmplugins,
|
||||
)));
|
||||
|
||||
check_upgrade_key($upgradekeyhash);
|
||||
|
||||
if (!$PAGE->headerprinted) {
|
||||
// Means core upgrade or installation was not already done.
|
||||
|
||||
$pluginman = core_plugin_manager::instance();
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!$pluginman->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (empty($confirmrelease)) {
|
||||
require_once($CFG->libdir . '/environmentlib.php');
|
||||
|
||||
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
|
||||
$strcurrentrelease = get_string('currentrelease');
|
||||
|
||||
$PAGE->navbar->add($strcurrentrelease);
|
||||
$PAGE->set_title($strcurrentrelease);
|
||||
$PAGE->set_heading($strcurrentrelease);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
|
||||
die();
|
||||
|
||||
} else if (!$confirmplugins) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
$PAGE->navbar->add($strplugincheck);
|
||||
$PAGE->set_title($strplugincheck);
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
|
||||
// Check for available updates.
|
||||
if ($fetchupdates) {
|
||||
require_sesskey();
|
||||
$updateschecker = \core\update\checker::instance();
|
||||
if ($updateschecker->enabled()) {
|
||||
$updateschecker->fetch();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel all plugin installations.
|
||||
if ($abortinstallx) {
|
||||
require_sesskey();
|
||||
$abortables = $pluginman->list_cancellable_installations();
|
||||
if ($abortables) {
|
||||
if ($confirmabortinstall) {
|
||||
foreach ($abortables as $plugin) {
|
||||
$pluginman->cancel_plugin_installation($plugin->component);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstallx' => $abortinstallx,
|
||||
'confirmabortinstall' => 1));
|
||||
echo $output->upgrade_confirm_abort_install_page($abortables, $continue);
|
||||
die();
|
||||
}
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin installation.
|
||||
if ($abortinstall) {
|
||||
require_sesskey();
|
||||
if ($confirmabortinstall) {
|
||||
$pluginman->cancel_plugin_installation($abortinstall);
|
||||
redirect($PAGE->url);
|
||||
} else {
|
||||
$continue = new moodle_url($PAGE->url, array('abortinstall' => $abortinstall, 'confirmabortinstall' => 1));
|
||||
$abortable = $pluginman->get_plugin_info($abortinstall);
|
||||
if ($pluginman->can_cancel_plugin_installation($abortable)) {
|
||||
echo $output->upgrade_confirm_abort_install_page(array($abortable), $continue);
|
||||
die();
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel all plugins upgrades (that is, restore archived versions).
|
||||
if ($abortupgradex) {
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if ($restorable) {
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgradex' => 1, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Cancel single plugin upgrade (that is, install the archived version).
|
||||
if ($abortupgrade) {
|
||||
require_sesskey();
|
||||
$restorable = $pluginman->list_restorable_archives();
|
||||
if (isset($restorable[$abortupgrade])) {
|
||||
$restorable = array($restorable[$abortupgrade]);
|
||||
upgrade_install_plugins($restorable, $confirmabortupgrade,
|
||||
get_string('cancelupgradehead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('abortupgrade' => $abortupgrade, 'confirmabortupgrade' => 1))
|
||||
);
|
||||
}
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Install all available missing dependencies.
|
||||
if ($installdepx) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdepx' => 1, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available missing dependency.
|
||||
if ($installdep) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->missing_dependencies(true));
|
||||
if (!empty($installable[$installdep])) {
|
||||
$installable = array($installable[$installdep]);
|
||||
upgrade_install_plugins($installable, $confirminstalldep,
|
||||
get_string('dependencyinstallhead', 'core_plugin'),
|
||||
new moodle_url($PAGE->url, array('installdep' => $installdep, 'confirminstalldep' => 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Install all available updates.
|
||||
if ($installupdatex) {
|
||||
require_sesskey();
|
||||
$installable = $pluginman->filter_installable($pluginman->available_updates());
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdatex' => 1, 'confirminstallupdate' => 1))
|
||||
);
|
||||
}
|
||||
|
||||
// Install single available update.
|
||||
if ($installupdate && $installupdateversion) {
|
||||
require_sesskey();
|
||||
if ($pluginman->is_remote_plugin_installable($installupdate, $installupdateversion)) {
|
||||
$installable = array($pluginman->get_remote_plugin_info($installupdate, $installupdateversion, true));
|
||||
upgrade_install_plugins($installable, $confirminstallupdate,
|
||||
get_string('updateavailableinstallallhead', 'core_admin'),
|
||||
new moodle_url($PAGE->url, array('installupdate' => $installupdate,
|
||||
'installupdateversion' => $installupdateversion, 'confirminstallupdate' => 1)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Show plugins info.
|
||||
echo $output->upgrade_plugin_check_page($pluginman, \core\update\checker::instance(),
|
||||
$version, $showallplugins,
|
||||
new moodle_url($PAGE->url),
|
||||
new moodle_url($PAGE->url, array('confirmplugincheck' => 1, 'cache' => 0)));
|
||||
die();
|
||||
}
|
||||
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!$pluginman->all_plugins_ok($version, $failed, $CFG->branch)) {
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
unset($failed);
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
|
||||
array('confirmplugincheck' => 0)));
|
||||
die();
|
||||
}
|
||||
|
||||
// Install/upgrade all plugins and other parts.
|
||||
upgrade_noncore(true);
|
||||
unset($failed);
|
||||
}
|
||||
|
||||
// If this is the first install, indicate that this site is fully configured,
|
||||
// Except the admin password.
|
||||
if (during_initial_install()) {
|
||||
set_config('rolesactive', 1); // After this, during_initial_install will return false.
|
||||
set_config('adminsetuppending', 1);
|
||||
set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
|
||||
// install/upgrade all plugins and other parts
|
||||
upgrade_noncore(true);
|
||||
}
|
||||
|
||||
// Apply default preset, if it is defined in $CFG and has a valid value.
|
||||
if (!empty($CFG->setsitepresetduringinstall)) {
|
||||
\core_adminpresets\helper::change_default_preset($CFG->setsitepresetduringinstall);
|
||||
}
|
||||
// If this is the first install, indicate that this site is fully configured
|
||||
// except the admin password
|
||||
if (during_initial_install()) {
|
||||
set_config('rolesactive', 1); // after this, during_initial_install will return false.
|
||||
set_config('adminsetuppending', 1);
|
||||
set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
|
||||
|
||||
// We need this redirect to setup proper session.
|
||||
upgrade_finished("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
// Apply default preset, if it is defined in $CFG and has a valid value.
|
||||
if (!empty($CFG->setsitepresetduringinstall)) {
|
||||
\core_adminpresets\helper::change_default_preset($CFG->setsitepresetduringinstall);
|
||||
}
|
||||
|
||||
// Make sure admin user is created - this is the last step,
|
||||
// We need session to be working properly in order to edit admin account.
|
||||
if (!empty($CFG->adminsetuppending)) {
|
||||
$sessionstarted = optional_param('sessionstarted', 0, PARAM_BOOL);
|
||||
if (!$sessionstarted) {
|
||||
redirect("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
// we need this redirect to setup proper session
|
||||
upgrade_finished("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
}
|
||||
|
||||
// make sure admin user is created - this is the last step because we need
|
||||
// session to be working properly in order to edit admin account
|
||||
if (!empty($CFG->adminsetuppending)) {
|
||||
$sessionstarted = optional_param('sessionstarted', 0, PARAM_BOOL);
|
||||
if (!$sessionstarted) {
|
||||
redirect("index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
} else {
|
||||
$sessionverify = optional_param('sessionverify', 0, PARAM_BOOL);
|
||||
if (!$sessionverify) {
|
||||
$SESSION->sessionverify = 1;
|
||||
redirect("index.php?sessionstarted=1&sessionverify=1&lang=$CFG->lang");
|
||||
} else {
|
||||
$sessionverify = optional_param('sessionverify', 0, PARAM_BOOL);
|
||||
if (!$sessionverify) {
|
||||
$SESSION->sessionverify = 1;
|
||||
redirect("index.php?sessionstarted=1&sessionverify=1&lang=$CFG->lang");
|
||||
} else {
|
||||
if (empty($SESSION->sessionverify)) {
|
||||
throw new \moodle_exception('installsessionerror', 'admin', "index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
}
|
||||
unset($SESSION->sessionverify);
|
||||
if (empty($SESSION->sessionverify)) {
|
||||
throw new \moodle_exception('installsessionerror', 'admin', "index.php?sessionstarted=1&lang=$CFG->lang");
|
||||
}
|
||||
unset($SESSION->sessionverify);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup SESSION to make sure other code does not complain in the future.
|
||||
unset($SESSION->has_timed_out);
|
||||
unset($SESSION->wantsurl);
|
||||
// Cleanup SESSION to make sure other code does not complain in the future.
|
||||
unset($SESSION->has_timed_out);
|
||||
unset($SESSION->wantsurl);
|
||||
|
||||
// At this stage there can be only one admin unless more were added by install,
|
||||
// Users may change username, so do not rely on that.
|
||||
$adminids = explode(',', $CFG->siteadmins);
|
||||
$adminuser = get_complete_user_data('id', reset($adminids));
|
||||
// at this stage there can be only one admin unless more were added by install - users may change username, so do not rely on that
|
||||
$adminids = explode(',', $CFG->siteadmins);
|
||||
$adminuser = get_complete_user_data('id', reset($adminids));
|
||||
|
||||
if ($adminuser->password === 'adminsetuppending') {
|
||||
// Prevent installation hijacking.
|
||||
if ($adminuser->lastip !== getremoteaddr()) {
|
||||
throw new \moodle_exception('installhijacked', 'admin');
|
||||
}
|
||||
// Login user and let him set password and admin details.
|
||||
$adminuser->newadminuser = 1;
|
||||
complete_user_login($adminuser);
|
||||
redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself.
|
||||
|
||||
} else {
|
||||
unset_config('adminsetuppending');
|
||||
if ($adminuser->password === 'adminsetuppending') {
|
||||
// prevent installation hijacking
|
||||
if ($adminuser->lastip !== getremoteaddr()) {
|
||||
throw new \moodle_exception('installhijacked', 'admin');
|
||||
}
|
||||
// login user and let him set password and admin details
|
||||
$adminuser->newadminuser = 1;
|
||||
complete_user_login($adminuser);
|
||||
redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself
|
||||
|
||||
} else {
|
||||
// Just make sure upgrade logging is properly terminated.
|
||||
upgrade_finished('upgradesettings.php');
|
||||
unset_config('adminsetuppending');
|
||||
}
|
||||
|
||||
} else {
|
||||
// just make sure upgrade logging is properly terminated
|
||||
upgrade_finished('upgradesettings.php');
|
||||
}
|
||||
|
||||
if (has_capability('moodle/site:config', context_system::instance())) {
|
||||
@@ -818,7 +811,7 @@ $context = context_system::instance();
|
||||
|
||||
if (!has_capability('moodle/site:config', $context)) {
|
||||
// Do not throw exception display an empty page with administration menu if visible for current user.
|
||||
$PAGE->set_title(get_string('home'));
|
||||
$PAGE->set_title($SITE->fullname);
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
+8
-4
@@ -96,16 +96,20 @@ function core_admin_pluginfile($course, $cm, $context, $filearea, $args, $forced
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
// Check whether width/height are specified, and we can resize the image (some types such as ICO cannot be resized).
|
||||
if (($maxwidth === 0 && $maxheight === 0) ||
|
||||
!$filedata = $file->resize_image($maxwidth, $maxheight)) {
|
||||
|
||||
// No need for resizing, but if the file should be cached we save it so we can serve it fast next time.
|
||||
if (empty($maxwidth) && empty($maxheight)) {
|
||||
if ($lifetime) {
|
||||
file_safe_save_content($file->get_content(), $candidate);
|
||||
}
|
||||
send_stored_file($file, $lifetime, 0, false, $options);
|
||||
}
|
||||
|
||||
// Proceed with the resizing.
|
||||
$filedata = $file->resize_image($maxwidth, $maxheight);
|
||||
if (!$filedata) {
|
||||
send_file_not_found();
|
||||
}
|
||||
|
||||
// If we don't want to cached the file, serve now and quit.
|
||||
if (!$lifetime) {
|
||||
send_content_uncached($filedata, $filename);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* Displays the list of found local plugins, their version (if found) and
|
||||
* a link to delete the local plugin.
|
||||
*
|
||||
* @see https://moodledev.io/docs/apis/plugintypes/local
|
||||
* @see http://docs.moodle.org/dev/Local_customisation
|
||||
* @package admin
|
||||
* @copyright 2010 David Mudrak <david.mudrak@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
+29
-22
@@ -23,11 +23,14 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../config.php');
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
define('NO_OUTPUT_BUFFERING', true);
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$plugin = required_param('plugin', PARAM_PLUGIN);
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
$action = required_param('action', PARAM_ALPHANUMEXT);
|
||||
$media = required_param('media', PARAM_PLUGIN);
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
|
||||
$PAGE->set_url('/admin/media.php');
|
||||
$PAGE->set_context(context_system::instance());
|
||||
@@ -35,38 +38,42 @@ $PAGE->set_context(context_system::instance());
|
||||
require_admin();
|
||||
require_sesskey();
|
||||
|
||||
$return = new moodle_url('/admin/settings.php', [
|
||||
'section' => 'managemediaplayers',
|
||||
]);
|
||||
$plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
|
||||
$sortorder = array_values(\core\plugininfo\media::get_enabled_plugins());
|
||||
|
||||
$return = new moodle_url('/admin/settings.php', array('section' => 'managemediaplayers'));
|
||||
|
||||
if (!array_key_exists($media, $plugins)) {
|
||||
redirect($return);
|
||||
}
|
||||
|
||||
$displayname = get_string('pluginname', "media_{$plugin}");
|
||||
switch ($action) {
|
||||
case 'disable':
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('media');
|
||||
if ($class::enable_plugin($plugin, false)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_disabled', 'core_admin', $displayname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
}
|
||||
$class::enable_plugin($media, false);
|
||||
break;
|
||||
|
||||
case 'enable':
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('media');
|
||||
if ($class::enable_plugin($plugin, true)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_enabled', 'core_admin', $displayname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
}
|
||||
$class::enable_plugin($media, true);
|
||||
break;
|
||||
|
||||
case 'up':
|
||||
$class::change_plugin_order($plugin, $class::MOVE_UP);
|
||||
if (($pos = array_search($media, $sortorder)) > 0) {
|
||||
$tmp = $sortorder[$pos - 1];
|
||||
$sortorder[$pos - 1] = $sortorder[$pos];
|
||||
$sortorder[$pos] = $tmp;
|
||||
\core\plugininfo\media::set_enabled_plugins($sortorder);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'down':
|
||||
$class::change_plugin_order($plugin, $class::MOVE_DOWN);
|
||||
if ((($pos = array_search($media, $sortorder)) !== false) && ($pos < count($sortorder) - 1)) {
|
||||
$tmp = $sortorder[$pos + 1];
|
||||
$sortorder[$pos + 1] = $sortorder[$pos];
|
||||
$sortorder[$pos] = $tmp;
|
||||
\core\plugininfo\media::set_enabled_plugins($sortorder);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_ALPHAEXT);
|
||||
$sort = optional_param('sort', 'username', PARAM_ALPHA);
|
||||
$dir = optional_param('dir', 'ASC', PARAM_ALPHA);
|
||||
$page = optional_param('page', 0, PARAM_INT);
|
||||
$perpage = optional_param('perpage', 30, PARAM_INT);
|
||||
@@ -153,15 +153,7 @@ foreach ($columns as $column) {
|
||||
$headings[$column] = "<a href=\"?sort=$column&dir=$columndir&\">".$string[$column]."</a>$columnicon";
|
||||
}
|
||||
$headings['delete'] = '';
|
||||
|
||||
$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);
|
||||
$acl = $DB->get_records('mnet_sso_access_control', null, "$sort $dir", '*'); //, $page * $perpage, $perpage);
|
||||
$aclcount = $DB->count_records('mnet_sso_access_control');
|
||||
|
||||
if (!$acl) {
|
||||
|
||||
@@ -83,6 +83,7 @@ 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();
|
||||
@@ -114,6 +115,7 @@ 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();
|
||||
|
||||
+139
-55
@@ -1,67 +1,151 @@
|
||||
<?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/>.
|
||||
// Allows the admin to manage activity modules
|
||||
|
||||
/**
|
||||
* A page to manage activity modules.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once('../config.php');
|
||||
require_once('../course/lib.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
require_once('../config.php');
|
||||
require_once('../course/lib.php');
|
||||
require_once("{$CFG->libdir}/adminlib.php");
|
||||
require_once("{$CFG->libdir}/tablelib.php");
|
||||
// defines
|
||||
define('MODULE_TABLE','module_administration_table');
|
||||
|
||||
define('MODULE_TABLE', 'module_administration_table');
|
||||
admin_externalpage_setup('managemodules');
|
||||
|
||||
admin_externalpage_setup('managemodules');
|
||||
$show = optional_param('show', '', PARAM_PLUGIN);
|
||||
$hide = optional_param('hide', '', PARAM_PLUGIN);
|
||||
|
||||
$plugin = optional_param('plugin', '', PARAM_PLUGIN);
|
||||
$action = optional_param('action', '', PARAM_ALPHA);
|
||||
|
||||
// If data submitted, then process and store.
|
||||
if (!empty($action) && !empty($plugin) && confirm_sesskey()) {
|
||||
$manager = \core_plugin_manager::resolve_plugininfo_class('mod');
|
||||
$pluginname = get_string('pluginname', $plugin);
|
||||
/// Print headings
|
||||
|
||||
if ($action === 'disable' && $manager::enable_plugin($plugin, 0)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_disabled', 'core_admin', $pluginname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
} else if ($action === 'enable' && $manager::enable_plugin($plugin, 1)) {
|
||||
\core\notification::add(
|
||||
get_string('plugin_enabled', 'core_admin', $pluginname),
|
||||
\core\notification::SUCCESS
|
||||
);
|
||||
$stractivities = get_string("activities");
|
||||
$struninstall = get_string('uninstallplugin', 'core_admin');
|
||||
$strversion = get_string("version");
|
||||
$strhide = get_string("hide");
|
||||
$strshow = get_string("show");
|
||||
$strsettings = get_string("settings");
|
||||
$stractivities = get_string("activities");
|
||||
$stractivitymodule = get_string("activitymodule");
|
||||
$strshowmodulecourse = get_string('showmodulecourse');
|
||||
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
/// If data submitted, then process and store.
|
||||
|
||||
if (!empty($hide) and confirm_sesskey()) {
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
|
||||
$class::enable_plugin($hide, false);
|
||||
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
redirect(new moodle_url('/admin/modules.php'));
|
||||
}
|
||||
|
||||
// Redirect back to the modules page with out any params.
|
||||
redirect(new moodle_url('/admin/modules.php'));
|
||||
}
|
||||
if (!empty($show) and confirm_sesskey()) {
|
||||
$canenablemodule = true;
|
||||
$modulename = $show;
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string("activities"));
|
||||
$table = new \core_admin\table\activity_management_table();
|
||||
$table->out();
|
||||
echo $OUTPUT->footer();
|
||||
// Invoking a callback function that enables plugins to force additional actions (e.g. displaying notifications,
|
||||
// modals, etc.) and also specify through its returned value (bool) whether the process of enabling the plugin
|
||||
// should continue after these actions or not.
|
||||
if (component_callback_exists("mod_{$modulename}", 'pre_enable_plugin_actions')) {
|
||||
$canenablemodule = component_callback("mod_{$modulename}", 'pre_enable_plugin_actions');
|
||||
}
|
||||
|
||||
if ($canenablemodule) {
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
|
||||
$class::enable_plugin($show, true);
|
||||
admin_get_root(true, false); // Settings not required - only pages.
|
||||
redirect(new moodle_url('/admin/modules.php'));
|
||||
}
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($stractivities);
|
||||
|
||||
/// Get and sort the existing modules
|
||||
|
||||
if (!$modules = $DB->get_records('modules', array(), 'name ASC')) {
|
||||
throw new \moodle_exception('moduledoesnotexist', 'error');
|
||||
}
|
||||
|
||||
/// Print the table of all modules
|
||||
// construct the flexible table ready to display
|
||||
$table = new flexible_table(MODULE_TABLE);
|
||||
$table->define_columns(array('name', 'instances', 'version', 'hideshow', 'uninstall', 'settings'));
|
||||
$table->define_headers(array($stractivitymodule, $stractivities, $strversion, "$strhide/$strshow", $strsettings, $struninstall));
|
||||
$table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/modules.php');
|
||||
$table->set_attribute('id', 'modules');
|
||||
$table->set_attribute('class', 'admintable generaltable');
|
||||
$table->setup();
|
||||
|
||||
$pluginmanager = core_plugin_manager::instance();
|
||||
|
||||
foreach ($modules as $module) {
|
||||
$plugininfo = $pluginmanager->get_plugin_info('mod_'.$module->name);
|
||||
$status = $plugininfo->get_status();
|
||||
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$strmodulename = '<span class="notifyproblem">'.$module->name.' ('.get_string('missingfromdisk').')</span>';
|
||||
$missing = true;
|
||||
} else {
|
||||
// took out hspace="\10\", because it does not validate. don't know what to replace with.
|
||||
$icon = "<img src=\"" . $OUTPUT->image_url('monologo', $module->name) . "\" class=\"icon\" alt=\"\" />";
|
||||
$strmodulename = $icon.' '.get_string('modulename', $module->name);
|
||||
$missing = false;
|
||||
}
|
||||
|
||||
$uninstall = '';
|
||||
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('mod_'.$module->name, 'manage')) {
|
||||
$uninstall = html_writer::link($uninstallurl, $struninstall);
|
||||
}
|
||||
|
||||
if (file_exists("$CFG->dirroot/mod/$module->name/settings.php") ||
|
||||
file_exists("$CFG->dirroot/mod/$module->name/settingstree.php")) {
|
||||
$settings = "<a href=\"settings.php?section=modsetting$module->name\">$strsettings</a>";
|
||||
} else {
|
||||
$settings = "";
|
||||
}
|
||||
|
||||
try {
|
||||
$count = $DB->count_records_select($module->name, "course<>0");
|
||||
} catch (dml_exception $e) {
|
||||
$count = -1;
|
||||
}
|
||||
if ($count>0) {
|
||||
$countlink = $OUTPUT->action_link(new moodle_url('/course/search.php', ['modulelist' => $module->name]),
|
||||
$count, null, ['title' => $strshowmodulecourse]);
|
||||
} else if ($count < 0) {
|
||||
$countlink = get_string('error');
|
||||
} else {
|
||||
$countlink = "$count";
|
||||
}
|
||||
|
||||
if ($missing) {
|
||||
$visible = '';
|
||||
$class = '';
|
||||
} else if ($module->visible) {
|
||||
$visible = "<a href=\"modules.php?hide=$module->name&sesskey=".sesskey()."\" title=\"$strhide\">".
|
||||
$OUTPUT->pix_icon('t/hide', $strhide) . '</a>';
|
||||
$class = '';
|
||||
} else {
|
||||
$visible = "<a href=\"modules.php?show=$module->name&sesskey=".sesskey()."\" title=\"$strshow\">".
|
||||
$OUTPUT->pix_icon('t/show', $strshow) . '</a>';
|
||||
$class = 'dimmed_text';
|
||||
}
|
||||
if ($module->name == "forum") {
|
||||
$uninstall = "";
|
||||
$visible = "";
|
||||
$class = "";
|
||||
}
|
||||
$version = get_config('mod_'.$module->name, 'version');
|
||||
|
||||
$table->add_data(array(
|
||||
$strmodulename,
|
||||
$countlink,
|
||||
$version,
|
||||
$visible,
|
||||
$settings,
|
||||
$uninstall,
|
||||
), $class);
|
||||
}
|
||||
|
||||
$table->print_html();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* MoodleNet callback.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core\moodlenet\moodlenet_client;
|
||||
use core\oauth2\api;
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_login();
|
||||
|
||||
// Parameters.
|
||||
$issuerid = required_param('issuerid', PARAM_INT);
|
||||
$error = optional_param('error', '', PARAM_RAW);
|
||||
$message = optional_param('error_description', null, PARAM_RAW);
|
||||
|
||||
// Headers to make it not cacheable.
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
|
||||
|
||||
$PAGE->set_context(context_system::instance());
|
||||
$PAGE->set_url('/admin/moodlenet_oauth2_callback.php');
|
||||
$PAGE->set_pagelayout('popup');
|
||||
|
||||
// Wait as long as it takes for this script to finish.
|
||||
core_php_time_limit::raise();
|
||||
|
||||
$issuer = api::get_issuer($issuerid);
|
||||
$returnurl = new moodle_url('/admin/moodlenet_oauth2_callback.php');
|
||||
$returnurl->param('issuerid', $issuerid);
|
||||
$returnurl->param('callback', 'yes');
|
||||
$returnurl->param('sesskey', sesskey());
|
||||
$oauthclient = api::get_user_oauth_client($issuer, $returnurl, moodlenet_client::API_SCOPE_CREATE_RESOURCE, true);
|
||||
$oauthclient->is_logged_in(); // Will upgrade the auth code to a token.
|
||||
|
||||
echo $OUTPUT->header();
|
||||
$PAGE->requires->js_call_amd('core/moodlenet/oauth2callback', 'init', [$error, $message]);
|
||||
echo $OUTPUT->footer();
|
||||
+12
-23
@@ -30,36 +30,25 @@
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
|
||||
// The state parameter we've given (used in moodle as a redirect url).
|
||||
// Per https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1, state is required, even during error responses.
|
||||
$state = required_param('state', PARAM_LOCALURL);
|
||||
$redirecturl = new moodle_url($state);
|
||||
$params = $redirecturl->params();
|
||||
|
||||
$error = optional_param('error', '', PARAM_RAW);
|
||||
|
||||
if ($error) {
|
||||
$message = optional_param('error_description', null, PARAM_RAW);
|
||||
|
||||
// Errors can occur for authenticated users, such as when a user denies authorization for some internal service call.
|
||||
// In such cases, propagate the error to the component redirect URI.
|
||||
if (isloggedin()) {
|
||||
if (isset($params['sesskey']) && confirm_sesskey($params['sesskey'])) {
|
||||
$redirecturl->param('error', $error);
|
||||
if ($message) {
|
||||
$redirecturl->param('error_description', $message);
|
||||
}
|
||||
redirect($redirecturl);
|
||||
}
|
||||
$message = optional_param('error_description', '', PARAM_RAW);
|
||||
if ($message) {
|
||||
$SESSION->loginerrormsg = $message;
|
||||
redirect(new moodle_url(get_login_url()));
|
||||
} else {
|
||||
$SESSION->loginerrormsg = $error;
|
||||
redirect(new moodle_url(get_login_url()));
|
||||
}
|
||||
|
||||
// Not logged in or the sesskey verification failed, redirect to login + show errors.
|
||||
$SESSION->loginerrormsg = $message ?? $error;
|
||||
redirect(new moodle_url(get_login_url()));
|
||||
}
|
||||
|
||||
// The authorization code generated by the authorization server.
|
||||
$code = required_param('code', PARAM_RAW);
|
||||
// The state parameter we've given (used in moodle as a redirect url).
|
||||
$state = required_param('state', PARAM_LOCALURL);
|
||||
|
||||
$redirecturl = new moodle_url($state);
|
||||
$params = $redirecturl->params();
|
||||
|
||||
if (isset($params['sesskey']) and confirm_sesskey($params['sesskey'])) {
|
||||
$redirecturl->param('oauth2code', $code);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* Displays the list of found plagiarism plugins, their version (if found) and
|
||||
* a link to uninstall the plagiarism plugin.
|
||||
*
|
||||
* @see https://moodledev.io/docs/apis/subsystems/plagiarism
|
||||
* @see http://docs.moodle.org/dev/Plagiarism_API
|
||||
* @package admin
|
||||
* @copyright 2012 Dan Marsden <dan@danmarsden.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
|
||||
@@ -190,8 +190,8 @@ class helper {
|
||||
static::add_item($presetid, 'showdataretentionsummary', '0', 'tool_dataprivacy');
|
||||
static::add_item($presetid, 'forum_maxattachments', '3');
|
||||
static::add_item($presetid, 'guestloginbutton', '0');
|
||||
// Set Activity chooser tabs to "Starred, Recommended, All".
|
||||
static::add_item($presetid, 'activitychoosertabmode', '4');
|
||||
// Set Activity chooser tabs to "Starred, All, Recommended".
|
||||
static::add_item($presetid, 'activitychoosertabmode', '1');
|
||||
|
||||
// Modules: Hide chat, database, external tool (lti), IMS content package (imscp), lesson, SCORM, survey, wiki, workshop.
|
||||
static::add_plugin($presetid, 'mod', 'chat', false);
|
||||
@@ -278,6 +278,9 @@ class helper {
|
||||
static::add_plugin($presetid, 'repository', 'url', false);
|
||||
static::add_plugin($presetid, 'repository', 'wikimedia', false);
|
||||
|
||||
// Text editors: Disable TinyMCE HTML editor.
|
||||
static::add_plugin($presetid, 'editor', 'tinymce', false);
|
||||
|
||||
// Create the "Full" site admin preset.
|
||||
$data = [
|
||||
'name' => get_string('fullpreset', 'core_adminpresets'),
|
||||
@@ -298,15 +301,17 @@ class helper {
|
||||
static::add_item($presetid, 'showdataretentionsummary', '1', 'tool_dataprivacy');
|
||||
static::add_item($presetid, 'forum_maxattachments', '9');
|
||||
static::add_item($presetid, 'guestloginbutton', '1');
|
||||
// Set Activity chooser tabs to the default value ("Starred, Recommended, All, Activities, Resources").
|
||||
static::add_item($presetid, 'activitychoosertabmode', '3');
|
||||
// Set Activity chooser tabs to the default value ("Starred, All, Activities, Resources, Recommended").
|
||||
static::add_item($presetid, 'activitychoosertabmode', '0');
|
||||
|
||||
// Modules: Enable database, external tool (lti), IMS content package (imscp), lesson, SCORM, wiki, workshop.
|
||||
// Modules: Enable chat, database, external tool (lti), IMS content package (imscp), lesson, SCORM, survey, wiki, workshop.
|
||||
static::add_plugin($presetid, 'mod', 'chat', true);
|
||||
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);
|
||||
|
||||
@@ -378,5 +383,8 @@ class helper {
|
||||
static::add_plugin($presetid, 'repository', 'local', true);
|
||||
static::add_plugin($presetid, 'repository', 'url', true);
|
||||
static::add_plugin($presetid, 'repository', 'wikimedia', true);
|
||||
|
||||
// Text editors: Enable TinyMCE HTML editor.
|
||||
static::add_plugin($presetid, 'editor', 'tinymce', true);
|
||||
}
|
||||
}
|
||||
|
||||
+29
-4
@@ -26,8 +26,34 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configmultiselect extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_configmultiselect $settingdata */
|
||||
protected $settingdata;
|
||||
/**
|
||||
* Ensure that the $value values are setting choices.
|
||||
*
|
||||
* @param mixed $value Setting value
|
||||
* @return mixed Returns false if wrong param value
|
||||
*/
|
||||
protected function set_value($value) {
|
||||
if ($value) {
|
||||
$options = explode(',', $value);
|
||||
foreach ($options as $option) {
|
||||
|
||||
foreach ($this->settingdata->choices as $key => $choice) {
|
||||
|
||||
if ($key == $option) {
|
||||
$this->value = $option;
|
||||
$this->set_visiblevalue();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = implode(',', $options);
|
||||
}
|
||||
$this->value = $value;
|
||||
$this->set_visiblevalue();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function set_visiblevalue() {
|
||||
$values = explode(',', $this->value);
|
||||
@@ -35,8 +61,7 @@ class adminpresets_admin_setting_configmultiselect extends adminpresets_setting
|
||||
|
||||
foreach ($values as $value) {
|
||||
|
||||
// Ensure that each value exists as a setting choice.
|
||||
if (array_key_exists($value, $this->settingdata->choices)) {
|
||||
if (!empty($this->settingdata->choices[$value])) {
|
||||
$visiblevalues[] = $this->settingdata->choices[$value];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,9 +26,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configselect extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_configselect $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
/**
|
||||
* Sets the setting value cleaning it.
|
||||
*
|
||||
@@ -37,7 +34,7 @@ class adminpresets_admin_setting_configselect extends adminpresets_setting {
|
||||
*/
|
||||
protected function set_value($value) {
|
||||
// When we intantiate the class we need the choices.
|
||||
if (empty($this->settingdata->choices) && method_exists($this->settingdata, 'load_choices')) {
|
||||
if (empty($this->settindata->choices) && method_exists($this->settingdata, 'load_choices')) {
|
||||
$this->settingdata->load_choices();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_configtime extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_configtime $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
/**
|
||||
* To check that the value is one of the options
|
||||
*
|
||||
|
||||
@@ -19,8 +19,6 @@ namespace core_adminpresets\local\setting;
|
||||
/**
|
||||
* Reimplementation to allow human friendly view of the selected regexps.
|
||||
*
|
||||
* @deprecated Moodle 4.3 MDL-78468 - No longer used since the devicedetectregex was removed.
|
||||
* @todo Final deprecation on Moodle 4.7 MDL-79052
|
||||
* @package core_adminpresets
|
||||
* @copyright 2021 Pimenko <support@pimenko.com><pimenko.com>
|
||||
* @author Jordan Kesraoui | Sylvain Revenu | Pimenko based on David Monllaó <david.monllao@urv.cat> code
|
||||
@@ -28,16 +26,7 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_devicedetectregex extends adminpresets_admin_setting_configtext {
|
||||
|
||||
/**
|
||||
* @deprecated Moodle 4.3 MDL-78468 - No longer used since the devicedetectregex was removed.
|
||||
* @todo Final deprecation on Moodle 4.7 MDL-79052
|
||||
*/
|
||||
public function set_visiblevalue() {
|
||||
debugging(
|
||||
__FUNCTION__ . '() is deprecated.' .
|
||||
'All functions associated with devicedetectregex theme setting are being removed.',
|
||||
DEBUG_DEVELOPER
|
||||
);
|
||||
$values = json_decode($this->get_value());
|
||||
|
||||
if (!$values) {
|
||||
|
||||
@@ -28,9 +28,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_special_backupdays extends adminpresets_setting {
|
||||
|
||||
/** @var \admin_setting_special_backupdays $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
protected function set_value($value) {
|
||||
$this->value = clean_param($value, PARAM_SEQUENCE);
|
||||
$this->set_visiblevalue();
|
||||
|
||||
-3
@@ -26,9 +26,6 @@ namespace core_adminpresets\local\setting;
|
||||
*/
|
||||
class adminpresets_admin_setting_users_with_capability extends adminpresets_admin_setting_configmultiselect {
|
||||
|
||||
/** @var \admin_setting_configmultiselect $settingdata */
|
||||
protected $settingdata;
|
||||
|
||||
protected function set_behaviors() {
|
||||
$this->behaviors['loadchoices'] = &$this->settingdata;
|
||||
}
|
||||
|
||||
@@ -68,9 +68,6 @@ class adminpresets_setting {
|
||||
*/
|
||||
protected $attributesvalues;
|
||||
|
||||
/** @var array To store the behaviors. */
|
||||
protected array $behaviors = [];
|
||||
|
||||
/**
|
||||
* Stores the setting data and the selected value
|
||||
*
|
||||
@@ -170,7 +167,7 @@ class adminpresets_setting {
|
||||
/**
|
||||
* Saves the setting attributes values
|
||||
*
|
||||
* @return array|false Array of inserted ids (in config_log) or false if nothing was inserted
|
||||
* @return array Array of inserted ids (in config_log)
|
||||
*/
|
||||
public function save_attributes_values() {
|
||||
// Plugin name or null.
|
||||
@@ -209,6 +206,8 @@ class adminpresets_setting {
|
||||
* @param bool $name Setting name to store.
|
||||
* @param mixed $value Setting value to store.
|
||||
* @return int|false config_log inserted id or false whenever the new value is the same as old value.
|
||||
* @throws dml_exception
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public function save_value($name = false, $value = null) {
|
||||
// Object values if no arguments.
|
||||
|
||||
@@ -105,6 +105,7 @@ class manager {
|
||||
'adminpresets_auth_shibboleth_admin_setting_special_idp_configtextarea' => 'adminpresets_admin_setting_configtext',
|
||||
'adminpresets_auth_shibboleth_admin_setting_special_wayf_select' => 'adminpresets_admin_setting_configselect',
|
||||
'adminpresets_editor_atto_toolbar_setting' => 'adminpresets_admin_setting_configtext',
|
||||
'adminpresets_editor_tinymce_json_setting_textarea' => 'adminpresets_admin_setting_configtext',
|
||||
'adminpresets_enrol_database_admin_setting_category' => 'adminpresets_admin_setting_configselect',
|
||||
'adminpresets_enrol_flatfile_role_setting' => 'adminpresets_admin_setting_configtext',
|
||||
'adminpresets_enrol_ldap_admin_setting_category' => 'adminpresets_admin_setting_configselect',
|
||||
@@ -183,8 +184,7 @@ class manager {
|
||||
* @param boolean $sitedbvalues Indicates if $dbsettings comes from the site db or not
|
||||
* @param array $settings Array format $array['plugin']['settingname'] = settings_types child class
|
||||
* @param array|false $children Array of admin_category children or false
|
||||
* @return \core_adminpresets\local\setting\adminpresets_setting[][] Array format
|
||||
* $array['plugin']['settingname'] = adminpresets_setting child class
|
||||
* @return array Array format $array['plugin']['settingname'] = settings_types child class
|
||||
*/
|
||||
public function get_settings(array $dbsettings, bool $sitedbvalues = false, array $settings = [], $children = false): array {
|
||||
global $DB;
|
||||
@@ -309,17 +309,11 @@ class manager {
|
||||
|
||||
$classname = null;
|
||||
|
||||
// Getting the appropriate class to get the correct setting value.
|
||||
// Getting the appropiate class to get the correct setting value.
|
||||
$settingtype = get_class($settingdata);
|
||||
// Check if it is a setting from a plugin.
|
||||
$namespacedata = explode('\\', $settingtype);
|
||||
if (count($namespacedata) > 1) {
|
||||
$plugindata = explode('_', $namespacedata[0]);
|
||||
$settingtype = end($namespacedata);
|
||||
} else {
|
||||
$plugindata = explode('_', $settingtype, 2);
|
||||
}
|
||||
|
||||
// Check if it is a setting from a plugin.
|
||||
$plugindata = explode('_', $settingtype);
|
||||
$types = \core_component::get_plugin_types();
|
||||
if (array_key_exists($plugindata[0], $types)) {
|
||||
$plugins = \core_component::get_plugin_list($plugindata[0]);
|
||||
@@ -761,8 +755,8 @@ class manager {
|
||||
public function delete_preset(int $presetid): void {
|
||||
global $DB;
|
||||
|
||||
// Check the preset exists (cannot delete the pre-installed core "Starter" and "Full" presets).
|
||||
$preset = $DB->get_record('adminpresets', ['id' => $presetid, 'iscore' => self::NONCORE_PRESET]);
|
||||
// Check the preset exists.
|
||||
$preset = $DB->get_record('adminpresets', ['id' => $presetid]);
|
||||
if (!$preset) {
|
||||
throw new moodle_exception('errordeleting', 'core_adminpresets');
|
||||
}
|
||||
|
||||
@@ -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 @@ class provider implements
|
||||
* @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();
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ class provider implements
|
||||
/**
|
||||
* Delete all data for all users in the specified context.
|
||||
*
|
||||
* @param \context $context The specific context to delete data for.
|
||||
* @param context $context The specific context to delete data for.
|
||||
*/
|
||||
public static function delete_data_for_all_users_in_context(\context $context) {
|
||||
// None of the the data from these tables should be deleted.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user