Compare commits

..

14 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) d09dc52b0a Moodle release 3.6.1 2018-12-04 17:42:58 +01:00
Eloy Lafuente (stronk7) 6e19850f6e weekly release 3.6+ 2018-12-04 13:06:09 +01:00
Bas Brands 5d30474242 MDL-63223 theme_boost: flexbox for login pagin footer 2018-12-04 12:06:49 +08:00
Jun Pataleta 1b972c31ac Merge branch 'MDL-64307_36' of git://github.com/markn86/moodle into MOODLE_36_STABLE 2018-12-04 12:03:08 +08:00
Mark Nelson 29b6ac23e9 MDL-64307 core_message: do not include disabled conversations in count 2018-12-04 11:48:54 +08:00
Mark Nelson 44b6ffb68c MDL-64307 core: set all individual conversations to enabled 2018-12-04 11:44:59 +08:00
Jun Pataleta 79abbd9adc Merge branch 'MDL-64206_36' of git://github.com/markn86/moodle into MOODLE_36_STABLE 2018-12-04 11:13:37 +08:00
Tim Hunt 270524858e MDL-64286 qtype_gapselect: removed unneeded line of code
The extended Behat test show the qtype works fine without it.
2018-12-04 11:12:52 +08:00
Damyon Wiese 60f9a401a9 Merge branch 'MDL-64155-master' of git://github.com/vmdef/moodle into MOODLE_36_STABLE 2018-12-03 15:26:56 +08:00
Tim Hunt ac0b8201a9 MDL-63459 qtype_calculatedmulti: fix incorrect hint object type 2018-12-03 14:25:41 +08:00
Tim Hunt be27fc0fe3 MDL-63459 qtype_calculatedmulti: unit test should test this qtype
This also demonstrates the bug to be fixed
2018-12-03 14:25:17 +08:00
Mark Nelson ebd104448f MDL-64206 core: updated FB logo URL 2018-12-03 12:23:47 +08:00
Andrew Nicols c69f425a7a Merge branch 'MDL-64300_36' of git://github.com/stronk7/moodle into MOODLE_36_STABLE 2018-12-03 08:35:32 +08:00
Eloy Lafuente (stronk7) e38e718441 MDL-64300 upgrade: add 3.6.0 separation line to all upgrade scripts 2018-12-02 18:37:59 +01:00
18393 changed files with 755229 additions and 1650744 deletions
+90
View File
@@ -0,0 +1,90 @@
# Generated by "grunt ignorefiles"
*/**/yui/src/*/meta/
*/**/build/
node_modules/
vendor/
admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
admin/tool/usertours/amd/src/tour.js
auth/cas/CAS/
enrol/lti/ims-blti/
filter/algebra/AlgParser.pm
filter/tex/mimetex.*
lib/editor/atto/plugins/html/yui/src/codemirror/
lib/editor/atto/plugins/html/yui/src/beautify/
lib/editor/atto/yui/src/rangy/js/*.*
lib/editor/tinymce/plugins/pdw/tinymce/
lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
lib/mlbackend/php/phpml/
lib/adodb/
lib/bennu/
lib/evalmath/
lib/lessphp/
lib/phpexcel/
lib/google/
lib/htmlpurifier/
lib/jabber/
lib/minify/matthiasmullie-minify/
lib/minify/matthiasmullie-pathconverter/
lib/pear/Auth/RADIUS.php
lib/pear/Crypt/CHAP.php
lib/pear/HTML/Common.php
lib/pear/HTML/QuickForm.php
lib/pear/HTML/QuickForm/
lib/pear/PEAR.php
lib/phpmailer/
lib/simplepie/
lib/tcpdf/
lib/typo3/
lib/yuilib/
lib/yuilib/gallery/
lib/jquery/
lib/html2text/
lib/markdown/
lib/recaptchalib.php
lib/xhprof/
lib/horde/
lib/requirejs/
lib/amd/src/loglevel.js
lib/mustache/
lib/amd/src/mustache.js
lib/graphlib.php
lib/php-css-parser/
lib/rtlcss/
lib/scssphp/
lib/spout/
lib/amd/src/chartjs-lazy.js
lib/maxmind/GeoIp2/
lib/maxmind/MaxMind/
lib/ltiprovider/
lib/amd/src/truncate.js
lib/fonts/
lib/amd/src/adapter.js
lib/validateurlsyntax.php
lib/amd/src/popper.js
lib/geopattern-php/
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/videojs/
media/player/videojs/amd/src/videojs-flash-lazy.js
media/player/videojs/videojs/video-js.swf
mod/assign/feedback/editpdf/fpdi/
repository/s3/S3.php
theme/boost/scss/bootstrap/
theme/boost/amd/src/alert.js
theme/boost/amd/src/button.js
theme/boost/amd/src/carousel.js
theme/boost/amd/src/collapse.js
theme/boost/amd/src/dropdown.js
theme/boost/amd/src/modal.js
theme/boost/amd/src/popover.js
theme/boost/amd/src/scrollspy.js
theme/boost/amd/src/tab.js
theme/boost/amd/src/tooltip.js
theme/boost/amd/src/util.js
theme/boost/amd/src/tether.js
theme/boost/scss/fontawesome/
theme/bootstrapbase/less/bootstrap/
theme/bootstrapbase/javascript/html5shiv.js
theme/bootstrapbase/amd/src/bootstrap.js
theme/bootstrapbase/less/fontawesome/
+4 -102
View File
@@ -1,15 +1,9 @@
{
'plugins': [
'babel',
'promise',
'jsdoc',
],
'env': {
'browser': true,
// Enable ES6+ features by default.
// See http://eslint.org/docs/user-guide/configuring#specifying-environments
// Note: The YUI override must exactly match this when disabling the ES6+ version because those features are not supported by Shifter.
'es2020': true,
'amd': true
},
'globals': {
@@ -87,7 +81,6 @@
'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',
@@ -197,115 +190,24 @@
'property': 'str',
'message': 'Use AMD module "core/str" or M.util.get_string()'
}],
},
overrides: [
{
files: ["**/yui/src/**/*.js"],
'env': {
// Disable ES6+ for YUI files.
'es2020': false,
},
// Disable some rules which we can't safely define for YUI rollups.
rules: {
'no-undef': 'off',
'no-unused-vars': 'off',
'no-unused-expressions': 'off',
// === JSDocs ===
"jsdoc/check-access": 'off',
"jsdoc/check-alignment": 'off',
"jsdoc/check-param-names": 'off',
"jsdoc/check-property-names": 'off',
"jsdoc/empty-tags": 'off',
"jsdoc/implements-on-classes": 'off',
"jsdoc/multiline-blocks": 'off',
"jsdoc/require-jsdoc": 'off',
"jsdoc/require-param": 'off',
"jsdoc/require-param-name": 'off',
"jsdoc/require-param-type": 'off',
"jsdoc/require-property": 'off',
"jsdoc/require-property-name": 'off',
"jsdoc/require-property-type": 'off',
'no-unused-expressions': 'off'
}
},
{
files: ["**/amd/src/*.js", "**/amd/src/**/*.js", "Gruntfile.js", ".grunt/*.js", ".grunt/tasks/*.js", "jsdoc.conf.js"],
// We're using babel transpiling so use their parser
// for linting.
parser: '@babel/eslint-parser',
files: ["**/amd/src/*.js"],
// 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',
// Not using this rule for the time being because it isn't
// compatible with jQuery and ES6.
'no-invalid-this': 'off',
'object-curly-spacing': 'off',
'quotes': 'off',
'semi': 'off',
'no-unused-expressions': 'off',
// Enable all of the babel version of these rules.
'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',
// 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',
],
},
parserOptions: {
'sourceType': 'module',
'requireConfigFile': false,
'no-implicit-globals': 'error'
}
}
]
+3 -7
View File
@@ -3,8 +3,6 @@
"Feature": 0,
"Background": 2,
"Scenario": 2,
"Examples": 4,
"example": 6,
"Step": 4,
"given": 4,
"and": 4
@@ -16,9 +14,7 @@
"no-multiple-empty-lines": "on",
"no-partially-commented-tag-lines": "on",
"no-trailing-spaces": "on",
"no-unnamed-features": "on",
"no-unnamed-scenarios": "on",
"no-scenario-outlines-without-examples": "on",
"no-examples-in-scenarios": "on",
"new-line-at-eof": ["on", "yes"]
"no-unamed-features": "on",
"no-unamed-scenarios": "on",
"no-scenario-outlines-without-examples": "on"
}
+2
View File
@@ -1,3 +1,5 @@
**/yui/build/** -diff
**/amd/build/** -diff
lib/dml/oci_native_moodle_package.sql text eol=lf
theme/bootstrapbase/style/editor.css -diff
theme/bootstrapbase/style/moodle.css -diff
-2
View File
@@ -1,2 +0,0 @@
# Primary donations pages.
custom: ["https://moodle.com/donations/", moodle.org]
-71
View File
@@ -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/>.
/**
* Template configuraton file for github actions CI/CD.
*
* @package core
* @copyright 2020 onwards Eloy Lafuente (stronk7) {@link https://stronk7.com}
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// This cannot be used out from a github actions workflow, so just exit.
getenv('GITHUB_WORKFLOW') || die; // phpcs:ignore moodle.Files.MoodleInternal.MoodleInternalGlobalState
unset($CFG);
global $CFG;
$CFG = new stdClass();
$CFG->dbtype = getenv('dbtype');
$CFG->dblibrary = 'native';
$CFG->dbhost = '127.0.0.1';
$CFG->dbname = 'test';
$CFG->dbuser = 'test';
$CFG->dbpass = 'test';
$CFG->prefix = 'm_';
$CFG->dboptions = ['dbcollation' => 'utf8mb4_bin'];
$host = 'localhost';
$CFG->wwwroot = "http://{$host}";
$CFG->dataroot = realpath(dirname(__DIR__)) . '/moodledata';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
// Debug options - possible to be controlled by flag in future.
$CFG->debug = (E_ALL | E_STRICT); // DEBUG_DEVELOPER.
$CFG->debugdisplay = 1;
$CFG->debugstringids = 1; // Add strings=1 to url to get string ids.
$CFG->perfdebug = 15;
$CFG->debugpageinfo = 1;
$CFG->allowthemechangeonurl = 1;
$CFG->passwordpolicy = 0;
$CFG->cronclionly = 0;
$CFG->pathtophp = getenv('pathtophp');
$CFG->phpunit_dataroot = realpath(dirname(__DIR__)) . '/phpunitdata';
$CFG->phpunit_prefix = 't_';
define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080');
define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080');
define('TEST_SESSION_REDIS_HOST', 'localhost');
define('TEST_CACHESTORE_REDIS_TESTSERVERS', 'localhost');
// TODO: add others (solr, mongodb, memcached, ldap...).
// Too much for now: define('PHPUNIT_LONGTEST', true); // Only leaves a few tests out and they are run later by CI.
require_once(__DIR__ . '/lib/setup.php');
-116
View File
@@ -1,116 +0,0 @@
name: Core
on:
push:
branches-ignore:
- master
- MOODLE_[0-9]+_STABLE
tags-ignore:
- v[0-9]+.[0-9]+.[0-9]+*
env:
php: 8.1
jobs:
Grunt:
runs-on: ubuntu-22.04
steps:
- name: Checking out code
uses: actions/checkout@v3
- name: Configuring node & npm
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
- name: Installing node stuff
run: npm install
- 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 }}
services:
exttests:
image: moodlehq/moodle-exttests
ports:
- 8080:80
redis:
image: redis
ports:
- 6379:6379
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
php: 7.4
extensions:
db: mysqli
- os: ubuntu-22.04
php: 8.1
db: pgsql
steps:
- name: Setting up DB mysql
if: ${{ matrix.db == 'mysqli' }}
uses: moodlehq/mysql-action@v1
with:
collation server: utf8mb4_bin
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: 12
postgresql db: test
postgresql user: test
postgresql password: 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: Checking out code from ${{ env.GITHUB_REF_SLUG }}
uses: actions/checkout@v3
- name: Setting up PHPUnit
env:
dbtype: ${{ matrix.db }}
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
sudo locale-gen en_AU.UTF-8
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
-144
View File
@@ -1,144 +0,0 @@
name: Windows Testing
on:
workflow_dispatch
env:
php: 8.1
jobs:
Grunt:
runs-on: windows-latest
steps:
- name: Set git to use LF
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checking out code
uses: actions/checkout@v3
- name: Configuring node & npm
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
- name: Installing node stuff
run: npm ci
- name: Running grunt
run: npx grunt
- name: Looking for uncommitted changes
# Add all files to the git index and then run diff --cached to see all changes.
# This ensures that we get the status of all files, including new files.
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
run: |
git add .
git reset -- npm-shrinkwrap.json
git diff --cached --exit-code
PHPUnit:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
php: 8.1
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
# this is the place to enable them.
# db: mysqli
db: pgsql
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
- os: windows-latest
php: 8.0
db: pgsql
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
steps:
- name: Setting up DB mysql
if: ${{ matrix.db == 'mysqli' }}
uses: shogo82148/actions-setup-mysql@v1
with:
mysql-version: 8.0
user: test
password: test
- name: Creating DB mysql
if: ${{ matrix.db == 'mysqli' }}
run: mysql --host 127.0.0.1 -utest -ptest -e 'CREATE DATABASE IF NOT EXISTS test COLLATE = utf8mb4_bin;';
- name: Setting up DB pgsql
if: ${{ matrix.db == 'pgsql' }}
run: |
# TODO: Remove these conf. modifications when php74 or php80 are lowest.
# Change to old md5 auth, because php73 does not support it.
# #password_encryption = scram-sha-256
(Get-Content "$env:PGDATA\postgresql.conf"). `
replace('#password_encryption = scram-sha-256', 'password_encryption = md5') | `
Set-Content "$env:PGDATA\postgresql.conf"
(Get-Content "$env:PGDATA\pg_hba.conf"). `
replace('scram-sha-256', 'md5') | `
Set-Content "$env:PGDATA\pg_hba.conf"
$pgService = Get-Service -Name postgresql*
Set-Service -InputObject $pgService -Status running -StartupType automatic
Start-Process -FilePath "$env:PGBIN\pg_isready" -Wait -PassThru
& $env:PGBIN\psql --command="CREATE USER test PASSWORD 'test'" --command="\du"
- name: Creating DB pgsql
if: ${{ matrix.db == 'pgsql' }}
run: |
& $env:PGBIN\createdb --owner=test test
$env:PGPASSWORD = 'test'
& $env:PGBIN\psql --username=test --host=localhost --list test
- name: Configuring git vars
uses: rlespinasse/github-slug-action@v4
- name: Setting up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: ${{ matrix.extensions }}
ini-values: max_input_vars=5000
coverage: none
- name: Set git to use LF
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
uses: actions/checkout@v3
# Needs to be done after php is available, git configured and Moodle checkout has happened.
- name: Setting up moodle-exttests service
run: |
git clone https://github.com/moodlehq/moodle-exttests.git
nssm install php-built-in C:\tools\php\php.exe -S localhost:8080 -t D:\a\moodle\moodle\moodle-exttests
nssm start php-built-in
- name: Setting up redis service
run: |
choco install redis-64 --version 3.0.503 --no-progress
nssm install redis redis-server
nssm start redis
- name: Setting up PHPUnit
env:
dbtype: ${{ matrix.db }}
shell: bash
run: |
echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
cp .github/workflows/config-template.php config.php
mkdir ../moodledata
php admin/tool/phpunit/cli/init.php --no-composer-self-update
- name: Running PHPUnit tests
env:
dbtype: ${{ matrix.db }}
phpunit_options: ${{ secrets.phpunit_options }}
run: vendor/bin/phpunit $phpunit_options
+2 -22
View File
@@ -9,24 +9,15 @@
#
# See gitignore(5) man page for more details
#
# Swap files (vim)
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Temporary files including undo
*~
#
/config.php
/lib/editor/tinymce/extra/tools/temp/
*~
*.swp
/tags
/TAGS
/cscope.*
/.patches/
/.idea/
.phpstorm.*
/nbproject/
CVS
.DS_Store
@@ -34,7 +25,6 @@ CVS
/.project
/.buildpath
/.cache
.phpunit.result.cache
phpunit.xml
# Composer support. Do not ignore composer.json, or composer.lock. These should be shipped by us.
composer.phar
@@ -46,13 +36,3 @@ composer.phar
/lib/yuilib/*/*/*-coverage.js
atlassian-ide-plugin.xml
/node_modules/
/.vscode/
moodle-plugin-ci.phar
.eslintignore
.stylelintignore
/jsdoc
/admin/tool/componentlibrary/docs
/admin/tool/componentlibrary/hugo/site/data/my-index.json
.hugo_build.lock
phpcs.xml
jsconfig.json
-169
View File
@@ -1,169 +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/>.
/**
* This is a babel plugin to add the Moodle module names to the AMD modules
* as part of the transpiling process.
*
* In addition it will also add a return statement for the default export if the
* module is using default exports. This is a highly specific Moodle thing because
* we're transpiling to AMD and none of the existing Babel 7 plugins work correctly.
*
* This will fix the issue where an ES6 module using "export default Foo" will be
* transpiled into an AMD module that returns {default: Foo}; Instead it will now
* just simply return Foo.
*
* Note: This means all other named exports in that module are ignored and won't be
* exported.
*
* @copyright 2018 Ryan Wyllie <ryan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
"use strict";
/* eslint-env node */
module.exports = ({template, types}) => {
const fs = require('fs');
const path = require('path');
const cwd = process.cwd();
const ComponentList = require(path.join(process.cwd(), '.grunt', 'components.js'));
/**
* Search the list of components that match the given file name
* and return the Moodle component for that file, if found.
*
* Throw an exception if no matching component is found.
*
* @throws {Error}
* @param {string} searchFileName The file name to look for.
* @return {string} Moodle component
*/
function getModuleNameFromFileName(searchFileName) {
searchFileName = fs.realpathSync(searchFileName);
const relativeFileName = searchFileName.replace(`${cwd}${path.sep}`, '').replace(/\\/g, '/');
const [componentPath, file] = relativeFileName.split('/amd/src/');
const fileName = file.replace('.js', '');
// Check subsystems first which require an exact match.
const componentName = ComponentList.getComponentFromPath(componentPath);
if (componentName) {
return `${componentName}/${fileName}`;
}
// This matches the previous PHP behaviour that would throw an exception
// if it couldn't parse an AMD file.
throw new Error(`Unable to find module name for ${searchFileName} (${componentPath}::${file}}`);
}
/**
* This is heavily inspired by the babel-plugin-add-module-exports plugin.
* See: https://github.com/59naga/babel-plugin-add-module-exports
*
* This is used when we detect a module using "export default Foo;" to make
* sure the transpiled code just returns Foo directly rather than an object
* with the default property (i.e. {default: Foo}).
*
* Note: This means that we can't support modules that combine named exports
* with a default export.
*
* @param {String} path
* @param {String} exportObjectName
*/
function addModuleExportsDefaults(path, exportObjectName) {
const rootPath = path.findParent(path => {
return path.key === 'body' || !path.parentPath;
});
// HACK: `path.node.body.push` instead of path.pushContainer(due doesn't work in Plugin.post).
// This is hardcoded to work specifically with AMD.
rootPath.node.body.push(template(`return ${exportObjectName}.default`)());
}
return {
pre() {
this.seenDefine = false;
this.addedReturnForDefaultExport = false;
},
visitor: {
// Plugin ordering is only respected if we visit the "Program" node.
// See: https://babeljs.io/docs/en/plugins.html#plugin-preset-ordering
//
// We require this to run after the other AMD module transformation so
// let's visit the "Program" node.
Program: {
exit(path) {
path.traverse({
CallExpression(path) {
// If we find a "define" function call.
if (!this.seenDefine && path.get('callee').isIdentifier({name: 'define'})) {
// We only want to modify the first instance of define that we find.
this.seenDefine = true;
// Get the Moodle component for the file being processed.
var moduleName = getModuleNameFromFileName(this.file.opts.filename);
// The function signature of `define()` is:
// define = function (name, deps, callback) {...}
// Ensure that if the moduel supplied its own name that it is replaced.
if (path.node.arguments.length > 0) {
// Ensure that there is only one name.
if (path.node.arguments[0].type === 'StringLiteral') {
// eslint-disable-next-line
console.log(`Replacing module name '${path.node.arguments[0].extra.rawValue}' with ${moduleName}`);
path.node.arguments.shift();
}
}
// Add the module name as the first argument to the define function.
path.node.arguments.unshift(types.stringLiteral(moduleName));
// Add a space after the define function in the built file so that previous versions
// of Moodle will not try to add the module name to the file when it's being served
// by PHP. This forces the regex in PHP to not match for this file.
path.node.callee.name = 'define ';
}
// Check for any Object.defineProperty('exports', 'default') calls.
if (!this.addedReturnForDefaultExport && path.get('callee').matchesPattern('Object.defineProperty')) {
const [identifier, prop] = path.get('arguments');
const objectName = identifier.get('name').node;
const propertyName = prop.get('value').node;
if ((objectName === 'exports' || objectName === '_exports') && propertyName === 'default') {
addModuleExportsDefaults(path, objectName);
this.addedReturnForDefaultExport = true;
}
}
},
AssignmentExpression(path) {
// Check for an exports.default assignments.
if (
!this.addedReturnForDefaultExport &&
(
path.get('left').matchesPattern('exports.default') ||
path.get('left').matchesPattern('_exports.default')
)
) {
const objectName = path.get('left.object.name').node;
addModuleExportsDefaults(path, objectName);
this.addedReturnForDefaultExport = true;
}
}
}, this);
}
}
}
};
};
-244
View File
@@ -1,244 +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/>.
/**
* Helper functions for working with Moodle component names, directories, and sources.
*
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
"use strict";
/* eslint-env node */
/** @var {Object} A list of subsystems in Moodle */
const componentData = {};
/**
* Load details of all moodle modules.
*
* @returns {object}
*/
const fetchComponentData = () => {
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const gruntFilePath = process.cwd();
if (!Object.entries(componentData).length) {
componentData.subsystems = {};
componentData.pathList = [];
// Fetch the component definiitions from the distributed JSON file.
const components = JSON.parse(fs.readFileSync(`${gruntFilePath}/lib/components.json`));
// Build the list of moodle subsystems.
componentData.subsystems.lib = 'core';
componentData.pathList.push(process.cwd() + path.sep + 'lib');
for (const [component, thisPath] of Object.entries(components.subsystems)) {
if (thisPath) {
// Prefix "core_" to the front of the subsystems.
componentData.subsystems[thisPath] = `core_${component}`;
componentData.pathList.push(process.cwd() + path.sep + thisPath);
}
}
// The list of components incldues the list of subsystems.
componentData.components = componentData.subsystems;
// Go through each of the plugintypes.
Object.entries(components.plugintypes).forEach(([pluginType, pluginTypePath]) => {
// We don't allow any code in this place..?
glob.sync(`${pluginTypePath}/*/version.php`).forEach(versionPath => {
const componentPath = fs.realpathSync(path.dirname(versionPath));
const componentName = path.basename(componentPath);
const frankenstyleName = `${pluginType}_${componentName}`;
componentData.components[`${pluginTypePath}/${componentName}`] = frankenstyleName;
componentData.pathList.push(componentPath);
// Look for any subplugins.
const subPluginConfigurationFile = `${componentPath}/db/subplugins.json`;
if (fs.existsSync(subPluginConfigurationFile)) {
const subpluginList = JSON.parse(fs.readFileSync(fs.realpathSync(subPluginConfigurationFile)));
Object.entries(subpluginList.plugintypes).forEach(([subpluginType, subpluginTypePath]) => {
glob.sync(`${subpluginTypePath}/*/version.php`).forEach(versionPath => {
const componentPath = fs.realpathSync(path.dirname(versionPath));
const componentName = path.basename(componentPath);
const frankenstyleName = `${subpluginType}_${componentName}`;
componentData.components[`${subpluginTypePath}/${componentName}`] = frankenstyleName;
componentData.pathList.push(componentPath);
});
});
}
});
});
}
return componentData;
};
/**
* Get the list of component paths.
*
* @param {string} relativeTo
* @returns {array}
*/
const getComponentPaths = (relativeTo = '') => fetchComponentData().pathList.map(componentPath => {
return componentPath.replace(relativeTo, '');
});
/**
* Get the list of paths to build AMD sources.
*
* @returns {Array}
*/
const getAmdSrcGlobList = () => {
const globList = [];
fetchComponentData().pathList.forEach(componentPath => {
globList.push(`${componentPath}/amd/src/*.js`);
globList.push(`${componentPath}/amd/src/**/*.js`);
});
return globList;
};
/**
* Get the list of paths to build YUI sources.
*
* @param {String} relativeTo
* @returns {Array}
*/
const getYuiSrcGlobList = relativeTo => {
const globList = [];
fetchComponentData().pathList.forEach(componentPath => {
const relativeComponentPath = componentPath.replace(relativeTo, '');
globList.push(`${relativeComponentPath}/yui/src/**/*.js`);
});
return globList;
};
/**
* Get the list of paths to thirdpartylibs.xml.
*
* @param {String} relativeTo
* @returns {Array}
*/
const getThirdPartyLibsList = relativeTo => {
const fs = require('fs');
const path = require('path');
return fetchComponentData().pathList
.map(componentPath => path.relative(relativeTo, componentPath) + '/thirdpartylibs.xml')
.map(componentPath => componentPath.replace(/\\/g, '/'))
.filter(path => fs.existsSync(path))
.sort();
};
/**
* Get the list of thirdparty library paths.
*
* @returns {array}
*/
const getThirdPartyPaths = () => {
const DOMParser = require('@xmldom/xmldom').DOMParser;
const fs = require('fs');
const path = require('path');
const xpath = require('xpath');
const thirdpartyfiles = getThirdPartyLibsList(fs.realpathSync('./'));
const libs = ['node_modules/', 'vendor/'];
const addLibToList = lib => {
if (!lib.match('\\*') && fs.statSync(lib).isDirectory()) {
// Ensure trailing slash on dirs.
lib = lib.replace(/\/?$/, '/');
}
// Look for duplicate paths before adding to array.
if (libs.indexOf(lib) === -1) {
libs.push(lib);
}
};
thirdpartyfiles.forEach(function(file) {
const dirname = path.dirname(file);
const xmlContent = fs.readFileSync(file, 'utf8');
const doc = new DOMParser().parseFromString(xmlContent);
const nodes = xpath.select("/libraries/library/location/text()", doc);
nodes.forEach(function(node) {
let lib = path.posix.join(dirname, node.toString());
addLibToList(lib);
});
});
return libs;
};
/**
* Find the name of the component matching the specified path.
*
* @param {String} path
* @returns {String|null} Name of matching component.
*/
const getComponentFromPath = path => {
const componentList = fetchComponentData().components;
if (componentList.hasOwnProperty(path)) {
return componentList[path];
}
return null;
};
/**
* Check whether the supplied path, relative to the Gruntfile.js, is in a known component.
*
* @param {String} checkPath The path to check. This can be with either Windows, or Linux directory separators.
* @returns {String|null}
*/
const getOwningComponentDirectory = checkPath => {
const path = require('path');
// Fetch all components into a reverse sorted array.
// This ensures that components which are within the directory of another component match first.
const pathList = Object.keys(fetchComponentData().components).sort().reverse();
for (const componentPath of pathList) {
// If the componentPath is the directory being checked, it will be empty.
// If the componentPath is a parent of the directory being checked, the relative directory will not start with ..
if (!path.relative(componentPath, checkPath).startsWith('..')) {
return componentPath;
}
}
return null;
};
module.exports = {
fetchComponentData,
getAmdSrcGlobList,
getComponentFromPath,
getComponentPaths,
getOwningComponentDirectory,
getYuiSrcGlobList,
getThirdPartyLibsList,
getThirdPartyPaths,
};
-19
View File
@@ -1,19 +0,0 @@
# Moodle JavaScript Documentation
```
.-..-.
_____ | || |
/____/-.---_ .---. .---. .-.| || | .---.
| | _ _ |/ _ \/ _ \/ _ || |/ __ \
* | | | | | || |_| || |_| || |_| || || |___/
|_| |_| |_|\_____/\_____/\_____||_|\_____)
Moodle - the world's open source learning platform
```
## About
This generated documentation includes API documentation for JavaScript written in the AMD and ES2015 module formats within Moodle.
## Related information
See [https://docs.moodle.org/dev](https://docs.moodle.org/dev) for other related Developer Documentation.
-131
View File
@@ -1,131 +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/>.
/**
* Helper functions for working with Moodle component names, directories, and sources.
*
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
"use strict";
/* eslint-env node */
// Do not include any plugins as stanard.
const plugins = [];
plugins.push('plugins/markdown');
/**
* Get the source configuration.
*
* @return {Object}
*/
const getSource = () => {
const glob = require('glob');
const path = require('path');
const ComponentList = require(path.resolve('.grunt/components.js'));
const thirdPartyPaths = ComponentList.getThirdPartyPaths();
const source = {
include: [],
includePattern: ".+\\.js$",
};
let includeList = [];
ComponentList.getAmdSrcGlobList().forEach(async pattern => {
includeList.push(...glob.sync(pattern));
});
const cwdLength = process.cwd().length + 1;
includeList.forEach(path => {
if (source.include.indexOf(path) !== -1) {
// Ensure no duplicates.
return;
}
const relPath = path.substring(cwdLength);
if (thirdPartyPaths.indexOf(relPath) !== -1) {
return;
}
source.include.push(path);
});
source.include.push('.grunt/jsdoc/README.md');
return source;
};
const tags = {
// Allow the use of unknown tags.
// We have a lot of legacy uses of these.
allowUnknownTags: true,
// We make use of jsdoc and closure dictionaries as standard.
dictionaries: [
'jsdoc',
'closure',
],
};
// Template configuraiton.
const templates = {
cleverLinks: false,
monospaceLinks: false,
};
module.exports = {
opts: {
destination: "./jsdoc/",
template: "node_modules/docdash",
},
plugins,
recurseDepth: 10,
source: getSource(),
sourceType: 'module',
tags,
templates,
docdash: {
collapse: true,
search: true,
sort: true,
sectionOrder: [
"Namespaces",
"Modules",
"Events",
"Classes",
"Externals",
"Mixins",
"Tutorials",
"Interfaces"
],
"menu": {
"Developer Docs": {
href: "https://docs.moodle.org/dev",
target: "_blank",
"class": "menu-item",
id: "devdocs"
},
"MDN Docs": {
href: "https://developer.mozilla.org/en-US/docs/Web/JavaScript",
target: "_blank",
"class": "menu-item",
id: "mdndocs",
},
},
typedefs: true,
},
};
-142
View File
@@ -1,142 +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 */
/**
* Component Library build tasks.
*
* @copyright 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
/**
* Get a child path of the component library.
*
* @param {string} path
* @returns {string}
*/
const getCLPath = path => `admin/tool/componentlibrary/${path}`;
/**
* Get a spawn handler.
*
* This is a generic function to write the spawn output, and then to exit if required and mark the async task as
* complete.
*
* @param {Promise} done
* @returns {function}
*/
const getSpawnHandler = done => (error, result, code) => {
grunt.log.write(result);
if (error) {
grunt.log.error(result.stdout);
process.exit(code);
}
done();
};
/**
* Spawn a function against Node with the provided args.
*
* @param {array} args
* @returns {object}
*/
const spawnNodeCall = (args) => grunt.util.spawn({
cmd: 'node',
args,
}, getSpawnHandler(grunt.task.current.async()));
/**
* Build the docs using Hugo.
*
* @returns {Object} Reference to the spawned task
*/
const docsBuild = () => spawnNodeCall([
'node_modules/hugo-bin/cli.js',
'--config', getCLPath('config.yml'),
'--cleanDestinationDir',
]);
/**
* Build the docs index using the hugo-lunr-indexer.
*
* @returns {Object} Reference to the spawned task
*/
const indexBuild = () => spawnNodeCall([
'node_modules/hugo-lunr-indexer/bin/hli.js',
'-i', getCLPath('content/**'),
'-o', getCLPath('hugo/site/data/my-index.json'),
'-l', 'yaml',
'-d', '---',
]);
/**
* Build the hugo CSS.
*
* @returns {Object} Reference to the spawned task
*/
const cssBuild = () => spawnNodeCall([
'node_modules/sass/sass.js',
'--style', 'expanded',
'--source-map',
'--embed-sources',
'--precision', 6,
'--load-path', process.cwd(),
getCLPath('hugo/scss/docs.scss'),
getCLPath('hugo/dist/css/docs.css'),
]);
// Register the various component library tasks.
grunt.registerTask('componentlibrary:docsBuild', 'Build the component library', docsBuild);
grunt.registerTask('componentlibrary:cssBuild', 'Build the component library', cssBuild);
grunt.registerTask('componentlibrary:indexBuild', 'Build the component library', indexBuild);
grunt.registerTask('componentlibrary', 'Build the component library', [
'componentlibrary:docsBuild',
'componentlibrary:cssBuild',
'componentlibrary:indexBuild',
]);
grunt.config.merge({
watch: {
componentLibraryDocs: {
files: [
getCLPath('content/**/*.md'),
getCLPath('hugo'),
],
tasks: ['componentlibrary:docsBuild', 'componentlibrary:indexBuild'],
},
componentLibraryCSS: {
files: [
getCLPath('hugo/scss/**/*.scss'),
'hugo',
],
tasks: ['componentlibrary:cssBuild'],
},
},
});
// Add the 'componentlibrary' task as a startup task.
grunt.moodleEnv.startupTasks.push('componentlibrary');
return {
docsBuild,
cssBuild,
indexBuild,
};
};
-64
View File
@@ -1,64 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
const files = grunt.moodleEnv.files;
// Project configuration.
grunt.config.merge({
eslint: {
// Even though warnings dont stop the build we don't display warnings by default because
// at this moment we've got too many core warnings.
// To display warnings call: grunt eslint --show-lint-warnings
// To fail on warnings call: grunt eslint --max-lint-warnings=0
// Also --max-lint-warnings=-1 can be used to display warnings but not fail.
options: {
quiet: (!grunt.option('show-lint-warnings')) && (typeof grunt.option('max-lint-warnings') === 'undefined'),
maxWarnings: ((typeof grunt.option('max-lint-warnings') !== 'undefined') ? grunt.option('max-lint-warnings') : -1)
},
// Check AMD src files.
amd: {src: files ? files : grunt.moodleEnv.amdSrc},
// Check YUI module source files.
yui: {src: files ? files : grunt.moodleEnv.yuiSrc},
},
});
grunt.loadNpmTasks('grunt-eslint');
// On watch, we dynamically modify config to build only affected files. This
// method is slightly complicated to deal with multiple changed files at once (copied
// from the grunt-contrib-watch readme).
let changedFiles = Object.create(null);
const onChange = grunt.util._.debounce(function() {
const files = Object.keys(changedFiles);
grunt.config('eslint.amd.src', files);
grunt.config('eslint.yui.src', files);
changedFiles = Object.create(null);
}, 200);
grunt.event.on('watch', (action, filepath) => {
changedFiles[filepath] = action;
onChange();
});
};
-92
View File
@@ -1,92 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
/**
* Get the list of feature files to pass to the gherkin linter.
*
* @returns {Array}
*/
const getGherkinLintTargets = () => {
if (grunt.moodleEnv.files) {
// Specific files were requested. Only check these.
return grunt.moodleEnv.files;
}
if (grunt.moodleEnv.inComponent) {
return [`${grunt.moodleEnv.runDir}/tests/behat/*.feature`];
}
return ['**/tests/behat/*.feature'];
};
const handler = function() {
const done = this.async();
const options = grunt.config('gherkinlint.options');
// Grab the gherkin-lint linter and required scaffolding.
const linter = require('gherkin-lint/dist/linter.js');
const featureFinder = require('gherkin-lint/dist/feature-finder.js');
const configParser = require('gherkin-lint/dist/config-parser.js');
const formatter = require('gherkin-lint/dist/formatters/stylish.js');
// Run the linter.
return linter.lint(
featureFinder.getFeatureFiles(grunt.file.expand(options.files)),
configParser.getConfiguration(configParser.defaultConfigFileName)
)
.then(results => {
// Print the results out uncondtionally.
formatter.printResults(results);
return results;
})
.then(results => {
// Report on the results.
// The done function takes a bool whereby a falsey statement causes the task to fail.
return results.every(result => result.errors.length === 0);
})
.then(done); // eslint-disable-line promise/no-callback-in-promise
};
grunt.registerTask('gherkinlint', 'Run gherkinlint against the current directory', handler);
grunt.config.set('gherkinlint', {
options: {
files: getGherkinLintTargets(),
}
});
grunt.config.merge({
watch: {
gherkinlint: {
files: [grunt.moodleEnv.inComponent ? 'tests/behat/*.feature' : '**/tests/behat/*.feature'],
tasks: ['gherkinlint'],
},
},
});
// Add the 'gherkinlint' task as a startup task.
grunt.moodleEnv.startupTasks.push('gherkinlint');
return handler;
};
-100
View File
@@ -1,100 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
/**
* Generate the PHPCS configuration.
*
* @param {Object} thirdPartyPaths
*/
const phpcsIgnore = (thirdPartyPaths) => {
const {toXML} = require('jstoxml');
const config = {
_name: 'ruleset',
_attrs: {
name: "MoodleCore",
},
_content: [
{
rule: {
_attrs: {
ref: './phpcs.xml.dist',
},
},
},
],
};
thirdPartyPaths.forEach(library => {
config._content.push({
'exclude-pattern': library,
});
});
grunt.file.write('phpcs.xml', toXML(config, {
header: true,
indent: ' ',
}) + "\n");
};
/**
* Generate ignore files (utilising thirdpartylibs.xml data)
*/
const handler = function() {
const path = require('path');
const ComponentList = require(path.join(process.cwd(), '.grunt', 'components.js'));
// An array of paths to third party directories.
const thirdPartyPaths = ComponentList.getThirdPartyPaths();
// Generate .eslintignore.
const eslintIgnores = [
'# Generated by "grunt ignorefiles"',
// Do not ignore the .grunt directory.
'!/.grunt',
// Ignore all yui/src meta directories and build directories.
'*/**/yui/src/*/meta/',
'*/**/build/',
].concat(thirdPartyPaths);
grunt.file.write('.eslintignore', eslintIgnores.join('\n') + '\n');
// Generate .stylelintignore.
const stylelintIgnores = [
'# Generated by "grunt ignorefiles"',
'**/yui/build/*',
'theme/boost/style/moodle.css',
'theme/classic/style/moodle.css',
'jsdoc/styles/*.css',
'admin/tool/componentlibrary/hugo/dist/css/docs.css',
].concat(thirdPartyPaths);
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n') + '\n');
phpcsIgnore(thirdPartyPaths);
};
grunt.registerTask('ignorefiles', 'Generate ignore files for linters', handler);
return handler;
};
-227
View File
@@ -1,227 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* 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
*
* @param {String} destPath the current destination
* @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');
return destPath;
};
module.exports = grunt => {
// Load the Ignorefiles tasks.
require('./ignorefiles')(grunt);
// Load the Shifter tasks.
require('./shifter')(grunt);
// Load ESLint.
require('./eslint')(grunt);
// Load jsconfig.
require('./jsconfig')(grunt);
// Load JSDoc.
require('./jsdoc')(grunt);
const path = require('path');
// Register JS tasks.
grunt.registerTask('yui', ['eslint:yui', 'shifter']);
grunt.registerTask('amd', ['ignorefiles', 'eslint:amd', 'rollup']);
grunt.registerTask('js', ['amd', 'yui']);
// Register NPM tasks.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-rollup');
const babelTransform = require('@babel/core').transform;
const babel = (options = {}) => {
return {
name: 'babel',
transform: (code, id) => {
grunt.log.debug(`Transforming ${id}`);
options.filename = id;
const transformed = babelTransform(code, options);
return {
code: transformed.code,
map: transformed.map
};
}
};
};
// Note: We have to use a rate limit plugin here because rollup runs all tasks asynchronously and in parallel.
// When we kick off a full run, if we kick off a rollup of every file this will fork-bomb the machine.
// To work around this we use a concurrent Promise queue based on the number of available processors.
const rateLimit = () => {
const queue = [];
let queueRunner;
const startQueue = () => {
if (queueRunner) {
return;
}
queueRunner = setTimeout(() => {
const limit = Math.max(1, require('os').cpus().length / 2);
grunt.log.debug(`Starting rollup with queue size of ${limit}`);
runQueue(limit);
}, 100);
};
// The queue runner will run the next `size` items in the queue.
const runQueue = (size = 1) => {
queue.splice(0, size).forEach(resolve => {
resolve();
});
};
return {
name: 'ratelimit',
// The options hook is run in parallel.
// We can return an unresolved Promise which is queued for later resolution.
options: async() => {
return new Promise(resolve => {
queue.push(resolve);
startQueue();
});
},
// When an item in the queue completes, start the next item in the queue.
buildEnd: () => {
runQueue();
},
};
};
const terser = require('rollup-plugin-terser').terser;
grunt.config.merge({
rollup: {
options: {
format: 'esm',
dir: 'output',
sourcemap: true,
treeshake: false,
context: 'window',
plugins: [
rateLimit(),
babel({
sourceMaps: true,
comments: false,
compact: false,
plugins: [
'transform-es2015-modules-amd-lazy',
'system-import-transformer',
// This plugin modifies the Babel transpiling for "export default"
// so that if it's used then only the exported value is returned
// by the generated AMD module.
//
// 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'),
'@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
}]
]
}),
terser({
// Do not mangle variables.
// Makes debugging easier.
mangle: false,
}),
],
},
dist: {
files: [{
expand: true,
src: grunt.moodleEnv.files ? grunt.moodleEnv.files : grunt.moodleEnv.amdSrc,
rename: babelRename
}],
},
},
});
grunt.config.merge({
watch: {
amd: {
files: grunt.moodleEnv.inComponent
? ['amd/src/*.js', 'amd/src/**/*.js']
: ['**/amd/src/**/*.js'],
tasks: ['amd']
},
},
});
// Add the 'js' task as a startup task.
grunt.moodleEnv.startupTasks.push('js');
// On watch, we dynamically modify config to build only affected files. This
// method is slightly complicated to deal with multiple changed files at once (copied
// from the grunt-contrib-watch readme).
let changedFiles = Object.create(null);
const onChange = grunt.util._.debounce(function() {
const files = Object.keys(changedFiles);
grunt.config('rollup.dist.files', [{expand: true, src: files, rename: babelRename}]);
changedFiles = Object.create(null);
}, 200);
grunt.event.on('watch', function(action, filepath) {
changedFiles[filepath] = action;
onChange();
});
return {
babelRename,
};
};
-53
View File
@@ -1,53 +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 2022 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const configuration = {
compilerOptions: {
baseUrl: ".",
paths: {
},
target: "es2015",
allowSyntheticDefaultImports: false,
},
exclude: [
"node_modules",
],
include: [],
};
module.exports = (grunt) => {
const handler = () => {
const jsconfigData = Object.assign({}, configuration);
const path = require('path');
const {fetchComponentData} = require(path.join(process.cwd(), '.grunt', 'components.js'));
const componentData = fetchComponentData().components;
for (const [thisPath, component] of Object.entries(componentData)) {
jsconfigData.compilerOptions.paths[`${component}/*`] = [`${thisPath}/amd/src/*`];
jsconfigData.include.push(`${thisPath}/amd/src/**/*`);
}
grunt.file.write('jsconfig.json', JSON.stringify(jsconfigData, null, " ") + "\n");
};
grunt.registerTask('jsconfig', 'Generate a jsconfig configuration compatible with the LSP', handler);
};
-36
View File
@@ -1,36 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
// Project configuration.
grunt.config.merge({
jsdoc: {
dist: {
options: {
configure: ".grunt/jsdoc/jsdoc.conf.js",
},
},
},
});
grunt.loadNpmTasks('grunt-jsdoc');
};
-40
View File
@@ -1,40 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
grunt.loadNpmTasks('grunt-sass');
grunt.config.merge({
sass: {
dist: {
files: {
"theme/boost/style/moodle.css": "theme/boost/scss/preset/default.scss",
"theme/classic/style/moodle.css": "theme/classic/scss/classicgrunt.scss"
}
},
options: {
implementation: require('sass'),
includePaths: ["theme/boost/scss/", "theme/classic/scss/"]
}
},
});
};
-155
View File
@@ -1,155 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/* eslint-env node */
module.exports = grunt => {
/**
* Shifter task. Is configured with a path to a specific file or a directory,
* in the case of a specific file it will work out the right module to be built.
*
* Note that this task runs the invidiaul shifter jobs async (becase it spawns
* so be careful to to call done().
*/
const handler = function() {
const done = this.async();
const options = grunt.config('shifter.options');
const async = require('async');
const path = require('path');
// Run the shifter processes one at a time to avoid confusing output.
async.eachSeries(options.paths, function(src, filedone) {
var args = [];
args.push(path.normalize(process.cwd() + '/node_modules/shifter/bin/shifter'));
// Always ignore the node_modules directory.
args.push('--excludes', 'node_modules');
// Determine the most appropriate options to run with based upon the current location.
if (grunt.file.isMatch('**/yui/**/*.js', src)) {
// When passed a JS file, build our containing module (this happen with
// watch).
grunt.log.debug('Shifter passed a specific JS file');
src = path.dirname(path.dirname(src));
options.recursive = false;
} else if (grunt.file.isMatch('**/yui/src', src)) {
// When in a src directory --walk all modules.
grunt.log.debug('In a src directory');
args.push('--walk');
options.recursive = false;
} else if (grunt.file.isMatch('**/yui/src/*', src)) {
// When in module, only build our module.
grunt.log.debug('In a module directory');
options.recursive = false;
} else if (grunt.file.isMatch('**/yui/src/*/js', src)) {
// When in module src, only build our module.
grunt.log.debug('In a source directory');
src = path.dirname(src);
options.recursive = false;
}
if (grunt.option('watch')) {
grunt.fail.fatal('The --watch option has been removed, please use `grunt watch` instead');
}
// Add the stderr option if appropriate
if (grunt.option('verbose')) {
args.push('--lint-stderr');
}
if (grunt.option('no-color')) {
args.push('--color=false');
}
var execShifter = function() {
grunt.log.ok("Running shifter on " + src);
grunt.util.spawn({
cmd: "node",
args: args,
opts: {cwd: src, stdio: 'inherit', env: process.env}
}, function(error, result, code) {
if (code) {
grunt.fail.fatal('Shifter failed with code: ' + code);
} else {
grunt.log.ok('Shifter build complete.');
filedone();
}
});
};
// Actually run shifter.
if (!options.recursive) {
execShifter();
} else {
// Check that there are yui modules otherwise shifter ends with exit code 1.
if (grunt.file.expand({cwd: src}, '**/yui/src/**/*.js').length > 0) {
args.push('--recursive');
execShifter();
} else {
grunt.log.ok('No YUI modules to build.');
filedone();
}
}
}, done);
};
// Register the shifter task.
grunt.registerTask('shifter', 'Run Shifter against the current directory', handler);
// Configure it.
grunt.config.set('shifter', {
options: {
recursive: true,
// Shifter takes a relative path.
paths: grunt.moodleEnv.files ? grunt.moodleEnv.files : [grunt.moodleEnv.runDir]
}
});
grunt.config.merge({
watch: {
yui: {
files: grunt.moodleEnv.inComponent
? ['yui/src/*.json', 'yui/src/**/*.js']
: ['**/yui/src/**/*.js'],
tasks: ['yui']
},
},
});
// On watch, we dynamically modify config to build only affected files. This
// method is slightly complicated to deal with multiple changed files at once (copied
// from the grunt-contrib-watch readme).
let changedFiles = Object.create(null);
const onChange = grunt.util._.debounce(function() {
const files = Object.keys(changedFiles);
grunt.config('shifter.options.paths', files);
changedFiles = Object.create(null);
}, 200);
grunt.event.on('watch', (action, filepath) => {
changedFiles[filepath] = action;
onChange();
});
return handler;
};
-46
View File
@@ -1,46 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
/**
* Generate ignore files (utilising thirdpartylibs.xml data)
*/
const handler = function() {
const path = require('path');
// Are we in a YUI directory?
if (path.basename(path.resolve(grunt.moodleEnv.cwd, '../../')) == 'yui') {
grunt.task.run('yui');
// Are we in an AMD directory?
} else if (grunt.moodleEnv.inAMD) {
grunt.task.run('amd');
} else {
// Run all of the requested startup tasks.
grunt.moodleEnv.startupTasks.forEach(taskName => grunt.task.run(taskName));
}
};
// Register the startup task.
grunt.registerTask('startup', 'Run the correct tasks for the current directory', handler);
return handler;
};
-35
View File
@@ -1,35 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
// Load the ignorefiles tasks.
require('./ignorefiles')(grunt);
// Load the Style Lint tasks.
require('./stylelint')(grunt);
// Load the SASS tasks.
require('./sass')(grunt);
// Add the 'css' task as a startup task.
grunt.moodleEnv.startupTasks.push('css');
};
-183
View File
@@ -1,183 +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 2021 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
const getCssConfigForFiles = files => {
return {
stylelint: {
css: {
// Use a fully-qualified path.
src: files,
options: {
configOverrides: {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
}
}
}
},
},
};
};
const getScssConfigForFiles = files => {
return {
stylelint: {
scss: {
options: {syntax: 'scss'},
src: files,
},
},
};
};
/**
* Register any stylelint tasks.
*
* @param {Object} grunt
* @param {Array} files
* @param {String} fullRunDir
*/
const registerStyleLintTasks = () => {
const glob = require('glob');
// The stylelinters do not handle the case where a configuration was provided but no files were included.
// Keep track of whether any files were found.
let hasCss = false;
let hasScss = false;
// The stylelint processors do not take a path argument. They always check all provided values.
// As a result we must check through each glob and determine if any files match the current directory.
const scssFiles = [];
const cssFiles = [];
const requestedFiles = grunt.moodleEnv.files;
if (requestedFiles) {
// Grunt was called with a files argument.
// Check whether each of the requested files matches either the CSS or SCSS source file list.
requestedFiles.forEach(changedFilePath => {
let matchesGlob;
// Check whether this watched path matches any watched SCSS file.
matchesGlob = grunt.moodleEnv.scssSrc.some(watchedPathGlob => {
return glob.sync(watchedPathGlob).indexOf(changedFilePath) !== -1;
});
if (matchesGlob) {
scssFiles.push(changedFilePath);
hasScss = true;
}
// Check whether this watched path matches any watched CSS file.
matchesGlob = grunt.moodleEnv.cssSrc.some(watchedPathGlob => {
return glob.sync(watchedPathGlob).indexOf(changedFilePath) !== -1;
});
if (matchesGlob) {
cssFiles.push(changedFilePath);
hasCss = true;
}
});
} else {
// Grunt was called without a list of files.
// The start directory (runDir) may be a child dir of the project.
// Check each scssSrc file to see if it's in the start directory.
// This means that we can lint just mod/*/styles.css if started in the mod directory.
grunt.moodleEnv.scssSrc.forEach(path => {
if (path.startsWith(grunt.moodleEnv.runDir)) {
scssFiles.push(path);
hasScss = true;
}
});
grunt.moodleEnv.cssSrc.forEach(path => {
if (path.startsWith(grunt.moodleEnv.runDir)) {
cssFiles.push(path);
hasCss = true;
}
});
}
// Register the tasks.
const scssTasks = ['sass'];
if (hasScss) {
grunt.config.merge(getScssConfigForFiles(scssFiles));
scssTasks.unshift('stylelint:scss');
}
scssTasks.unshift('ignorefiles');
const cssTasks = ['ignorefiles'];
if (hasCss) {
grunt.config.merge(getCssConfigForFiles(cssFiles));
cssTasks.push('stylelint:css');
}
// The tasks must be registered, even if empty to ensure a consistent command list.
// They jsut won't run anything.
grunt.registerTask('scss', scssTasks);
grunt.registerTask('rawcss', cssTasks);
};
// Register CSS tasks.
grunt.loadNpmTasks('grunt-stylelint');
// Register the style lint tasks.
registerStyleLintTasks();
grunt.registerTask('css', ['scss', 'rawcss']);
const getCoreThemeMatches = () => {
const scssMatch = 'scss/**/*.scss';
if (grunt.moodleEnv.inTheme) {
return [scssMatch];
}
if (grunt.moodleEnv.runDir.startsWith('theme')) {
return [`*/${scssMatch}`];
}
return [`theme/*/${scssMatch}`];
};
// Add the watch configuration for rawcss, and scss.
grunt.config.merge({
watch: {
rawcss: {
files: [
'**/*.css',
],
excludes: [
'**/moodle.css',
'**/editor.css',
'jsdoc/styles/*.css',
],
tasks: ['rawcss']
},
scss: {
files: getCoreThemeMatches(),
tasks: ['scss']
},
},
});
};
-272
View File
@@ -1,272 +0,0 @@
/**
* This is a wrapper task to handle the grunt watch command. It attempts to use
* Watchman to monitor for file changes, if it's installed, because it's much faster.
*
* If Watchman isn't installed then it falls back to the grunt-contrib-watch file
* watcher for backwards compatibility.
*/
/* eslint-env node */
module.exports = grunt => {
/**
* This is a wrapper task to handle the grunt watch command. It attempts to use
* Watchman to monitor for file changes, if it's installed, because it's much faster.
*
* If Watchman isn't installed then it falls back to the grunt-contrib-watch file
* watcher for backwards compatibility.
*/
const watchHandler = function() {
const async = require('async');
const watchTaskDone = this.async();
let watchInitialised = false;
let watchTaskQueue = {};
let processingQueue = false;
const watchman = require('fb-watchman');
const watchmanClient = new watchman.Client();
// Grab the tasks and files that have been queued up and execute them.
var processWatchTaskQueue = function() {
if (!Object.keys(watchTaskQueue).length || processingQueue) {
// If there is nothing in the queue or we're already processing then wait.
return;
}
processingQueue = true;
// Grab all tasks currently in the queue.
var queueToProcess = watchTaskQueue;
// Reset the queue.
watchTaskQueue = {};
async.forEachSeries(
Object.keys(queueToProcess),
function(task, next) {
var files = queueToProcess[task];
var filesOption = '--files=' + files.join(',');
grunt.log.ok('Running task ' + task + ' for files ' + filesOption);
// Spawn the task in a child process so that it doesn't kill this one
// if it failed.
grunt.util.spawn(
{
// Spawn with the grunt bin.
grunt: true,
// Run from current working dir and inherit stdio from process.
opts: {
cwd: grunt.moodleEnv.fullRunDir,
stdio: 'inherit'
},
args: [task, filesOption]
},
function(err, res, code) {
if (code !== 0) {
// The grunt task failed.
grunt.log.error(err);
}
// Move on to the next task.
next();
}
);
},
function() {
// No longer processing.
processingQueue = false;
// Once all of the tasks are done then recurse just in case more tasks
// were queued while we were processing.
processWatchTaskQueue();
}
);
};
const originalWatchConfig = grunt.config.get(['watch']);
const watchConfig = Object.keys(originalWatchConfig).reduce(function(carry, key) {
if (key == 'options') {
return carry;
}
const value = originalWatchConfig[key];
const taskNames = value.tasks;
const files = value.files;
let excludes = [];
if (value.excludes) {
excludes = value.excludes;
}
taskNames.forEach(function(taskName) {
carry[taskName] = {
files,
excludes,
};
});
return carry;
}, {});
watchmanClient.on('error', function(error) {
// We have to add an error handler here and parse the error string because the
// example way from the docs to check if Watchman is installed doesn't actually work!!
// See: https://github.com/facebook/watchman/issues/509
if (error.message.match('Watchman was not found')) {
// If watchman isn't installed then we should fallback to the other watch task.
grunt.log.ok('It is recommended that you install Watchman for better performance using the "watch" command.');
// Fallback to the old grunt-contrib-watch task.
grunt.renameTask('watch-grunt', 'watch');
grunt.task.run(['watch']);
// This task is finished.
watchTaskDone(0);
} else {
grunt.log.error(error);
// Fatal error.
watchTaskDone(1);
}
});
watchmanClient.on('subscription', function(resp) {
if (resp.subscription !== 'grunt-watch') {
return;
}
resp.files.forEach(function(file) {
grunt.log.ok('File changed: ' + file.name);
var fullPath = grunt.moodleEnv.fullRunDir + '/' + file.name;
Object.keys(watchConfig).forEach(function(task) {
const fileGlobs = watchConfig[task].files;
var match = fileGlobs.some(function(fileGlob) {
return grunt.file.isMatch(`**/${fileGlob}`, fullPath);
});
if (match) {
// If we are watching a subdirectory then the file.name will be relative
// to that directory. However the grunt tasks expect the file paths to be
// relative to the Gruntfile.js location so let's normalise them before
// adding them to the queue.
var relativePath = fullPath.replace(grunt.moodleEnv.gruntFilePath + '/', '');
if (task in watchTaskQueue) {
if (!watchTaskQueue[task].includes(relativePath)) {
watchTaskQueue[task] = watchTaskQueue[task].concat(relativePath);
}
} else {
watchTaskQueue[task] = [relativePath];
}
}
});
});
processWatchTaskQueue();
});
process.on('SIGINT', function() {
// Let the user know that they may need to manually stop the Watchman daemon if they
// no longer want it running.
if (watchInitialised) {
grunt.log.ok('The Watchman daemon may still be running and may need to be stopped manually.');
}
process.exit();
});
// Initiate the watch on the current directory.
watchmanClient.command(['watch-project', grunt.moodleEnv.fullRunDir], function(watchError, watchResponse) {
if (watchError) {
grunt.log.error('Error initiating watch:', watchError);
watchTaskDone(1);
return;
}
if ('warning' in watchResponse) {
grunt.log.error('warning: ', watchResponse.warning);
}
var watch = watchResponse.watch;
var relativePath = watchResponse.relative_path;
watchInitialised = true;
watchmanClient.command(['clock', watch], function(clockError, clockResponse) {
if (clockError) {
grunt.log.error('Failed to query clock:', clockError);
watchTaskDone(1);
return;
}
// Generate the expression query used by watchman.
// Documentation is limited, but see https://facebook.github.io/watchman/docs/expr/allof.html for examples.
// We generate an expression to match any value in the files list of all of our tasks, but excluding
// all value in the excludes list of that task.
//
// [anyof, [
// [allof, [
// [anyof, [
// ['match', validPath, 'wholename'],
// ['match', validPath, 'wholename'],
// ],
// [not,
// [anyof, [
// ['match', invalidPath, 'wholename'],
// ['match', invalidPath, 'wholename'],
// ],
// ],
// ],
var matchWholeName = fileGlob => ['match', fileGlob, 'wholename'];
var matches = Object.keys(watchConfig).map(function(task) {
const matchAll = [];
matchAll.push(['anyof'].concat(watchConfig[task].files.map(matchWholeName)));
if (watchConfig[task].excludes.length) {
matchAll.push(['not', ['anyof'].concat(watchConfig[task].excludes.map(matchWholeName))]);
}
return ['allof'].concat(matchAll);
});
matches = ['anyof'].concat(matches);
var sub = {
expression: matches,
// Which fields we're interested in.
fields: ["name", "size", "type"],
// Add our time constraint.
since: clockResponse.clock
};
if (relativePath) {
/* eslint-disable camelcase */
sub.relative_root = relativePath;
}
watchmanClient.command(['subscribe', watch, 'grunt-watch', sub], function(subscribeError) {
if (subscribeError) {
// Probably an error in the subscription criteria.
grunt.log.error('failed to subscribe: ', subscribeError);
watchTaskDone(1);
return;
}
grunt.log.ok('Listening for changes to files in ' + grunt.moodleEnv.fullRunDir);
});
});
});
};
// Rename the grunt-contrib-watch "watch" task because we're going to wrap it.
grunt.renameTask('watch', 'watch-grunt');
// Register the new watch handler.
grunt.registerTask('watch', 'Run tasks on file changes', watchHandler);
grunt.config.merge({
watch: {
options: {
nospawn: true // We need not to spawn so config can be changed dynamically.
},
},
});
return watchHandler;
};
-2
View File
@@ -1,2 +0,0 @@
**/amd/**
/*.js
-1
View File
@@ -1 +0,0 @@
lts/gallium
+93
View File
@@ -0,0 +1,93 @@
# Generated by "grunt ignorefiles"
**/yui/build/*
theme/bootstrapbase/style/
theme/clean/style/custom.css
theme/more/style/custom.css
theme/boost/style/moodle.css
node_modules/
vendor/
admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
admin/tool/usertours/amd/src/tour.js
auth/cas/CAS/
enrol/lti/ims-blti/
filter/algebra/AlgParser.pm
filter/tex/mimetex.*
lib/editor/atto/plugins/html/yui/src/codemirror/
lib/editor/atto/plugins/html/yui/src/beautify/
lib/editor/atto/yui/src/rangy/js/*.*
lib/editor/tinymce/plugins/pdw/tinymce/
lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
lib/mlbackend/php/phpml/
lib/adodb/
lib/bennu/
lib/evalmath/
lib/lessphp/
lib/phpexcel/
lib/google/
lib/htmlpurifier/
lib/jabber/
lib/minify/matthiasmullie-minify/
lib/minify/matthiasmullie-pathconverter/
lib/pear/Auth/RADIUS.php
lib/pear/Crypt/CHAP.php
lib/pear/HTML/Common.php
lib/pear/HTML/QuickForm.php
lib/pear/HTML/QuickForm/
lib/pear/PEAR.php
lib/phpmailer/
lib/simplepie/
lib/tcpdf/
lib/typo3/
lib/yuilib/
lib/yuilib/gallery/
lib/jquery/
lib/html2text/
lib/markdown/
lib/recaptchalib.php
lib/xhprof/
lib/horde/
lib/requirejs/
lib/amd/src/loglevel.js
lib/mustache/
lib/amd/src/mustache.js
lib/graphlib.php
lib/php-css-parser/
lib/rtlcss/
lib/scssphp/
lib/spout/
lib/amd/src/chartjs-lazy.js
lib/maxmind/GeoIp2/
lib/maxmind/MaxMind/
lib/ltiprovider/
lib/amd/src/truncate.js
lib/fonts/
lib/amd/src/adapter.js
lib/validateurlsyntax.php
lib/amd/src/popper.js
lib/geopattern-php/
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/videojs/
media/player/videojs/amd/src/videojs-flash-lazy.js
media/player/videojs/videojs/video-js.swf
mod/assign/feedback/editpdf/fpdi/
repository/s3/S3.php
theme/boost/scss/bootstrap/
theme/boost/amd/src/alert.js
theme/boost/amd/src/button.js
theme/boost/amd/src/carousel.js
theme/boost/amd/src/collapse.js
theme/boost/amd/src/dropdown.js
theme/boost/amd/src/modal.js
theme/boost/amd/src/popover.js
theme/boost/amd/src/scrollspy.js
theme/boost/amd/src/tab.js
theme/boost/amd/src/tooltip.js
theme/boost/amd/src/util.js
theme/boost/amd/src/tether.js
theme/boost/scss/fontawesome/
theme/bootstrapbase/less/bootstrap/
theme/bootstrapbase/javascript/html5shiv.js
theme/bootstrapbase/amd/src/bootstrap.js
theme/bootstrapbase/less/fontawesome/
+100 -90
View File
@@ -2,96 +2,84 @@
# process (which uses our internal CI system) this file is here for the benefit
# of community developers git clones - see MDL-51458.
sudo: required
# We currently disable Travis notifications entirely until https://github.com/travis-ci/travis-ci/issues/4976
# is fixed.
notifications:
email:
if: env(MOODLE_EMAIL) != no
email: false
language: php
os: linux
dist: focal
services:
- mysql
- docker
php:
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
- 7.2
- 7.0
addons:
postgresql: "12"
apt:
packages:
- postgresql-12
- postgresql-client-12
postgresql: "9.6"
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
branches:
except:
- master
- /MOODLE_[0-9]+_STABLE/
- /^v[0-9]+\.[0-9]+\.[0-9]+.*/
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
# services:
# - redis-server
jobs:
env:
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
# start first so that the total run time is not too high.
#
# We only run MySQL on PHP 7.2, so run that first.
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
# Postgres is significantly is pretty reasonable in its run-time.
# Run unit tests on MySQL
- DB=mysqli TASK=PHPUNIT
# Run CI Tests without running PHPUnit.
- DB=none TASK=CITEST
# Run unit tests on Postgres
- DB=pgsql TASK=PHPUNIT
# Perform an upgrade test too.
- DB=pgsql TASK=UPGRADE
matrix:
# 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
# Run grunt/npm install on highest version ('node' is an alias for the latest node.js version.)
- php: 7.2
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
- 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
exclude:
# MySQL - it's just too slow.
# Exclude it on all versions except for 7.2
- 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.1)
- if: env(MOODLE_PHP) = "all"
php: 8.1
env: DB=none TASK=CITEST
- if: env(MOODLE_PHP) = "all"
php: 8.1
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.1
env: DB=pgsql TASK=PHPUNIT
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all")
php: 8.1
env: DB=mysqli TASK=PHPUNIT
- env: DB=mysqli TASK=PHPUNIT
php: 7.0
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 stop mysql
sudo mv /var/lib/mysql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
echo -e "[mysqld]\nskip-log-bin" | sudo tee -a /etc/mysql/my.cnf
sudo service mysql start
sudo start mysql
fi
- >
if [ "$DB" = 'pgsql' ];
@@ -101,8 +89,7 @@ install:
sudo service postgresql stop
sudo mv /var/lib/postgresql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
sudo service postgresql start
sh -c 'until pg_isready -p $PGPORT; do echo "Waiting for the DB to be up..."; sleep 2; done'
sudo service postgresql start 9.6
fi
- >
if [ "$TASK" = 'PHPUNIT' ];
@@ -112,8 +99,10 @@ install:
echo 'auth.json' >> .git/info/exclude
fi
echo 'extension="redis.so"' > /tmp/redis.ini
phpenv config-add /tmp/redis.ini
# Enable Redis.
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
# 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.
@@ -124,15 +113,14 @@ install:
- >
if [ "$TASK" = 'GRUNT' ];
then
nvm install
nvm use
nvm install $NVM_VERSION ;
nvm use $NVM_VERSION ;
fi
before_script:
- echo 'max_input_vars=5000' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- phpenv config-rm xdebug.ini
- >
if [ "$TASK" = 'PHPUNIT' ];
if [ "$TASK" = 'PHPUNIT' -o "$TASK" = 'UPGRADE' ];
then
# Copy generic configuration in place.
cp config-dist.php config.php ;
@@ -156,11 +144,10 @@ before_script:
then
# Postgres-specific setup.
sed -i \
-e "s%= 'username'%= 'travis'%" \
-e "s%'dbsocket' => false%'dbsocket' => true%" \
-e "s%= 'username'%= 'postgres'%" \
config.php ;
psql -c 'CREATE DATABASE travis_ci_test;' -U travis;
psql -c 'CREATE DATABASE travis_ci_test;' -U postgres;
fi
if [ "$DB" = 'mysqli' ];
@@ -186,24 +173,12 @@ before_script:
mkdir -p "$HOME"/roots/phpunit
# The phpunit dataroot and prefix..
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
# -e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
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
@@ -232,7 +207,7 @@ before_script:
# We need the official upstream for comparison
git remote add upstream https://github.com/moodle/moodle.git;
git fetch upstream MOODLE_401_STABLE;
git fetch upstream MOODLE_36_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`
@@ -243,6 +218,32 @@ before_script:
export phpcmd=`which php`;
fi
########################################################################
# Upgrade test
########################################################################
- >
if [ "$TASK" = 'UPGRADE' ];
then
# We need the official upstream.
git remote add upstream https://github.com/moodle/moodle.git;
# Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
git fetch upstream MOODLE_30_STABLE;
git checkout MOODLE_30_STABLE;
# Perform the upgrade
php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
# Return to the previous commit
git checkout -;
# Perform the upgrade
php admin/cli/upgrade.php --non-interactive --allow-unstable ;
# The local_ci repository can be used to check upgrade savepoints.
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci ;
fi
script:
- >
if [ "$TASK" = 'PHPUNIT' ];
@@ -268,10 +269,19 @@ script:
git diff --cached --exit-code ;
fi
after_script:
########################################################################
# Upgrade test
########################################################################
- >
if [ "$TASK" = 'PHPUNIT' ];
if [ "$TASK" = 'UPGRADE' ];
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"
cp local/ci/check_upgrade_savepoints/check_upgrade_savepoints.php ./check_upgrade_savepoints.php
result=`php check_upgrade_savepoints.php`;
# Check if there are problems
count=`echo "$result" | grep -P "ERROR|WARN" | wc -l` ;
if (($count > 0));
then
echo "$result"
exit 1 ;
fi
fi
+350 -218
View File
@@ -16,200 +16,22 @@
/* eslint-env node */
/**
* Grunt configuration for Moodle.
*
* @copyright 2014 Andrew Nicols
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Setup the Grunt Moodle environment.
*
* @param {Grunt} grunt
* @returns {Object}
* Grunt configuration
*/
const setupMoodleEnvironment = grunt => {
const fs = require('fs');
const path = require('path');
const ComponentList = require(path.join(process.cwd(), '.grunt', 'components.js'));
const getAmdConfiguration = () => {
// If the cwd is the amd directory in the current component then it will be empty.
// If the cwd is a child of the component's AMD directory, the relative directory will not start with ..
let inAMD = !path.relative(`${componentDirectory}/amd`, cwd).startsWith('..');
// Globbing pattern for matching all AMD JS source files.
let amdSrc = [];
if (inComponent) {
amdSrc.push(
componentDirectory + "/amd/src/*.js",
componentDirectory + "/amd/src/**/*.js"
);
} else {
amdSrc = ComponentList.getAmdSrcGlobList();
}
return {
inAMD,
amdSrc,
};
};
const getYuiConfiguration = () => {
let yuiSrc = [];
if (inComponent) {
yuiSrc.push(componentDirectory + "/yui/src/**/*.js");
} else {
yuiSrc = ComponentList.getYuiSrcGlobList(gruntFilePath + '/');
}
return {
yuiSrc,
};
};
const getStyleConfiguration = () => {
const ComponentList = require(path.join(process.cwd(), '.grunt', 'components.js'));
// Build the cssSrc and scssSrc.
// Valid paths are:
// [component]/styles.css; and either
// [theme/[themename]]/scss/**/*.scss; or
// [theme/[themename]]/style/*.css.
//
// If a theme has scss, then it is assumed that the style directory contains generated content.
let cssSrc = [];
let scssSrc = [];
const checkComponentDirectory = componentDirectory => {
const isTheme = componentDirectory.startsWith('theme/');
if (isTheme) {
const scssDirectory = `${componentDirectory}/scss`;
if (fs.existsSync(scssDirectory)) {
// This theme has an SCSS directory.
// Include all scss files within it recursively, but do not check for css files.
scssSrc.push(`${scssDirectory}/*.scss`);
scssSrc.push(`${scssDirectory}/**/*.scss`);
} else {
// This theme has no SCSS directory.
// Only hte CSS files in the top-level directory are checked.
cssSrc.push(`${componentDirectory}/style/*.css`);
}
} else {
// This is not a theme.
// All other plugin types are restricted to a single styles.css in their top level.
cssSrc.push(`${componentDirectory}/styles.css`);
}
};
if (inComponent) {
checkComponentDirectory(componentDirectory);
} else {
ComponentList.getComponentPaths(`${gruntFilePath}/`).forEach(componentPath => {
checkComponentDirectory(componentPath);
});
}
return {
cssSrc,
scssSrc,
};
};
/**
* Calculate the cwd, taking into consideration the `root` option (for Windows).
*
* @param {Object} grunt
* @returns {String} The current directory as best we can determine
*/
const getCwd = grunt => {
let cwd = fs.realpathSync(process.env.PWD || process.cwd());
// Windows users can't run grunt in a subdirectory, so allow them to set
// the root by passing --root=path/to/dir.
if (grunt.option('root')) {
const root = grunt.option('root');
if (grunt.file.exists(__dirname, root)) {
cwd = fs.realpathSync(path.join(__dirname, root));
grunt.log.ok('Setting root to ' + cwd);
} else {
grunt.fail.fatal('Setting root to ' + root + ' failed - path does not exist');
}
}
return cwd;
};
// Detect directories:
// * gruntFilePath The real path on disk to this Gruntfile.js
// * cwd The current working directory, which can be overridden by the `root` option
// * relativeCwd The cwd, relative to the Gruntfile.js
// * componentDirectory The root directory of the component if the cwd is in a valid component
// * inComponent Whether the cwd is in a valid component
// * runDir The componentDirectory or cwd if not in a component, relative to Gruntfile.js
// * fullRunDir The full path to the runDir
const gruntFilePath = fs.realpathSync(process.cwd());
const cwd = getCwd(grunt);
const relativeCwd = path.relative(gruntFilePath, cwd);
const componentDirectory = ComponentList.getOwningComponentDirectory(relativeCwd);
const inComponent = !!componentDirectory;
const inTheme = !!componentDirectory && componentDirectory.startsWith('theme/');
const runDir = inComponent ? componentDirectory : relativeCwd;
const fullRunDir = fs.realpathSync(gruntFilePath + path.sep + runDir);
const {inAMD, amdSrc} = getAmdConfiguration();
const {yuiSrc} = getYuiConfiguration();
const {cssSrc, scssSrc} = getStyleConfiguration();
let files = null;
if (grunt.option('files')) {
// Accept a comma separated list of files to process.
files = grunt.option('files').split(',');
}
grunt.log.debug('============================================================================');
grunt.log.debug(`= Node version: ${process.versions.node}`);
grunt.log.debug(`= grunt version: ${grunt.package.version}`);
grunt.log.debug(`= process.cwd: '` + process.cwd() + `'`);
grunt.log.debug(`= process.env.PWD: '${process.env.PWD}'`);
grunt.log.debug(`= path.sep '${path.sep}'`);
grunt.log.debug('============================================================================');
grunt.log.debug(`= gruntFilePath: '${gruntFilePath}'`);
grunt.log.debug(`= relativeCwd: '${relativeCwd}'`);
grunt.log.debug(`= componentDirectory: '${componentDirectory}'`);
grunt.log.debug(`= inComponent: '${inComponent}'`);
grunt.log.debug(`= runDir: '${runDir}'`);
grunt.log.debug(`= fullRunDir: '${fullRunDir}'`);
grunt.log.debug('============================================================================');
if (inComponent) {
grunt.log.ok(`Running tasks for component directory ${componentDirectory}`);
}
return {
amdSrc,
componentDirectory,
cwd,
cssSrc,
files,
fullRunDir,
gruntFilePath,
inAMD,
inComponent,
inTheme,
relativeCwd,
runDir,
scssSrc,
yuiSrc,
};
};
/**
* Verify tha tthe current NodeJS version matches the required version in package.json.
*
* @param {Grunt} grunt
*/
const verifyNodeVersion = grunt => {
const semver = require('semver');
module.exports = function(grunt) {
var path = require('path'),
tasks = {},
cwd = process.env.PWD || process.cwd(),
async = require('async'),
DOMParser = require('xmldom').DOMParser,
xpath = require('xpath'),
semver = require('semver');
// Verify the node version is new enough.
var expected = semver.validRange(grunt.file.readJSON('package.json').engines.node);
@@ -217,48 +39,358 @@ const verifyNodeVersion = grunt => {
if (!semver.satisfies(actual, expected)) {
grunt.fail.fatal('Node version not satisfied. Require ' + expected + ', version installed: ' + actual);
}
};
/**
* Grunt configuration.
*
* @param {Grunt} grunt
*/
module.exports = function(grunt) {
// Verify that the Node version meets our requirements.
verifyNodeVersion(grunt);
// Windows users can't run grunt in a subdirectory, so allow them to set
// the root by passing --root=path/to/dir.
if (grunt.option('root')) {
var root = grunt.option('root');
if (grunt.file.exists(__dirname, root)) {
cwd = path.join(__dirname, root);
grunt.log.ok('Setting root to ' + cwd);
} else {
grunt.fail.fatal('Setting root to ' + root + ' failed - path does not exist');
}
}
// Setup the Moodle environemnt within the Grunt object.
grunt.moodleEnv = setupMoodleEnvironment(grunt);
var inAMD = path.basename(cwd) == 'amd';
// Globbing pattern for matching all AMD JS source files.
var amdSrc = [inAMD ? cwd + '/src/*.js' : '**/amd/src/*.js'];
/**
* Add the named 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
*
* @param {string} name
* @param {Grunt} grunt
* @param {String} destPath the current destination
* @param {String} srcPath the matched src path
* @return {String} The rewritten destination path.
*/
const addTask = (name, grunt) => {
const path = require('path');
const taskPath = path.resolve(`./.grunt/tasks/${name}.js`);
grunt.log.debug(`Including tasks for ${name} from ${taskPath}`);
require(path.resolve(`./.grunt/tasks/${name}.js`))(grunt);
var uglifyRename = function(destPath, srcPath) {
destPath = srcPath.replace('src', 'build');
destPath = destPath.replace('.js', '.min.js');
destPath = path.resolve(cwd, destPath);
return destPath;
};
// Startup tasks.
grunt.moodleEnv.startupTasks = [];
/**
* Find thirdpartylibs.xml and generate an array of paths contained within
* them (used to generate ignore files and so on).
*
* @return {array} The list of thirdparty paths.
*/
var getThirdPartyPathsFromXML = function() {
var thirdpartyfiles = grunt.file.expand('*/**/thirdpartylibs.xml');
var libs = ['node_modules/', 'vendor/'];
// Add Moodle task configuration.
addTask('gherkinlint', grunt);
addTask('ignorefiles', grunt);
thirdpartyfiles.forEach(function(file) {
var dirname = path.dirname(file);
addTask('javascript', grunt);
addTask('style', grunt);
addTask('componentlibrary', grunt);
var doc = new DOMParser().parseFromString(grunt.file.read(file));
var nodes = xpath.select("/libraries/library/location/text()", doc);
addTask('watch', grunt);
addTask('startup', grunt);
nodes.forEach(function(node) {
var lib = path.join(dirname, node.toString());
if (grunt.file.isDir(lib)) {
// Ensure trailing slash on dirs.
lib = lib.replace(/\/?$/, '/');
}
// Look for duplicate paths before adding to array.
if (libs.indexOf(lib) === -1) {
libs.push(lib);
}
});
});
return libs;
};
// Project configuration.
grunt.initConfig({
eslint: {
// Even though warnings dont stop the build we don't display warnings by default because
// at this moment we've got too many core warnings.
options: {quiet: !grunt.option('show-lint-warnings')},
amd: {src: amdSrc},
// Check YUI module source files.
yui: {src: ['**/yui/src/**/*.js', '!*/**/yui/src/*/meta/*.js']}
},
uglify: {
amd: {
files: [{
expand: true,
src: amdSrc,
rename: uglifyRename
}],
options: {report: 'none'}
}
},
less: {
bootstrapbase: {
files: {
"theme/bootstrapbase/style/moodle.css": "theme/bootstrapbase/less/moodle.less",
"theme/bootstrapbase/style/editor.css": "theme/bootstrapbase/less/editor.less",
},
options: {
compress: false // We must not compress to keep the comments.
}
}
},
sass: {
dist: {
files: {
"theme/boost/style/moodle.css": "theme/boost/scss/preset/default.scss"
}
},
options: {
includePaths: ["theme/boost/scss/"]
}
},
watch: {
options: {
nospawn: true // We need not to spawn so config can be changed dynamically.
},
amd: {
files: ['**/amd/src/**/*.js'],
tasks: ['amd']
},
bootstrapbase: {
files: ["theme/bootstrapbase/less/**/*.less"],
tasks: ["css"]
},
yui: {
files: ['**/yui/src/**/*.js'],
tasks: ['yui']
},
gherkinlint: {
files: ['**/tests/behat/*.feature'],
tasks: ['gherkinlint']
}
},
shifter: {
options: {
recursive: true,
paths: [cwd]
}
},
gherkinlint: {
options: {
files: ['**/tests/behat/*.feature'],
}
},
stylelint: {
less: {
options: {
syntax: 'less',
configOverrides: {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
}
}
},
src: ['theme/**/*.less']
},
scss: {
options: {syntax: 'scss'},
src: ['*/**/*.scss']
},
css: {
src: ['*/**/*.css'],
options: {
configOverrides: {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
}
}
}
}
}
});
/**
* Generate ignore files (utilising thirdpartylibs.xml data)
*/
tasks.ignorefiles = function() {
// An array of paths to third party directories.
var thirdPartyPaths = getThirdPartyPathsFromXML();
// Generate .eslintignore.
var eslintIgnores = ['# Generated by "grunt ignorefiles"', '*/**/yui/src/*/meta/', '*/**/build/'].concat(thirdPartyPaths);
grunt.file.write('.eslintignore', eslintIgnores.join('\n'));
// Generate .stylelintignore.
var stylelintIgnores = [
'# Generated by "grunt ignorefiles"',
'**/yui/build/*',
'theme/bootstrapbase/style/',
'theme/clean/style/custom.css',
'theme/more/style/custom.css',
'theme/boost/style/moodle.css'
].concat(thirdPartyPaths);
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n'));
};
/**
* Shifter task. Is configured with a path to a specific file or a directory,
* in the case of a specific file it will work out the right module to be built.
*
* Note that this task runs the invidiaul shifter jobs async (becase it spawns
* so be careful to to call done().
*/
tasks.shifter = function() {
var done = this.async(),
options = grunt.config('shifter.options');
// Run the shifter processes one at a time to avoid confusing output.
async.eachSeries(options.paths, function(src, filedone) {
var args = [];
args.push(path.normalize(__dirname + '/node_modules/shifter/bin/shifter'));
// Always ignore the node_modules directory.
args.push('--excludes', 'node_modules');
// Determine the most appropriate options to run with based upon the current location.
if (grunt.file.isMatch('**/yui/**/*.js', src)) {
// When passed a JS file, build our containing module (this happen with
// watch).
grunt.log.debug('Shifter passed a specific JS file');
src = path.dirname(path.dirname(src));
options.recursive = false;
} else if (grunt.file.isMatch('**/yui/src', src)) {
// When in a src directory --walk all modules.
grunt.log.debug('In a src directory');
args.push('--walk');
options.recursive = false;
} else if (grunt.file.isMatch('**/yui/src/*', src)) {
// When in module, only build our module.
grunt.log.debug('In a module directory');
options.recursive = false;
} else if (grunt.file.isMatch('**/yui/src/*/js', src)) {
// When in module src, only build our module.
grunt.log.debug('In a source directory');
src = path.dirname(src);
options.recursive = false;
}
if (grunt.option('watch')) {
grunt.fail.fatal('The --watch option has been removed, please use `grunt watch` instead');
}
// Add the stderr option if appropriate
if (grunt.option('verbose')) {
args.push('--lint-stderr');
}
if (grunt.option('no-color')) {
args.push('--color=false');
}
var execShifter = function() {
grunt.log.ok("Running shifter on " + src);
grunt.util.spawn({
cmd: "node",
args: args,
opts: {cwd: src, stdio: 'inherit', env: process.env}
}, function(error, result, code) {
if (code) {
grunt.fail.fatal('Shifter failed with code: ' + code);
} else {
grunt.log.ok('Shifter build complete.');
filedone();
}
});
};
// Actually run shifter.
if (!options.recursive) {
execShifter();
} else {
// Check that there are yui modules otherwise shifter ends with exit code 1.
if (grunt.file.expand({cwd: src}, '**/yui/src/**/*.js').length > 0) {
args.push('--recursive');
execShifter();
} else {
grunt.log.ok('No YUI modules to build.');
filedone();
}
}
}, done);
};
tasks.gherkinlint = function() {
var done = this.async(),
options = grunt.config('gherkinlint.options');
var args = grunt.file.expand(options.files);
args.unshift(path.normalize(__dirname + '/node_modules/.bin/gherkin-lint'));
grunt.util.spawn({
cmd: 'node',
args: args,
opts: {stdio: 'inherit', env: process.env}
}, function(error, result, code) {
// Propagate the exit code.
done(code === 0);
});
};
tasks.startup = function() {
// Are we in a YUI directory?
if (path.basename(path.resolve(cwd, '../../')) == 'yui') {
grunt.task.run('yui');
// Are we in an AMD directory?
} else if (inAMD) {
grunt.task.run('amd');
} else {
// Run them all!.
grunt.task.run('css');
grunt.task.run('js');
grunt.task.run('gherkinlint');
}
};
// On watch, we dynamically modify config to build only affected files. This
// method is slightly complicated to deal with multiple changed files at once (copied
// from the grunt-contrib-watch readme).
var changedFiles = Object.create(null);
var onChange = grunt.util._.debounce(function() {
var files = Object.keys(changedFiles);
grunt.config('eslint.amd.src', files);
grunt.config('eslint.yui.src', files);
grunt.config('uglify.amd.files', [{expand: true, src: files, rename: uglifyRename}]);
grunt.config('shifter.options.paths', files);
grunt.config('stylelint.less.src', files);
grunt.config('gherkinlint.options.files', files);
changedFiles = Object.create(null);
}, 200);
grunt.event.on('watch', function(action, filepath) {
changedFiles[filepath] = action;
onChange();
});
// Register NPM tasks.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-stylelint');
// Register JS tasks.
grunt.registerTask('shifter', 'Run Shifter against the current directory', tasks.shifter);
grunt.registerTask('gherkinlint', 'Run gherkinlint against the current directory', tasks.gherkinlint);
grunt.registerTask('ignorefiles', 'Generate ignore files for linters', tasks.ignorefiles);
grunt.registerTask('yui', ['eslint:yui', 'shifter']);
grunt.registerTask('amd', ['eslint:amd', 'uglify']);
grunt.registerTask('js', ['amd', 'yui']);
// Register CSS taks.
grunt.registerTask('css', ['stylelint:scss', 'sass', 'stylelint:less', 'less:bootstrapbase', 'stylelint:css']);
// Register the startup task.
grunt.registerTask('startup', 'Run the correct tasks for the current directory', tasks.startup);
// Register the default task.
grunt.registerTask('default', ['startup']);
+35 -53
View File
@@ -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 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 wed like to
make it clear how Moodle-related projects, organisations, and people can use
the Moodle trademark. Wed 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 dont 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 youve 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 cant use "Moodle" in the name of your software (including Mobile apps)
* You cant use "Moodle" in your company name
* You cant use "Moodle" in your domain name
* You cant use "Moodle" in advertising-related keywords (such as Adsense)
* You cant 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/>.
+48
View File
@@ -0,0 +1,48 @@
<?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/>.
/**
* Admin settings search form
*
* @package admin
* @copyright 2016 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
require_once $CFG->libdir.'/formslib.php';
/**
* Admin settings search form
*
* @package admin
* @copyright 2016 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_settings_search_form extends moodleform {
function definition () {
$mform = $this->_form;
//$mform->addElement('header', 'settingsheader', get_string('search', 'admin'));
$elements = [];
$elements[] = $mform->createElement('text', 'query', get_string('query', 'admin'));
$elements[] = $mform->createElement('submit', 'search', get_string('search'));
$mform->addGroup($elements);
$mform->setType('query', PARAM_RAW);
$mform->setDefault('query', optional_param('query', '', PARAM_RAW));
}
}
+9 -16
View File
@@ -33,7 +33,8 @@ $confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/admin/antiviruses.php', array('action' => $action, 'antivirus' => $antivirus));
$PAGE->set_context(context_system::instance());
require_admin();
require_login();
require_capability('moodle/site:config', context_system::instance());
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageantiviruses";
@@ -54,19 +55,18 @@ if (!confirm_sesskey()) {
redirect($returnurl);
}
$needsupdate = false;
switch ($action) {
case 'disable':
// Remove from enabled list.
$class = \core_plugin_manager::resolve_plugininfo_class('antivirus');
$class::enable_plugin($antivirus, false);
$key = array_search($antivirus, $activeantiviruses);
unset($activeantiviruses[$key]);
break;
case 'enable':
// Add to enabled list.
if (!in_array($antivirus, $activeantiviruses)) {
$class = \core_plugin_manager::resolve_plugininfo_class('antivirus');
$class::enable_plugin($antivirus, true);
$activeantiviruses[] = $antivirus;
$activeantiviruses = array_unique($activeantiviruses);
}
break;
@@ -79,7 +79,6 @@ switch ($action) {
$fsave = $activeantiviruses[$key];
$activeantiviruses[$key] = $activeantiviruses[$key + 1];
$activeantiviruses[$key + 1] = $fsave;
$needsupdate = true;
}
}
break;
@@ -93,7 +92,6 @@ switch ($action) {
$fsave = $activeantiviruses[$key];
$activeantiviruses[$key] = $activeantiviruses[$key - 1];
$activeantiviruses[$key - 1] = $fsave;
$needsupdate = true;
}
}
break;
@@ -102,12 +100,7 @@ switch ($action) {
break;
}
if ($needsupdate) {
$new = implode(',', $activeantiviruses);
add_to_config_log('antiviruses', $CFG->antiviruses, $new, 'core');
set_config('antiviruses', $new);
core_plugin_manager::reset_caches();
}
set_config('antiviruses', implode(',', $activeantiviruses));
core_plugin_manager::reset_caches();
redirect ($returnurl);
redirect ($returnurl);
+29 -16
View File
@@ -11,7 +11,8 @@ require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/tablelib.php');
require_admin();
require_login();
require_capability('moodle/site:config', context_system::instance());
$returnurl = new moodle_url('/admin/settings.php', array('section'=>'manageauths'));
@@ -28,7 +29,7 @@ if (empty($CFG->auth)) {
}
if (!empty($auth) and !exists_auth_plugin($auth)) {
throw new \moodle_exception('pluginnotinstalled', 'auth', $returnurl, $auth);
print_error('pluginnotinstalled', 'auth', $returnurl, $auth);
}
////////////////////////////////////////////////////////////////////////////////
@@ -40,31 +41,43 @@ if (!confirm_sesskey()) {
switch ($action) {
case 'disable':
// Remove from enabled list.
$class = \core_plugin_manager::resolve_plugininfo_class('auth');
$class::enable_plugin($auth, false);
// remove from enabled list
$key = array_search($auth, $authsenabled);
if ($key !== false) {
unset($authsenabled[$key]);
set_config('auth', implode(',', $authsenabled));
}
if ($auth == $CFG->registerauth) {
set_config('registerauth', '');
}
\core\session\manager::gc(); // Remove stale sessions.
core_plugin_manager::reset_caches();
break;
case 'enable':
// Add to enabled list.
$class = \core_plugin_manager::resolve_plugininfo_class('auth');
$class::enable_plugin($auth, true);
// add to enabled list
if (!in_array($auth, $authsenabled)) {
$authsenabled[] = $auth;
$authsenabled = array_unique($authsenabled);
set_config('auth', implode(',', $authsenabled));
}
\core\session\manager::gc(); // Remove stale sessions.
core_plugin_manager::reset_caches();
break;
case 'down':
$key = array_search($auth, $authsenabled);
// check auth plugin is valid
if ($key === false) {
throw new \moodle_exception('pluginnotenabled', 'auth', $returnurl, $auth);
print_error('pluginnotenabled', 'auth', $returnurl, $auth);
}
// move down the list
if ($key < (count($authsenabled) - 1)) {
$fsave = $authsenabled[$key];
$authsenabled[$key] = $authsenabled[$key + 1];
$authsenabled[$key + 1] = $fsave;
$value = implode(',', $authsenabled);
add_to_config_log('auth', $CFG->auth, $value, 'core');
set_config('auth', $value);
set_config('auth', implode(',', $authsenabled));
}
break;
@@ -72,16 +85,14 @@ switch ($action) {
$key = array_search($auth, $authsenabled);
// check auth is valid
if ($key === false) {
throw new \moodle_exception('pluginnotenabled', 'auth', $returnurl, $auth);
print_error('pluginnotenabled', 'auth', $returnurl, $auth);
}
// move up the list
if ($key >= 1) {
$fsave = $authsenabled[$key];
$authsenabled[$key] = $authsenabled[$key - 1];
$authsenabled[$key - 1] = $fsave;
$value = implode(',', $authsenabled);
add_to_config_log('auth', $CFG->auth, $value, 'core');
set_config('auth', $value);
set_config('auth', implode(',', $authsenabled));
}
break;
@@ -90,3 +101,5 @@ switch ($action) {
}
redirect($returnurl);
+2
View File
@@ -171,6 +171,8 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
// limit for the setting name is 100.
continue;
}
} elseif ($fieldname == 'url') {
$fieldname = get_string('webpage');
} else {
$fieldname = get_string($fieldname);
}
+16 -17
View File
@@ -30,28 +30,26 @@
$strprotect = get_string('blockprotect', 'admin');
$strunprotect = get_string('blockunprotect', 'admin');
/// If data submitted, then process and store.
// 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');
if (!$block = $DB->get_record('block', array('id'=>$hide))) {
print_error('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);
$DB->set_field('block', 'visible', '0', array('id'=>$block->id)); // Hide block
add_to_config_log('block_visibility', $block->visible, '0', $block->name);
core_plugin_manager::reset_caches();
admin_get_root(true, false); // settings not required - only pages
}
if (!empty($show) && confirm_sesskey() ) {
if (!$block = $DB->get_record('block', ['id' => $show])) {
throw new \moodle_exception('blockdoesnotexist', 'error');
if (!$block = $DB->get_record('block', array('id'=>$show))) {
print_error('blockdoesnotexist', 'error');
}
$class = \core_plugin_manager::resolve_plugininfo_class('block');
$class::enable_plugin($block->name, true);
// Settings not required - only pages.
admin_get_root(true, false);
$DB->set_field('block', 'visible', '1', array('id'=>$block->id)); // Show block
add_to_config_log('block_visibility', $block->visible, '1', $block->name);
core_plugin_manager::reset_caches();
admin_get_root(true, false); // settings not required - only pages
}
if (!empty($protect) && confirm_sesskey()) {
@@ -69,13 +67,12 @@
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.
print_error('noblocks', 'error'); // Should never happen
}
$incompatible = array();
@@ -237,3 +234,5 @@
}
echo $OUTPUT->footer();
+11 -13
View File
@@ -30,6 +30,7 @@ $category = required_param('category', PARAM_SAFEDIR);
$return = optional_param('return','', PARAM_ALPHA);
$adminediting = optional_param('adminedit', -1, PARAM_BOOL);
/// no guest autologin
require_login(0, false);
$PAGE->set_context(context_system::instance());
$PAGE->set_url('/admin/category.php', array('category' => $category));
@@ -41,19 +42,13 @@ $adminroot = admin_get_root(); // need all settings
$settingspage = $adminroot->locate($category, true);
if (empty($settingspage) or !($settingspage instanceof admin_category)) {
throw new \moodle_exception('categoryerror', 'error', "$CFG->wwwroot/$CFG->admin/");
print_error('categoryerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
}
if (!($settingspage->check_access())) {
throw new \moodle_exception('accessdenied', 'admin');
print_error('accessdenied', 'admin');
}
$hassiteconfig = has_capability('moodle/site:config', $PAGE->context);
if ($hassiteconfig) {
$PAGE->add_header_action($OUTPUT->render_from_template('core_admin/header_search_input', [
'action' => new moodle_url('/admin/search.php'),
]));
}
$statusmsg = '';
$errormsg = '';
@@ -81,7 +76,7 @@ if ($PAGE->user_allowed_editing() && $adminediting != -1) {
$USER->editing = $adminediting;
}
$buttons = null;
if ($PAGE->user_allowed_editing() && !$PAGE->theme->haseditswitch) {
if ($PAGE->user_allowed_editing()) {
$url = clone($PAGE->url);
if ($PAGE->user_is_editing()) {
$caption = get_string('blockseditoff');
@@ -146,7 +141,13 @@ if ($errormsg !== '') {
echo $OUTPUT->notification($statusmsg, 'notifysuccess');
}
echo $OUTPUT->heading(get_string('admincategory', 'admin', $settingspage->visiblename), 2);
$path = array_reverse($settingspage->visiblepath);
if (is_array($path)) {
$visiblename = join(' / ', $path);
} else {
$visiblename = $path;
}
echo $OUTPUT->heading(get_string('admincategory', 'admin', $visiblename), 2);
echo html_writer::start_tag('form', array('action' => '', 'method' => 'post', 'id' => 'adminsettings'));
echo html_writer::start_tag('div');
@@ -158,7 +159,4 @@ echo $outputhtml;
echo html_writer::end_tag('fieldset');
echo html_writer::end_tag('form');
// Add the form change checker.
$PAGE->requires->js_call_amd('core_form/changechecker', 'watchFormById', ['adminsettings']);
echo $OUTPUT->footer();
-1
View File
@@ -50,7 +50,6 @@ class purge_caches extends \moodleform {
$mform->createElement('advcheckbox', 'theme', '', get_string('purgethemecache', 'admin')),
$mform->createElement('advcheckbox', 'lang', '', get_string('purgelangcache', 'admin')),
$mform->createElement('advcheckbox', 'js', '', get_string('purgejscache', 'admin')),
$mform->createElement('advcheckbox', 'template', '', get_string('purgetemplates', 'admin')),
$mform->createElement('advcheckbox', 'filter', '', get_string('purgefiltercache', 'admin')),
$mform->createElement('advcheckbox', 'muc', '', get_string('purgemuc', 'admin')),
$mform->createElement('advcheckbox', 'other', '', get_string('purgeothercaches', 'admin'))
@@ -1,92 +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/>.
/**
* Testing outgoing mail configuration form
*
* @package core
* @copyright 2019 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\form;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/formslib.php');
/**
* Test mail form
*
* @package core
* @copyright 2019 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class testoutgoingmailconf_form extends \moodleform {
/**
* Add elements to form
*/
public function definition() {
$mform = $this->_form;
// Recipient.
$options = ['maxlength' => '100', 'size' => '25', 'autocomplete' => 'email'];
$mform->addElement('text', 'recipient', get_string('testoutgoingmailconf_toemail', 'admin'), $options);
$mform->setType('recipient', PARAM_EMAIL);
$mform->addRule('recipient', get_string('required'), 'required');
// From user.
$options = ['maxlength' => '100', 'size' => '25'];
$mform->addElement('text', 'from', get_string('testoutgoingmailconf_fromemail', 'admin'), $options);
$mform->setType('from', PARAM_TEXT);
$mform->addHelpButton('from', 'testoutgoingmailconf_fromemail', 'admin');
// Additional subject text.
$options = ['size' => '25'];
$mform->addElement('text', 'additionalsubject', get_string('testoutgoingmailconf_subjectadditional', 'admin'), $options);
$mform->setType('additionalsubject', PARAM_TEXT);
$buttonarray = array();
$buttonarray[] = $mform->createElement('submit', 'send', get_string('testoutgoingmailconf_sendtest', 'admin'));
$buttonarray[] = $mform->createElement('cancel');
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
$mform->closeHeaderBefore('buttonar');
}
/**
* Validate Form field, should be a valid email format or a username that matches with a Moodle user.
*
* @param array $data
* @param array $files
* @return array
* @throws \dml_exception|\coding_exception
*/
public function validation($data, $files): array {
$errors = parent::validation($data, $files);
if (isset($data['from']) && $data['from']) {
$userfrom = \core_user::get_user_by_username($data['from']);
if (!$userfrom && !validate_email($data['from'])) {
$errors['from'] = get_string('testoutgoingmailconf_fromemail_invalid', 'admin');
}
}
return $errors;
}
}
@@ -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/>.
/**
* External admin page class that allows a callback to be provided to determine whether page can be accessed
*
* @package core_admin
* @copyright 2019 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\local\externalpage;
use admin_externalpage;
defined('MOODLE_INTERNAL') || die();
require_once("{$CFG->libdir}/adminlib.php");
/**
* Admin externalpage class
*
* @package core_admin
* @copyright 2019 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class accesscallback extends admin_externalpage {
/** @var callable $accesscheckcallback */
protected $accesscheckcallback;
/**
* Class constructor
*
* @param string $name
* @param string $visiblename
* @param string $url
* @param callable $accesscheckcallback The callback method that will be executed to check whether user has access to
* this page. The setting instance ($this) is passed as an argument to the callback. Should return boolean value
* @param bool $hidden
*/
public function __construct(string $name, string $visiblename, string $url, callable $accesscheckcallback,
bool $hidden = false) {
$this->accesscheckcallback = $accesscheckcallback;
parent::__construct($name, $visiblename, $url, [], $hidden);
}
/**
* Determines if the current user has access to this external page based on access callback
*
* @return bool
*/
public function check_access() {
return ($this->accesscheckcallback)($this);
}
}
@@ -1,206 +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/>.
/**
* Auto complete admin setting.
*
* @package core_admin
* @copyright 2020 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\local\settings;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/adminlib.php');
/**
* Auto complete setting class.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @copyright 2020 The Open University
*/
class autocomplete extends \admin_setting_configmultiselect {
/** @var boolean Should we allow typing new entries to the field? */
protected $tags = false;
/** @var string Name of an AMD module to send/process ajax requests. */
protected $ajax = '';
/** @var string Placeholder text for an empty list. */
protected $placeholder = '';
/** @var bool Whether the search has to be case-sensitive. */
protected $casesensitive = false;
/** @var bool Show suggestions by default - but this can be turned off. */
protected $showsuggestions = true;
/** @var string String that is shown when there are no selections. */
protected $noselectionstring = '';
/** @var string Delimiter to store values in database. */
protected $delimiter = ',';
/** @var string Should be multiple choices? */
protected $multiple = true;
/** @var string The link to manage choices. */
protected $manageurl = true;
/** @var string The text to display in manage link. */
protected $managetext = true;
/**
* Constructor
*
* @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting'
* for ones in config_plugins.
* @param string $visiblename localised
* @param string $description long localised info
* @param array $defaultsetting array of selected items
* @param array $choices options for autocomplete field
* @param array $attributes settings for autocomplete field
*/
public function __construct($name, $visiblename, $description, $defaultsetting, $choices, $attributes = null) {
if ($attributes === null) {
$attributes = [];
}
$this->placeholder = get_string('search');
$this->noselectionstring = get_string('noselection', 'form');
$defaultattributes = [
'tags',
'showsuggestions',
'placeholder',
'noselectionstring',
'ajax',
'casesensitive',
'delimiter',
'multiple',
'manageurl',
'managetext'
];
foreach ($defaultattributes as $attributename) {
if (isset($attributes[$attributename])) {
$this->$attributename = $attributes[$attributename];
}
}
parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
}
/**
* Returns the select setting(s)
*
* @return mixed null or array. Null if no settings else array of setting(s)
*/
public function get_setting() {
$result = $this->config_read($this->name);
if (is_null($result)) {
return null;
}
if ($result === '') {
return [];
}
return explode($this->delimiter, $result);
}
/**
* Saves setting(s) provided through $data
*
* @param array $data
*/
public function write_setting($data) {
if (!is_array($data)) {
return ''; // Ignore it.
}
if (!$this->load_choices() || empty($this->choices)) {
return '';
}
unset($data['xxxxx']);
$save = [];
foreach ($data as $value) {
if (!array_key_exists($value, $this->choices)) {
continue; // Ignore it.
}
$save[] = $value;
}
return ($this->config_write($this->name, implode($this->delimiter, $save)) ? '' : get_string('errorsetting', 'admin'));
}
/**
* Returns XHTML autocomplete field
*
* @param array $data Array of values to select by default
* @param string $query
* @return string XHTML autocomplete field
*/
public function output_html($data, $query = '') {
global $OUTPUT;
if (!$this->load_choices() or empty($this->choices)) {
return '';
}
$default = $this->get_defaultsetting();
if (empty($default)) {
$default = [];
}
if (is_null($data)) {
$data = [];
}
$context = [
'id' => $this->get_id(),
'name' => $this->get_full_name()
];
$defaults = [];
$options = [];
$template = 'core_admin/local/settings/autocomplete';
foreach ($this->choices as $value => $name) {
if (in_array($value, $default)) {
$defaults[] = $name;
}
$options[] = [
'value' => $value,
'text' => $name,
'selected' => in_array($value, $data),
'disabled' => false
];
}
$context['options'] = $options;
$context['tags'] = $this->tags;
$context['placeholder'] = $this->placeholder;
$context['casesensitive'] = $this->casesensitive;
$context['multiple'] = $this->multiple;
$context['showsuggestions'] = $this->showsuggestions;
$context['manageurl'] = $this->manageurl;
$context['managetext'] = $this->managetext;
if (is_null($default)) {
$defaultinfo = null;
} if (!empty($defaults)) {
$defaultinfo = implode(', ', $defaults);
} else {
$defaultinfo = get_string('none');
}
$element = $OUTPUT->render_from_template($template, $context);
return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
}
}
-197
View File
@@ -1,197 +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/>.
/**
* File size admin setting.
*
* @package core_admin
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\local\settings;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/adminlib.php');
/**
* An admin setting to support entering and displaying of file sizes in Bytes, KB, MB or GB.
*
* @copyright 2019 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class filesize extends \admin_setting {
/** @var int The byte unit. Number of bytes in a byte */
const UNIT_B = 1;
/** @var int The kilobyte unit (number of bytes in a kilobyte) */
const UNIT_KB = 1024;
/** @var int The megabyte unit (number of bytes in a megabyte) */
const UNIT_MB = 1048576;
/** @var int The gigabyte unit (number of bytes in a gigabyte) */
const UNIT_GB = 1073741824;
/** @var int default size unit */
protected $defaultunit;
/**
* Constructor
*
* @param string $name unique ascii name, either 'mysetting' for settings that in config,
* or 'myplugin/mysetting' for ones in config_plugins.
* @param string $visiblename localised name
* @param string $description localised long description
* @param int|null $defaultvalue Value of the settings in bytes
* @param int|null $defaultunit GB, MB, etc. (in bytes)
*/
public function __construct(string $name, string $visiblename, string $description,
int $defaultvalue = null, int $defaultunit = null) {
$defaultsetting = self::parse_bytes($defaultvalue);
if ($defaultunit && array_key_exists($defaultunit, self::get_units())) {
$this->defaultunit = $defaultunit;
} else {
$this->defaultunit = self::UNIT_MB;
}
parent::__construct($name, $visiblename, $description, $defaultsetting);
}
/**
* Returns selectable units.
*
* @return array
*/
protected static function get_units(): array {
return [
self::UNIT_GB => get_string('sizegb'),
self::UNIT_MB => get_string('sizemb'),
self::UNIT_KB => get_string('sizekb'),
self::UNIT_B => get_string('sizeb'),
];
}
/**
* Converts bytes to some more user friendly string.
*
* @param int $bytes The number of bytes we want to convert from
* @return string
*/
protected static function get_size_text(int $bytes): string {
if (empty($bytes)) {
return get_string('none');
}
return display_size($bytes, 0);
}
/**
* Finds suitable units for given file size.
*
* @param int $bytes The number of bytes
* @return array Parsed file size in the format of ['v' => value, 'u' => unit]
*/
protected static function parse_bytes(int $bytes): array {
foreach (self::get_units() as $unit => $unused) {
if ($bytes % $unit === 0) {
return ['v' => (int)($bytes / $unit), 'u' => $unit];
}
}
return ['v' => (int)$bytes, 'u' => self::UNIT_B];
}
/**
* Get the selected file size as array.
*
* @return array|null An array containing 'v' => xx, 'u' => xx, or null if not set
*/
public function get_setting(): ?array {
$bytes = $this->config_read($this->name);
if (is_null($bytes)) {
return null;
}
$bytes = intval($bytes);
return self::parse_bytes($bytes);
}
/**
* Store the file size as bytes.
*
* @param array $data Must be form 'h' => xx, 'm' => xx
* @return string The error string if any
*/
public function write_setting($data): string {
if (!is_array($data)) {
return '';
}
if (!is_numeric($data['v']) || $data['v'] < 0) {
return get_string('errorsetting', 'admin');
}
// Calculate size in bytes, ensuring we don't overflow PHP_INT_MAX.
$bytes = $data['v'] * $data['u'];
$result = (is_int($bytes) && $this->config_write($this->name, $bytes));
return ($result ? '' : get_string('errorsetting', 'admin'));
}
/**
* Returns file size text+select fields.
*
* @param array $data The current setting value. Must be form 'v' => xx, 'u' => xx.
* @param string $query Admin search query to be highlighted.
* @return string File size text+select fields and wrapping div(s).
*/
public function output_html($data, $query = ''): string {
global $OUTPUT;
$default = $this->get_defaultsetting();
if (is_number($default)) {
$defaultinfo = self::get_size_text($default);
} else if (is_array($default)) {
$defaultinfo = self::get_size_text($default['v'] * $default['u']);
} else {
$defaultinfo = null;
}
$inputid = $this->get_id() . 'v';
$units = self::get_units();
$defaultunit = $this->defaultunit;
$context = (object) [
'id' => $this->get_id(),
'name' => $this->get_full_name(),
'value' => $data['v'],
'readonly' => $this->is_readonly(),
'options' => array_map(function($unit, $title) use ($data, $defaultunit) {
return [
'value' => $unit,
'name' => $title,
'selected' => ($data['v'] == 0 && $unit == $defaultunit) || $unit == $data['u']
];
}, array_keys($units), $units)
];
$element = $OUTPUT->render_from_template('core_admin/setting_configfilesize', $context);
return format_admin_setting($this, $this->visiblename, $element, $this->description, $inputid, '', $defaultinfo, $query);
}
}
@@ -1,37 +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/>.
/**
* A settings page which can be viewed with a link directly.
*
* @package core_admin
* @copyright 2021 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\local\settings;
use moodle_url;
interface linkable_settings_page {
/**
* Get the URL to view this settings page.
*
* @return moodle_url
*/
public function get_settings_page_url(): moodle_url;
}
@@ -1,74 +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/>.
/**
* Payment gateway admin setting.
*
* @package core_admin
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\local\settings;
/**
* Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
*/
class manage_payment_gateway_plugins extends \admin_setting_manage_plugins {
/**
* Get the admin settings section title (use get_string).
*
* @return string
*/
public function get_section_title() {
return get_string('type_paygw_plural', 'plugin');
}
/**
* Get the type of plugin to manage.
*
* @return string
*/
public function get_plugin_type() {
return 'paygw';
}
/**
* Get the name of the second column.
*
* @return string
*/
public function get_info_column_name() {
return get_string('supportedcurrencies', 'core_payment');
}
/**
* Get the type of plugin to manage.
*
* @param plugininfo The plugin info class.
* @return string
*/
public function get_info_column($plugininfo) {
$codes = $plugininfo->get_supported_currencies();
$currencies = [];
foreach ($codes as $c) {
$currencies[$c] = new \lang_string($c, 'core_currencies');
}
return implode(get_string('listsep', 'langconfig') . ' ', $currencies);
}
}
@@ -1,121 +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/>.
/**
* Admin setting to show current scheduled task's status.
*
* @package core
* @copyright 2021 Universitat Rovira i Virgili
* @author Jordi Pujol-Ahulló <jpahullo@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\local\settings;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->libdir . '/moodlelib.php');
use admin_setting_description;
use core\task\manager;
use core\task\scheduled_task;
use html_writer;
use lang_string;
use moodle_url;
use stdClass;
/**
* This admin setting tells whether a given scheduled task is enabled, providing a link to its configuration page.
*
* The goal of this setting is to help contextualizing the configuration settings with related scheduled task status,
* providing the big picture of that part of the system.
*
* @package core
* @copyright 2021 Universitat Rovira i Virgili
* @author Jordi Pujol-Ahulló <jpahullo@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class setting_scheduled_task_status extends admin_setting_description {
/**
* @var string fully qualified class name of a scheduled task.
*/
private $classname;
/**
* @var string additional text to append to the description.
*/
private $extradescription;
/**
* setting_scheduled_task_status constructor.
* @param string $name unique setting name.
* @param string $scheduledtaskclassname full classpath class name of the scheduled task.
* @param string $extradescription extra detail to append to the scheduled task status to add context in the setting
* page.
*/
public function __construct(string $name, string $scheduledtaskclassname, string $extradescription = '') {
$visiblename = new lang_string('task_status', 'admin');
$this->classname = $scheduledtaskclassname;
$this->extradescription = $extradescription;
parent::__construct($name, $visiblename, '');
}
/**
* Calculates lazily the content of the description.
* @param mixed $data nothing expected in this case.
* @param string $query nothing expected in this case.
* @return string the HTML content to print for this setting.
*/
public function output_html($data, $query = ''): string {
if (empty($this->description)) {
$this->description = $this->get_task_description();
}
return parent::output_html($data, $query);
}
/**
* Returns the HTML to print as the description.
* @return string description to be printed.
*/
private function get_task_description(): string {
$task = manager::get_scheduled_task($this->classname);
if ($task->is_enabled()) {
$taskenabled = get_string('enabled', 'admin');
} else {
$taskenabled = get_string('disabled', 'admin');
}
$taskenabled = strtolower($taskenabled);
$gotourl = new moodle_url(
'/admin/tool/task/scheduledtasks.php',
[],
scheduled_task::get_html_id($this->classname)
);
if (!empty($this->extradescription)) {
$this->extradescription = '<br />' . $this->extradescription;
}
$taskdetail = new stdClass();
$taskdetail->class = $this->classname;
$taskdetail->name = $task->get_name();
$taskdetail->status = $taskenabled;
$taskdetail->gotourl = $gotourl->out(false);
$taskdetail->extradescription = $this->extradescription;
return html_writer::tag('p', get_string('task_status_desc', 'admin', $taskdetail));
}
}
@@ -1,117 +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\datasource;
use core_admin\reportbuilder\local\entities\task_log;
use core_reportbuilder\datasource;
use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\filters\select;
/**
* Task logs datasource
*
* @package core_admin
* @copyright 2022 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class task_logs extends datasource {
/**
* Return user friendly name of the report source
*
* @return string
*/
public static function get_name(): string {
return get_string('tasklogs', 'core_admin');
}
/**
* Initialise report
*/
protected function initialise(): void {
$tasklogentity = new task_log();
$tasklogalias = $tasklogentity->get_table_alias('task_log');
$this->set_main_table('task_log', $tasklogalias);
$this->add_entity($tasklogentity);
// Join the user entity to represent the associated user.
$userentity = new user();
$useralias = $userentity->get_table_alias('user');
$this->add_entity($userentity->add_join("
LEFT JOIN {user} {$useralias}
ON {$useralias}.id = {$tasklogalias}.userid")
);
// Add report elements from each of the entities we added to the report.
$this->add_all_from_entities();
}
/**
* Return the columns that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_columns(): array {
return [
'task_log:name',
'task_log:starttime',
'task_log:duration',
'task_log:result',
];
}
/**
* Return the filters that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_filters(): array {
return [
'task_log:timestart',
'task_log:result',
];
}
/**
* Return the conditions that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_conditions(): array {
return [
'task_log:type',
'task_log:timestart',
'task_log:result',
];
}
/**
* Return the condition values that will be set for the report upon creation
*
* @return array
*/
public function get_default_condition_values(): array {
return [
'task_log:type_operator' => select::EQUAL_TO,
'task_log:type_value' => \core\task\database_logger::TYPE_SCHEDULED,
];
}
}
@@ -1,427 +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\entities;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\filters\duration;
use core_reportbuilder\local\filters\number;
use core_reportbuilder\local\filters\select;
use core_reportbuilder\local\filters\text;
use core_reportbuilder\local\filters\autocomplete;
use core_reportbuilder\local\helpers\format;
use lang_string;
use core_reportbuilder\local\entities\base;
use core_reportbuilder\local\report\column;
use core_reportbuilder\local\report\filter;
use stdClass;
use core_collator;
/**
* Task log entity class implementation
*
* @package core_admin
* @copyright 2021 David Matamoros <davidmc@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class task_log extends base {
/** @var int Result success */
protected const SUCCESS = 0;
/** @var int Result failed */
protected const FAILED = 1;
/**
* Database tables that this entity uses and their default aliases
*
* @return array
*/
protected function get_default_table_aliases(): array {
return ['task_log' => 'tl'];
}
/**
* The default title for this entity in the list of columns/conditions/filters in the report builder
*
* @return lang_string
*/
protected function get_default_entity_title(): lang_string {
return new lang_string('entitytasklog', 'admin');
}
/**
* Initialise the entity
*
* @return base
*/
public function initialise(): base {
$columns = $this->get_all_columns();
foreach ($columns as $column) {
$this->add_column($column);
}
// All the filters defined by the entity can also be used as conditions.
$filters = $this->get_all_filters();
foreach ($filters as $filter) {
$this
->add_filter($filter)
->add_condition($filter);
}
return $this;
}
/**
* Returns list of all available columns
*
* @return column[]
*/
protected function get_all_columns(): array {
global $DB;
$tablealias = $this->get_table_alias('task_log');
// Name column.
$columns[] = (new column(
'name',
new lang_string('name'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_field("$tablealias.classname")
->set_is_sortable(true)
->add_callback(static function(string $classname): string {
$output = '';
if (class_exists($classname)) {
$task = new $classname;
if ($task instanceof \core\task\task_base) {
$output = $task->get_name();
}
}
$output .= \html_writer::tag('div', "\\{$classname}", [
'class' => 'small text-muted',
]);
return $output;
});
// Component column.
$columns[] = (new column(
'component',
new lang_string('plugin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_field("{$tablealias}.component")
->set_is_sortable(true);
// Type column.
$columns[] = (new column(
'type',
new lang_string('tasktype', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_field("{$tablealias}.type")
->set_is_sortable(true)
->add_callback(static function($value): string {
if (\core\task\database_logger::TYPE_SCHEDULED === (int) $value) {
return get_string('task_type:scheduled', 'admin');
}
return get_string('task_type:adhoc', 'admin');
});
// Start time column.
$columns[] = (new column(
'starttime',
new lang_string('task_starttime', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TIMESTAMP)
->add_field("{$tablealias}.timestart")
->set_is_sortable(true)
->add_callback([format::class, 'userdate'], get_string('strftimedatetimeshortaccurate', 'core_langconfig'));
// End time column.
$columns[] = (new column(
'endtime',
new lang_string('task_endtime', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TIMESTAMP)
->add_field("{$tablealias}.timeend")
->set_is_sortable(true)
->add_callback([format::class, 'userdate'], get_string('strftimedatetimeshortaccurate', 'core_langconfig'));
// Duration column.
$columns[] = (new column(
'duration',
new lang_string('task_duration', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_FLOAT)
->add_field("{$tablealias}.timeend - {$tablealias}.timestart", 'duration')
->set_is_sortable(true)
->add_callback(static function(float $value): string {
$duration = round($value, 2);
if (empty($duration)) {
// The format_time function returns 'now' when the difference is exactly 0.
// Note: format_time performs concatenation in exactly this fashion so we should do this for consistency.
return '0 ' . get_string('secs', 'moodle');
}
return format_time($duration);
});
// Hostname column.
$columns[] = (new column(
'hostname',
new lang_string('hostname', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_field("$tablealias.hostname")
->set_is_sortable(true);
// PID column.
$columns[] = (new column(
'pid',
new lang_string('pid', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_field("{$tablealias}.pid")
->set_is_sortable(true)
// Although this is an integer column, it doesn't make sense to perform numeric aggregation on it.
->set_disabled_aggregation(['avg', 'count', 'countdistinct', 'max', 'min', 'sum']);
// Database column.
$columns[] = (new column(
'database',
new lang_string('task_dbstats', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_fields("{$tablealias}.dbreads, {$tablealias}.dbwrites")
->set_is_sortable(true, ["{$tablealias}.dbreads", "{$tablealias}.dbwrites"])
->add_callback(static function(int $value, stdClass $row): string {
$output = '';
$output .= \html_writer::div(get_string('task_stats:dbreads', 'admin', $row->dbreads));
$output .= \html_writer::div(get_string('task_stats:dbwrites', 'admin', $row->dbwrites));
return $output;
})
// Although this is an integer column, it doesn't make sense to perform numeric aggregation on it.
->set_disabled_aggregation(['avg', 'count', 'countdistinct', 'max', 'min', 'sum']);
// Database reads column.
$columns[] = (new column(
'dbreads',
new lang_string('task_dbreads', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_fields("{$tablealias}.dbreads")
->set_is_sortable(true);
// Database writes column.
$columns[] = (new column(
'dbwrites',
new lang_string('task_dbwrites', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_fields("{$tablealias}.dbwrites")
->set_is_sortable(true);
// Result column.
$columns[] = (new column(
'result',
new lang_string('task_result', 'admin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_BOOLEAN)
// For accurate aggregation, we need to return boolean success = true by xor'ing the field value.
->add_field($DB->sql_bitxor("{$tablealias}.result", 1), 'success')
->set_is_sortable(true)
->add_callback(static function(bool $success): string {
if (!$success) {
return get_string('task_result:failed', 'admin');
}
return get_string('success');
});
return $columns;
}
/**
* Return list of all available filters
*
* @return filter[]
*/
protected function get_all_filters(): array {
global $DB;
$tablealias = $this->get_table_alias('task_log');
// Name filter (Filter by classname).
$filters[] = (new filter(
autocomplete::class,
'name',
new lang_string('classname', 'tool_task'),
$this->get_entity_name(),
"{$tablealias}.classname"
))
->add_joins($this->get_joins())
->set_options_callback(static function(): array {
global $DB;
$classnames = $DB->get_fieldset_sql('SELECT DISTINCT classname FROM {task_log} ORDER BY classname ASC');
$options = [];
foreach ($classnames as $classname) {
if (class_exists($classname)) {
$task = new $classname;
$options[$classname] = $task->get_name();
}
}
core_collator::asort($options);
return $options;
});
// Component filter.
$filters[] = (new filter(
text::class,
'component',
new lang_string('plugin'),
$this->get_entity_name(),
"{$tablealias}.component"
))
->add_joins($this->get_joins());
// Type filter.
$filters[] = (new filter(
select::class,
'type',
new lang_string('tasktype', 'admin'),
$this->get_entity_name(),
"{$tablealias}.type"
))
->add_joins($this->get_joins())
->set_options([
\core\task\database_logger::TYPE_ADHOC => new lang_string('task_type:adhoc', 'admin'),
\core\task\database_logger::TYPE_SCHEDULED => new lang_string('task_type:scheduled', 'admin'),
]);
// Output filter (Filter by task output).
$filters[] = (new filter(
text::class,
'output',
new lang_string('task_logoutput', 'admin'),
$this->get_entity_name(),
$DB->sql_cast_to_char("{$tablealias}.output")
))
->add_joins($this->get_joins());
// Start time filter.
$filters[] = (new filter(
date::class,
'timestart',
new lang_string('task_starttime', 'admin'),
$this->get_entity_name(),
"{$tablealias}.timestart"
))
->add_joins($this->get_joins())
->set_limited_operators([
date::DATE_ANY,
date::DATE_RANGE,
date::DATE_PREVIOUS,
date::DATE_CURRENT,
]);
// End time.
$filters[] = (new filter(
date::class,
'timeend',
new lang_string('task_endtime', 'admin'),
$this->get_entity_name(),
"{$tablealias}.timeend"
))
->add_joins($this->get_joins())
->set_limited_operators([
date::DATE_ANY,
date::DATE_RANGE,
date::DATE_PREVIOUS,
date::DATE_CURRENT,
]);
// Duration filter.
$filters[] = (new filter(
duration::class,
'duration',
new lang_string('task_duration', 'admin'),
$this->get_entity_name(),
"{$tablealias}.timeend - {$tablealias}.timestart"
))
->add_joins($this->get_joins());
// Database reads.
$filters[] = (new filter(
number::class,
'dbreads',
new lang_string('task_dbreads', 'admin'),
$this->get_entity_name(),
"{$tablealias}.dbreads"
))
->add_joins($this->get_joins());
// Database writes.
$filters[] = (new filter(
number::class,
'dbwrites',
new lang_string('task_dbwrites', 'admin'),
$this->get_entity_name(),
"{$tablealias}.dbwrites"
))
->add_joins($this->get_joins());
// Result filter.
$filters[] = (new filter(
select::class,
'result',
new lang_string('task_result', 'admin'),
$this->get_entity_name(),
"{$tablealias}.result"
))
->add_joins($this->get_joins())
->set_options([
self::SUCCESS => get_string('success'),
self::FAILED => get_string('task_result:failed', 'admin'),
]);
return $filters;
}
}
@@ -1,159 +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 context_system;
use core_admin\reportbuilder\local\entities\task_log;
use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\report\action;
use lang_string;
use moodle_url;
use pix_icon;
use core_reportbuilder\system_report;
/**
* Task logs system report class implementation
*
* @package core_admin
* @copyright 2021 David Matamoros <davidmc@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class task_logs extends system_report {
/**
* Initialise report, we need to set the main table, load our entities and set columns/filters
*/
protected function initialise(): void {
// Our main entity, it contains all of the column definitions that we need.
$entitymain = new task_log();
$entitymainalias = $entitymain->get_table_alias('task_log');
$this->set_main_table('task_log', $entitymainalias);
$this->add_entity($entitymain);
// Any columns required by actions should be defined here to ensure they're always available.
$this->add_base_fields("{$entitymainalias}.id");
// We can join the "user" entity to our "main" entity and use the fullname column from the user entity.
$entityuser = new user();
$entituseralias = $entityuser->get_table_alias('user');
$this->add_entity($entityuser->add_join(
"LEFT JOIN {user} {$entituseralias} ON {$entituseralias}.id = {$entitymainalias}.userid"
));
// 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, get_string('tasklogs', 'admin'));
}
/**
* Validates access to view this report
*
* @return bool
*/
protected function can_view(): bool {
return has_capability('moodle/site:config', context_system::instance());
}
/**
* Get the visible name of the report
*
* @return string
*/
public static function get_name(): string {
return get_string('entitytasklog', 'admin');
}
/**
* 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 {
$columns = [
'task_log:name',
'task_log:type',
'user:fullname',
'task_log:starttime',
'task_log:duration',
'task_log:hostname',
'task_log:pid',
'task_log:database',
'task_log:result',
];
$this->add_columns_from_entities($columns);
// It's possible to override the display name of a column, if you don't want to use the value provided by the entity.
if ($column = $this->get_column('user:fullname')) {
$column->set_title(new lang_string('user', 'admin'));
}
// It's possible to set a default initial sort direction for one column.
$this->set_initial_sort_column('task_log:starttime', SORT_DESC);
}
/**
* 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 {
$filters = [
'task_log:name',
'task_log:type',
'task_log:output',
'task_log:result',
'task_log:timestart',
'task_log:duration',
];
$this->add_filters_from_entities($filters);
}
/**
* 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 {
// Action to view individual task log on a popup window.
$this->add_action((new action(
new moodle_url('/admin/tasklogs.php', ['logid' => ':id']),
new pix_icon('e/search', ''),
[],
true,
new lang_string('view'),
)));
// Action to download individual task log.
$this->add_action((new action(
new moodle_url('/admin/tasklogs.php', ['logid' => ':id', 'download' => true]),
new pix_icon('t/download', ''),
[],
false,
new lang_string('download'),
)));
}
}
-131
View File
@@ -1,131 +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/>.
/**
* Task executor for adhoc tasks.
*
* @package core
* @subpackage cli
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @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");
require_once("{$CFG->libdir}/cronlib.php");
list($options, $unrecognized) = cli_get_params(
[
'execute' => false,
'help' => false,
'keep-alive' => 0,
'showsql' => false,
'showdebugging' => false,
'ignorelimits' => false,
'force' => false,
], [
'h' => 'help',
'e' => 'execute',
'k' => 'keep-alive',
'i' => 'ignorelimits',
'f' => 'force',
]
);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] or empty($options['execute'])) {
$help = <<<EOT
Ad hoc cron tasks.
Options:
-h, --help Print out this help
--showsql Show sql queries before they are executed
--showdebugging Show developer level debugging information
-e, --execute Run all queued adhoc tasks
-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
Example:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --execute
EOT;
echo $help;
die;
}
if ($options['showdebugging']) {
set_debugging(DEBUG_DEVELOPER, true);
}
if ($options['showsql']) {
$DB->set_debug(true);
}
if (CLI_MAINTENANCE) {
echo "CLI maintenance mode active, cron execution suspended.\n";
exit(1);
}
if (moodle_needs_upgrading()) {
echo "Moodle upgrade pending, cron execution suspended.\n";
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);
}
if (empty($options['keep-alive'])) {
$options['keep-alive'] = 0;
}
if (!empty($CFG->showcronsql)) {
$DB->set_debug(true);
}
if (!empty($CFG->showcrondebugging)) {
set_debugging(DEBUG_DEVELOPER, true);
}
$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.
cron_setup_user();
$humantimenow = date('r', time());
$keepalive = (int)$options['keep-alive'];
\core\local\cli\shutdown::script_supports_graceful_exit();
mtrace("Server Time: {$humantimenow}\n");
cron_run_adhoc_tasks(time(), $keepalive, $checklimits);
+3 -15
View File
@@ -83,7 +83,7 @@ Examples:
Stores the given configuration variable in the shell variable, escaped
so that it can be safely used as a shell argument.
# php cfg.php --name=theme --set=classic
# php cfg.php --name=theme --set=clean
Sets the given configuration variable to the given value.
# php cfg.php --name=noemailever --unset
@@ -120,23 +120,11 @@ if ($options['unset'] || $options['set'] !== null) {
}
// Check that the variable is not hard-set in the main config.php already.
$component = $options['component'];
if (!empty($component)) {
$componentsettings = $CFG->forced_plugin_settings[$component] ?? [];
$settinginconfig = array_key_exists($options['name'], $componentsettings);
} else {
$settinginconfig = array_key_exists($options['name'], $CFG->config_php_settings);
}
if ($settinginconfig) {
if (array_key_exists($options['name'], $CFG->config_php_settings)) {
cli_error('The configuration variable is hard-set in the config.php, unable to change.', 4);
}
$new = $options['set'];
$old = get_config($options['component'], $options['name']);
if ($new !== $old) {
set_config($options['name'], $options['set'], $options['component']);
add_to_config_log($options['name'], $old, $new, $options['component']);
}
set_config($options['name'], $options['set'], $options['component']);
exit(0);
}
-171
View File
@@ -1,171 +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/>.
/**
* CLI tool for system checks
*
* @package core
* @category check
* @copyright 2020 Brendan Heywood (brendan@catalyst-au.net)
* @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');
use core\check\result;
list($options, $unrecognized) = cli_get_params([
'help' => false,
'filter' => '',
'type' => 'status',
'verbose' => false,
], [
'h' => 'help',
'f' => 'filter',
'v' => 'verbose',
't' => 'type',
]);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
$checks = \core\check\manager::get_checks($options['type']);
$types = join(', ', \core\check\manager::TYPES);
$help = "Run Moodle system checks
Options:
-h, --help Print out this help
-f, --filter Filter to a subset of checks
-t, --type Which set of checks? Defaults to 'status'
One of $types
-v, --verbose Show details of all checks, not just failed checks
Example:
sudo -u www-data php admin/cli/checks.php
sudo -u www-data php admin/cli/checks.php -v
sudo -u www-data php admin/cli/checks.php -v --filter=environment
";
if ($options['help']) {
echo $help;
die();
}
$filter = $options['filter'];
if ($filter) {
$checks = array_filter($checks, function($check, $key) use ($filter) {
$ref = $check->get_ref();
return (strpos($ref, $filter) !== false);
}, 1);
}
// These shell exit codes and labels align with the NRPE standard.
$exitcodes = [
result::NA => 0,
result::OK => 0,
result::INFO => 0,
result::UNKNOWN => 3,
result::WARNING => 1,
result::ERROR => 2,
result::CRITICAL => 2,
];
$exitlabel = [
result::NA => 'OK',
result::OK => 'OK',
result::INFO => 'OK',
result::UNKNOWN => 'UNKNOWN',
result::WARNING => 'WARNING',
result::ERROR => 'CRITICAL',
result::CRITICAL => 'CRITICAL',
];
$format = "% 10s| % -60s\n";
$spacer = "----------+--------------------------------------------------------------------\n";
$prefix = ' |';
$output = '';
$header = $exitlabel[result::OK] . ': ' . get_string('checksok', '', $options['type']) . "\n";
$exitcode = $exitcodes[result::OK];
foreach ($checks as $check) {
$ref = $check->get_ref();
$result = $check->get_result();
$status = $result->get_status();
$checkexitcode = $exitcodes[$status];
// Summary is treated as html.
$summary = $result->get_summary();
$summary = html_to_text($summary, 60, false);
if ($checkexitcode > $exitcode) {
$exitcode = $checkexitcode;
$header = $exitlabel[$status] . ': ' . $check->get_name() . " (" . $check->get_ref() . ")\n";
}
if (empty($messages[$status])) {
$messages[$status] = $result;
}
$len = strlen(get_string('status' . $status));
if ($options['verbose'] ||
$status == result::WARNING ||
$status == result::CRITICAL ||
$status == result::ERROR) {
$output .= sprintf(
$format,
$OUTPUT->check_result($result),
sprintf('%s (%s)', $check->get_name(), $ref)
);
$summary = str_replace("\n", "\n" . $prefix . ' ', $summary);
$output .= sprintf( $format, '', ' ' . $summary);
if ($options['verbose']) {
$actionlink = $check->get_action_link();
if ($actionlink) {
$output .= sprintf( $format, '', ' ' . $actionlink->url);
}
$output .= sprintf( $format, '', '');
}
}
}
// Print NRPE header.
print $header;
// Only show the table header if there is anything to show.
if ($output) {
print sprintf($format,
get_string('status'). ' ',
get_string('check')
) . $spacer;
print $output;
}
// NRPE shell exit code.
exit($exitcode);
+3 -120
View File
@@ -35,25 +35,8 @@ 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(
[
'help' => false,
'stop' => false,
'list' => false,
'force' => false,
'enable' => false,
'disable' => false,
'disable-wait' => false,
], [
'h' => 'help',
's' => 'stop',
'l' => 'list',
'f' => 'force',
'e' => 'enable',
'd' => 'disable',
'w' => 'disable-wait',
]
);
list($options, $unrecognized) = cli_get_params(array('help'=>false),
array('h'=>'help'));
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
@@ -65,13 +48,7 @@ if ($options['help']) {
"Execute periodic cron actions.
Options:
-h, --help Print out this help
-s, --stop Notify all other running cron processes to stop after the current task
-l, --list Show the list of currently running tasks and how long they have been running
-f, --force Execute task even if cron is disabled
-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)
-h, --help Print out this help
Example:
\$sudo -u www-data /usr/bin/php admin/cli/cron.php
@@ -81,98 +58,4 @@ Example:
die;
}
if ($options['stop']) {
// By clearing the caches this signals to other running processes
// to exit after finishing the current task.
\core\task\manager::clear_static_caches();
die;
}
if ($options['enable']) {
set_config('cron_enabled', 1);
mtrace('Cron has been enabled for the site.');
exit(0);
}
if ($options['disable']) {
set_config('cron_enabled', 0);
\core\task\manager::clear_static_caches();
mtrace('Cron has been disabled for the site.');
exit(0);
}
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,
'PID',
'HOST',
'TYPE',
'TIME',
'CLASSNAME'
);
foreach ($tasks as $task) {
printf ($format,
$task->pid,
substr($task->hostname, 0, 12),
$task->type,
format_time(time() - $task->timestarted),
substr($task->classname, 0, 52)
);
}
exit(0);
}
if ($wait = $options['disable-wait']) {
$started = time();
if (true === $wait) {
// Default waiting time.
$waitsec = 600;
} else {
$waitsec = $wait;
$wait = true;
}
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.');
$lastcount = 0;
while ($wait) {
$tasks = \core\task\manager::get_running_tasks();
if (count($tasks) == 0) {
mtrace('');
mtrace('All scheduled and adhoc tasks finished.');
exit(0);
}
if (time() - $started >= $waitsec) {
mtrace('');
mtrace('Wait time ('. format_time($waitsec) . ') elapsed, but ' . count($tasks) . ' task(s) still running.');
mtrace('Exiting with code 1.');
exit(1);
}
if (count($tasks) !== $lastcount) {
mtrace('');
mtrace(count($tasks) . " tasks currently running.", '');
$lastcount = count($tasks);
} else {
mtrace('.', '');
}
sleep(1);
}
}
if (!get_config('core', 'cron_enabled') && !$options['force']) {
mtrace('Cron is disabled. Use --force to override.');
exit(1);
}
\core\local\cli\shutdown::script_supports_graceful_exit();
cron_run();
-65
View File
@@ -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/>.
/**
* CLI script to reset dashboards.
*
* @package core
* @subpackage cli
* @copyright 2021 Brendan Heywood (brendan@catalyst-au.net)
* @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');
require_once($CFG->dirroot.'/my/lib.php');
list($options, $unrecognized) = cli_get_params([
'help' => false,
'execute' => false,
], [
'h' => 'help',
'e' => 'execute',
]);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized), 2);
}
if (!$options['execute']) {
$help = <<<EOF
Resets Moodle dashboards for all users
Options:
-h, --help Print out this help
-e, --execute Actually run the reset
Example:
\$ sudo -u www-data /usr/bin/php admin/cli/dashboard_reset.php -e
EOF;
echo $help;
exit(0);
}
$progressbar = new progress_bar();
$progressbar->create();
my_reset_page_for_all_users(MY_PAGE_PRIVATE, 'my-index', $progressbar);
-124
View File
@@ -1,124 +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/>.
/**
* CLI script to delete a course.
*
* @package core
* @subpackage cli
* @author Mikhail Golenkov <mikhailgolenkov@catalyst-au.net>
* @copyright 2022 Catalyst IT
* @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');
require_once($CFG->libdir . '/cronlib.php');
list($options, $unrecognized) = cli_get_params(
[
'courseid' => false,
'help' => false,
'showsql' => false,
'showdebugging' => false,
'disablerecyclebin' => false,
'non-interactive' => false,
], [
'c' => 'courseid',
'h' => 'help',
]
);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] || empty($options['courseid'])) {
$help = <<<EOT
CLI script to delete a course.
Options:
-h, --help Print out this help
--showsql Show sql queries before they are executed
--showdebugging Show developer level debugging information
--disablerecyclebin Skip backing up the course
--non-interactive No interactive questions or confirmations
-c, --courseid Course id to be deleted
Example:
\$sudo -u www-data /usr/bin/php admin/cli/delete_course.php --courseid=123456
\$sudo -u www-data /usr/bin/php admin/cli/delete_course.php --courseid=123456 --showdebugging
\$sudo -u www-data /usr/bin/php admin/cli/delete_course.php --courseid=123456 --disablerecyclebin
EOT;
echo $help;
die;
}
$interactive = empty($options['non-interactive']);
if ($options['showdebugging']) {
mtrace('Enabling debugging...');
set_debugging(DEBUG_DEVELOPER, true);
}
if ($options['showsql']) {
mtrace('Enabling SQL debugging...');
$DB->set_debug(true);
}
if (CLI_MAINTENANCE) {
cli_error('CLI maintenance mode active, CLI execution suspended');
}
if (moodle_needs_upgrading()) {
cli_error('Moodle upgrade pending, CLI execution suspended');
}
$course = $DB->get_record('course', array('id' => $options['courseid']));
if (empty($course)) {
cli_error('Course not found');
}
mtrace('Deleting course id ' . $course->id);
mtrace('Course name: ' . $course->fullname);
mtrace('Short name: ' . $course->shortname);
if ($interactive) {
mtrace('');
$input = cli_input('Are you sure you wish to delete this course? (y/N)', 'N', ['y', 'Y', 'n', 'N']);
if (strtolower($input) != 'y') {
exit(0);
}
}
if ($options['disablerecyclebin']) {
mtrace('Disabling recycle bin...');
$overrideconfig = ['tool_recyclebin' => ['coursebinenable' => false, 'categorybinenable' => false]];
$CFG->forced_plugin_settings = array_merge($CFG->forced_plugin_settings, $overrideconfig);
}
core_php_time_limit::raise();
delete_course($course);
mtrace('Updating course count in categories...');
fix_course_sortorder();
mtrace('Done!');
-138
View File
@@ -1,138 +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/>.
/**
* Fix orphaned calendar events that were broken by MDL-67494.
*
* This script will look for all the calendar events which userids
* where broken by a wrong upgrade step, affecting to Moodle 3.9.5
* and up.
*
* It performs checks to both:
* a) Detect if the site was affected (ran the wrong upgrade step).
* b) Look for orphaned calendar events, categorising them as:
* - standard: site / category / course / group / user events
* - subscription: events created via subscriptions.
* - action: normal action events, created to show common important dates.
* - override: user and group override events, particular, that some activities support.
* - custom: other events, not being any of the above, common or particular.
* By specifying it (--fix) try to recover as many broken events (missing userid) as
* possible. Standard, subscription, action, override events in core are fully supported but
* override or custom events should be fixed by each plugin as far as there isn't any standard
* API (plugin-wise) to launch a rebuild of the calendar events.
*
* @package core
* @copyright 2021 onwards Simey Lameze <simey@moodle.com>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require_once(__DIR__ . '/../../config.php');
require_once($CFG->libdir . "/clilib.php");
require_once($CFG->libdir . '/db/upgradelib.php');
// Supported options.
$long = ['fix' => false, 'help' => false];
$short = ['f' => 'fix', 'h' => 'help'];
// CLI options.
[$options, $unrecognized] = cli_get_params($long, $short);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help']) {
$help = <<<EOT
Fix orphaned calendar events.
This script detects calendar events that have had their
userid lost. By default it will perform various checks
and report them, showing the site status in an easy way.
Also, optionally (--fix), it wil try to recover as many
lost userids as possible from different sources. Note that
this script aims to process well-know events in core,
leaving custom events in 3rd part plugins mostly unmodified
because there isn't any consistent way to regenerate them.
For more details: https://tracker.moodle.org/browse/MDL-71156
Options:
-h, --help Print out this help.
-f, --fix Fix the orphaned calendar events in the DB.
If not specified only check and report problems to STDERR.
Usage:
- Only report: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php
- Report and fix: \$ sudo -u www-data /usr/bin/php admin/cli/fix_orphaned_calendar_events.php -f
EOT;
cli_writeln($help);
die;
}
// Check various usual pre-requisites.
if (empty($CFG->version)) {
cli_error('Database is not yet installed.');
}
$admin = get_admin();
if (!$admin) {
cli_error('Error: No admin account was found.');
}
if (moodle_needs_upgrading()) {
cli_error('Moodle upgrade pending, script execution suspended.');
}
// Do everything as admin by default.
\core\session\manager::set_user($admin);
// Report current site status.
cli_heading('Checking the site status');
$needsfix = upgrade_calendar_site_status();
// Report current calendar events status.
cli_heading('Checking the calendar events status');
$info = upgrade_calendar_events_status();
$hasbadevents = $info['total']->bad > 0 || $info['total']->bad != $info['other']->bad;
$needsfix = $needsfix || $hasbadevents;
// If, selected, fix as many calendar events as possible.
if ($options['fix']) {
// If the report has told us that the fix was not needed... ask for confirmation!
if (!$needsfix) {
cli_writeln("This site DOES NOT NEED to run the calendar events fix.");
$input = cli_input('Are you completely sure that you want to run the fix? (y/N)', 'N', ['y', 'Y', 'n', 'N']);
if (strtolower($input) != 'y') {
exit(0);
}
cli_writeln("");
}
cli_heading('Fixing as many as possible calendar events');
upgrade_calendar_events_fix_remaining($info);
// Report current (after fix) calendar events status.
cli_heading('Checking the calendar events status (after fix)');
upgrade_calendar_events_status();
} else if ($needsfix) {
// Fix option was not provided but problem events have been found. Notify the user and provide info how to fix these events.
cli_writeln("This site NEEDS to run the calendar events fix!");
cli_writeln("To fix the calendar events, re-run this script with the --fix option.");
}
-79
View File
@@ -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/>.
/**
* Generates a secure key for the current server (presuming it does not already exist).
*
* @package core_admin
* @copyright 2020 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use \core\encryption;
define('CLI_SCRIPT', true);
require(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/clilib.php');
// Get cli options.
[$options, $unrecognized] = cli_get_params(
['help' => false, 'method' => null],
['h' => 'help']);
if ($unrecognized) {
$unrecognized = implode("\n ", $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
This script manually creates a secure key within the secret data root folder (configured in
config.php as \$CFG->secretdataroot). You must run it using an account with access to write
to that folder.
In normal use Moodle automatically creates the key; this script is intended when setting up
a new Moodle system, for cases where the secure folder is not on shared storage and the key
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
* openssl-aes-256-ctr
Example:
php admin/cli/generate_key.php
";
exit;
}
$method = $options['method'];
if (encryption::key_exists($method)) {
echo 'Key already exists: ' . encryption::get_key_file($method) . "\n";
exit;
}
// Creates key with default permissions (no chmod).
echo "Generating key...\n";
encryption::create_key($method, false);
echo "\nKey created: " . encryption::get_key_file($method) . "\n\n";
echo "If the key folder is not shared storage, then key files should be copied to all servers.\n";
+181 -223
View File
@@ -74,8 +74,6 @@ Options:
--adminpass=PASSWORD Password for the moodle admin account,
required in non-interactive mode.
--adminemail=STRING Email address for the moodle admin account.
--sitepreset=STRING Admin site preset to be applied during the installation process.
--supportemail=STRING Email address for support and help.
--upgradekey=STRING The upgrade key to be set in the config.php, leave empty to not set it.
--non-interactive No interactive questions, installation fails if any
problem encountered.
@@ -217,7 +215,6 @@ define('SITEID', 1);
//Database types
$databases = array('mysqli' => moodle_database::get_driver_instance('mysqli', 'native'),
'auroramysql' => moodle_database::get_driver_instance('auroramysql', 'native'),
'mariadb'=> moodle_database::get_driver_instance('mariadb', 'native'),
'pgsql' => moodle_database::get_driver_instance('pgsql', 'native'),
'oci' => moodle_database::get_driver_instance('oci', 'native'),
@@ -256,8 +253,6 @@ list($options, $unrecognized) = cli_get_params(
'adminuser' => 'admin',
'adminpass' => '',
'adminemail' => '',
'sitepreset' => '',
'supportemail' => '',
'upgradekey' => '',
'non-interactive' => false,
'agree-license' => false,
@@ -271,7 +266,6 @@ list($options, $unrecognized) = cli_get_params(
);
$interactive = empty($options['non-interactive']);
$skipdatabase = $options['skip-database'];
// set up language
$lang = clean_param($options['lang'], PARAM_SAFEDIR);
@@ -280,12 +274,6 @@ if (array_key_exists($lang, $languages)) {
$CFG->lang = $lang;
}
// Set up site admin preset.
$sitepreset = clean_param($options['sitepreset'], PARAM_RAW);
if (!empty($sitepreset)) {
$CFG->setsitepresetduringinstall = $sitepreset;
}
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
@@ -403,6 +391,7 @@ if ($interactive) {
$CFG->wwwroot = $wwwroot;
$CFG->httpswwwroot = $CFG->wwwroot;
//We need dataroot before lang download
$CFG->dataroot = $options['dataroot'];
if ($interactive) {
@@ -525,105 +514,100 @@ if ($interactive) {
$database = $databases[$CFG->dbtype];
// We cannot do any validation until all DB connection data is provided.
$hintdatabase = '';
do {
echo $hintdatabase;
// Ask for db host.
if ($interactive) {
cli_separator();
cli_heading(get_string('databasehost', 'install'));
if ($options['dbhost'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbhost = cli_input($prompt, $options['dbhost']);
// ask for db host
if ($interactive) {
cli_separator();
cli_heading(get_string('databasehost', 'install'));
if ($options['dbhost'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
} else {
$CFG->dbhost = $options['dbhost'];
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbhost = cli_input($prompt, $options['dbhost']);
// Ask for db name.
if ($interactive) {
cli_separator();
cli_heading(get_string('databasename', 'install'));
if ($options['dbname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbname = cli_input($prompt, $options['dbname']);
} else {
$CFG->dbhost = $options['dbhost'];
}
// ask for db name
if ($interactive) {
cli_separator();
cli_heading(get_string('databasename', 'install'));
if ($options['dbname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
} else {
$CFG->dbname = $options['dbname'];
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbname = cli_input($prompt, $options['dbname']);
// Ask for db prefix.
if ($interactive) {
cli_separator();
cli_heading(get_string('dbprefix', 'install'));
//TODO: solve somehow the prefix trouble for oci.
if ($options['prefix'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->prefix = cli_input($prompt, $options['prefix']);
} else {
$CFG->dbname = $options['dbname'];
}
// ask for db prefix
if ($interactive) {
cli_separator();
cli_heading(get_string('dbprefix', 'install'));
//TODO: solve somehow the prefix trouble for oci
if ($options['prefix'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
} else {
$CFG->prefix = $options['prefix'];
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->prefix = cli_input($prompt, $options['prefix']);
// Ask for db port.
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseport', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbport']);
$CFG->dboptions['dbport'] = (int) cli_input($prompt, $options['dbport']);
} else {
$CFG->prefix = $options['prefix'];
}
// ask for db port
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseport', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbport']);
$CFG->dboptions['dbport'] = (int)cli_input($prompt, $options['dbport']);
} else {
$CFG->dboptions['dbport'] = (int)$options['dbport'];
}
if ($CFG->dboptions['dbport'] <= 0) {
$CFG->dboptions['dbport'] = '';
}
// ask for db socket
if ($CFG->ostype === 'WINDOWS') {
$CFG->dboptions['dbsocket'] = '';
} else if ($interactive and empty($CFG->dboptions['dbport'])) {
cli_separator();
cli_heading(get_string('databasesocket', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbsocket']);
$CFG->dboptions['dbsocket'] = cli_input($prompt, $options['dbsocket']);
} else {
$CFG->dboptions['dbsocket'] = $options['dbsocket'];
}
// ask for db user
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseuser', 'install'));
if ($options['dbuser'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
} else {
$CFG->dboptions['dbport'] = (int) $options['dbport'];
}
if ($CFG->dboptions['dbport'] <= 0) {
$CFG->dboptions['dbport'] = '';
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbuser = cli_input($prompt, $options['dbuser']);
// Ask for db socket.
if ($CFG->ostype === 'WINDOWS') {
$CFG->dboptions['dbsocket'] = '';
} else if ($interactive and empty($CFG->dboptions['dbport'])) {
cli_separator();
cli_heading(get_string('databasesocket', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbsocket']);
$CFG->dboptions['dbsocket'] = cli_input($prompt, $options['dbsocket']);
} else {
$CFG->dboptions['dbsocket'] = $options['dbsocket'];
}
// Ask for db user.
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseuser', 'install'));
if ($options['dbuser'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbuser = cli_input($prompt, $options['dbuser']);
} else {
$CFG->dbuser = $options['dbuser'];
}
// Ask for db password.
if ($interactive) {
cli_separator();
cli_heading(get_string('databasepass', 'install'));
} else {
$CFG->dbuser = $options['dbuser'];
}
// ask for db password
if ($interactive) {
cli_separator();
cli_heading(get_string('databasepass', 'install'));
do {
if ($options['dbpass'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbpass']);
} else {
@@ -631,132 +615,110 @@ do {
}
$CFG->dbpass = cli_input($prompt, $options['dbpass']);
if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation.
$distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']),
$distro);
if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation
$distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']), $distro);
}
$hintdatabase = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']));
$hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']));
} while ($hint_database !== '');
} else {
$CFG->dbpass = $options['dbpass'];
$hintdatabase = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']));
if ($hintdatabase !== '') {
cli_error(get_string('dbconnectionerror', 'install'));
}
} else {
$CFG->dbpass = $options['dbpass'];
$hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']));
if ($hint_database !== '') {
cli_error(get_string('dbconnectionerror', 'install'));
}
} while ($hintdatabase !== '');
}
// If --skip-database option is provided, we do not need to ask for site fullname, shortname, adminuser, adminpass, adminemail.
// These fields will be requested during the database install part.
if (!$skipdatabase) {
// Ask for fullname.
if ($interactive) {
cli_separator();
cli_heading(get_string('fullsitename', 'moodle'));
// ask for fullname
if ($interactive) {
cli_separator();
cli_heading(get_string('fullsitename', 'moodle'));
if ($options['fullname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['fullname']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
do {
$options['fullname'] = cli_input($prompt, $options['fullname']);
} while (empty($options['fullname']));
if ($options['fullname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['fullname']);
} else {
if (empty($options['fullname'])) {
$a = (object)['option' => 'fullname', 'value' => $options['fullname']];
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// Ask for shortname.
if ($interactive) {
cli_separator();
cli_heading(get_string('shortsitename', 'moodle'));
if ($options['shortname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['shortname']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
do {
$options['shortname'] = cli_input($prompt, $options['shortname']);
} while (empty($options['shortname']));
} else {
if (empty($options['shortname'])) {
$a = (object)['option' => 'shortname', 'value' => $options['shortname']];
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// Ask for admin user name.
if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminusername', 'install'));
if (!empty($options['adminuser'])) {
$prompt = get_string('clitypevaluedefault', 'admin', $options['adminuser']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
do {
$options['adminuser'] = cli_input($prompt, $options['adminuser']);
} while (empty($options['adminuser']) or $options['adminuser'] === 'guest');
} else {
if ((empty($options['adminuser']) || $options['adminuser'] === 'guest')) {
$a = (object)['option' => 'adminuser', 'value' => $options['adminuser']];
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// Ask for admin user password.
if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminpassword', 'install'));
$prompt = get_string('clitypevalue', 'admin');
do {
$options['adminpass'] = cli_input($prompt);
} while (empty($options['adminpass']) or $options['adminpass'] === 'admin');
}
do {
$options['fullname'] = cli_input($prompt, $options['fullname']);
} while (empty($options['fullname']));
} else {
if (empty($options['fullname'])) {
$a = (object)array('option'=>'fullname', 'value'=>$options['fullname']);
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// ask for shortname
if ($interactive) {
cli_separator();
cli_heading(get_string('shortsitename', 'moodle'));
if ($options['shortname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['shortname']);
} else {
if ((empty($options['adminpass']) or $options['adminpass'] === 'admin')) {
$a = (object)['option' => 'adminpass', 'value' => $options['adminpass']];
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
$prompt = get_string('clitypevalue', 'admin');
}
// Ask for the admin email address.
if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminemail', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['adminemail']);
$options['adminemail'] = cli_input($prompt, $options['adminemail']);
}
// Validate that the address provided was an e-mail address.
if (!empty($options['adminemail']) && !validate_email($options['adminemail'])) {
$a = (object)['option' => 'adminemail', 'value' => $options['adminemail']];
do {
$options['shortname'] = cli_input($prompt, $options['shortname']);
} while (empty($options['shortname']));
} else {
if (empty($options['shortname'])) {
$a = (object)array('option'=>'shortname', 'value'=>$options['shortname']);
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// Ask for the support email address.
if ($interactive) {
cli_separator();
cli_heading(get_string('clisupportemail', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['supportemail']);
$options['supportemail'] = cli_input($prompt, $options['supportemail']);
// ask for admin user name
if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminusername', 'install'));
if (!empty($options['adminuser'])) {
$prompt = get_string('clitypevaluedefault', 'admin', $options['adminuser']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
// Validate that the support email address provided is valid.
if (!empty($options['supportemail']) && !validate_email($options['supportemail'])) {
$a = (object)['option' => 'supportemail', 'value' => $options['supportemail']];
do {
$options['adminuser'] = cli_input($prompt, $options['adminuser']);
} while (empty($options['adminuser']) or $options['adminuser'] === 'guest');
} else {
if (empty($options['adminuser']) or $options['adminuser'] === 'guest') {
$a = (object)array('option'=>'adminuser', 'value'=>$options['adminuser']);
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// ask for admin user password
if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminpassword', 'install'));
$prompt = get_string('clitypevalue', 'admin');
do {
$options['adminpass'] = cli_input($prompt);
} while (empty($options['adminpass']) or $options['adminpass'] === 'admin');
} else {
if (empty($options['adminpass']) or $options['adminpass'] === 'admin') {
$a = (object)array('option'=>'adminpass', 'value'=>$options['adminpass']);
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
}
// Ask for the admin email address.
if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminemail', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['adminemail']);
$options['adminemail'] = cli_input($prompt);
}
// Validate that the address provided was an e-mail address.
if (!empty($options['adminemail']) && !validate_email($options['adminemail'])) {
$a = (object) array('option' => 'adminemail', 'value' => $options['adminemail']);
cli_error(get_string('cliincorrectvalueerror', 'admin', $a));
}
// Ask for the upgrade key.
if ($interactive) {
cli_separator();
@@ -775,27 +737,23 @@ if ($options['upgradekey'] !== '') {
$CFG->upgradekey = $options['upgradekey'];
}
// The user does not also need to pass agree-license when --skip-database is provided as the user will need to accept
// the license again in the database install part.
if (!$skipdatabase) {
if ($interactive) {
if (!$options['agree-license']) {
cli_separator();
cli_heading(get_string('copyrightnotice'));
echo "Moodle - Modular Object-Oriented Dynamic Learning Environment\n";
echo get_string('gpl3')."\n\n";
echo get_string('doyouagree')."\n";
$prompt = get_string('cliyesnoprompt', 'admin');
$input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
if ($input == get_string('clianswerno', 'admin')) {
exit(1);
}
}
} else {
if (!$options['agree-license'] && !$skipdatabase) {
cli_error(get_string('climustagreelicense', 'install'));
if ($interactive) {
if (!$options['agree-license']) {
cli_separator();
cli_heading(get_string('copyrightnotice'));
echo "Moodle - Modular Object-Oriented Dynamic Learning Environment\n";
echo get_string('gpl3')."\n\n";
echo get_string('doyouagree')."\n";
$prompt = get_string('cliyesnoprompt', 'admin');
$input = cli_input($prompt, '', array(get_string('clianswerno', 'admin'), get_string('cliansweryes', 'admin')));
if ($input == get_string('clianswerno', 'admin')) {
exit(1);
}
}
} else {
if (!$options['agree-license']) {
cli_error(get_string('climustagreelicense', 'install'));
}
}
// Finally we have all info needed for config.php
@@ -843,7 +801,7 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
cli_error(get_string('pluginschecktodo', 'admin'));
}
if (!$skipdatabase) {
if (!$options['skip-database']) {
install_cli_database($options, $interactive);
// This needs to happen at the end to ensure it occurs after all caches
// have been purged for the last time.
+5 -23
View File
@@ -56,8 +56,6 @@ Options:
--agree-license Indicates agreement with software license.
--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:
@@ -84,6 +82,11 @@ require_once($CFG->libdir.'/installlib.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/componentlib.class.php');
// make sure no tables are installed yet
if ($DB->get_tables() ) {
cli_error(get_string('clitablesexist', 'install'));
}
$CFG->early_install_lang = true;
get_string_manager(true);
@@ -98,8 +101,6 @@ list($options, $unrecognized) = cli_get_params(
'adminemail' => '',
'fullname' => '',
'shortname' => '',
'summary' => '',
'supportemail' => '',
'agree-license' => false,
'help' => false
),
@@ -108,22 +109,12 @@ list($options, $unrecognized) = cli_get_params(
)
);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
// We show help text even if tables are installed.
if ($options['help']) {
echo $help;
die;
}
// Make sure no tables are installed yet.
if ($DB->get_tables() ) {
cli_error(get_string('clitablesexist', 'install'));
}
if (!$options['agree-license']) {
cli_error('You have to agree to the license. --help prints out the help'); // TODO: localize
}
@@ -138,15 +129,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';
+8 -8
View File
@@ -119,7 +119,7 @@ if (!empty($options['collation'])) {
if ($dbcollation->value !== $collation || $dbcharset->value !== $charset) {
// Try to convert the DB.
echo "Converting database to '$collation' for $CFG->wwwroot:\n";
$sql = "ALTER DATABASE `$CFG->dbname` DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
$sql = "ALTER DATABASE $CFG->dbname DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation";
try {
$DB->change_database_structure($sql);
} catch (exception $e) {
@@ -146,7 +146,7 @@ if (!empty($options['collation'])) {
} else {
try {
$DB->change_database_structure("ALTER TABLE `$table->name` CONVERT TO CHARACTER SET $charset COLLATE $collation");
$DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
echo "CONVERTED\n";
$converted++;
} catch (ddl_exception $e) {
@@ -163,7 +163,7 @@ if (!empty($options['collation'])) {
}
}
$sql = "SHOW FULL COLUMNS FROM `$table->name` WHERE collation IS NOT NULL";
$sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
$rs2 = $DB->get_recordset_sql($sql);
foreach ($rs2 as $column) {
$column = (object)array_change_key_case((array)$column, CASE_LOWER);
@@ -181,7 +181,7 @@ if (!empty($options['collation'])) {
$notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
$default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
// primary, unique and inc are not supported for texts
$sql = "ALTER TABLE `$table->name`
$sql = "ALTER TABLE $table->name
MODIFY COLUMN $column->field $column->type
CHARACTER SET $charset
COLLATE $collation $notnull $default";
@@ -192,11 +192,11 @@ if (!empty($options['collation'])) {
$default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
if ($rowformat != '') {
$sql = "ALTER TABLE `$table->name` $rowformat";
$sql = "ALTER TABLE $table->name $rowformat";
$DB->change_database_structure($sql);
}
$sql = "ALTER TABLE `$table->name`
$sql = "ALTER TABLE $table->name
MODIFY COLUMN $column->field $column->type
CHARACTER SET $charset
COLLATE $collation $notnull $default";
@@ -315,8 +315,8 @@ function mysql_set_row_format($tablename, $charset, $collation, $engine) {
if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
$rowformat = $DB->get_row_format_sql($engine, $collation);
// Try to convert to compressed format and then try updating the collation again.
$DB->change_database_structure("ALTER TABLE `$tablename` $rowformat");
$DB->change_database_structure("ALTER TABLE `$tablename` CONVERT TO CHARACTER SET $charset COLLATE $collation");
$DB->change_database_structure("ALTER TABLE $tablename $rowformat");
$DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
} else {
// Row format may not be the problem. Can not diagnose problem. Send fail reply.
return false;
+2 -2
View File
@@ -158,7 +158,7 @@ if (!empty($options['info'])) {
}
foreach ($fixtables as $table) {
$DB->change_database_structure("ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed");
$DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
}
@@ -189,7 +189,7 @@ if (!empty($options['info'])) {
echo "SET GLOBAL innodb_file_per_table=1;\n";
echo "SET GLOBAL innodb_file_format=Barracuda;\n";
foreach ($fixtables as $table) {
echo "ALTER TABLE `{$prefix}$table` ROW_FORMAT=Compressed;\n";
echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
}
echo "\n";
exit(0);
+180
View File
@@ -0,0 +1,180 @@
<?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/>.
/**
* MySQL engine conversion tool.
*
* @package core
* @subpackage cli
* @copyright 2009 Petr Skoda (http://skodak.org)
* @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'); // cli only functions
if ($DB->get_dbfamily() !== 'mysql') {
cli_error('This function is designed for MySQL databases only!');
}
// now get cli options
list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'engine'=>false, 'available'=>false),
array('h'=>'help', 'l'=>'list', 'a'=>'available'));
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
$help =
"MySQL engine conversions script.
It is recommended to stop the web server before the conversion.
Do not use MyISAM if possible, because it is not ACID compliant
and does not support transactions.
Options:
--engine=ENGINE Convert MySQL tables to different engine
-l, --list Show table information
-a, --available Show list of available engines
-h, --help Print out this help
Example:
\$sudo -u www-data /usr/bin/php admin/cli/mysql_engine.php --engine=InnoDB
";
if (!empty($options['engine'])) {
$engines = mysql_get_engines();
$engine = clean_param($options['engine'], PARAM_ALPHA);
if (!isset($engines[strtoupper($engine)])) {
cli_error("Error: engine '$engine' is not available on this server!");
}
echo "Converting tables to '$engine' for $CFG->wwwroot:\n";
$prefix = $DB->get_prefix();
$prefix = str_replace('_', '\\_', $prefix);
$sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
$rs = $DB->get_recordset_sql($sql);
$converted = 0;
$skipped = 0;
$errors = 0;
foreach ($rs as $table) {
if (strtoupper($table->engine) === strtoupper($engine)) {
$newengine = mysql_get_table_engine($table->name);
echo str_pad($table->name, 40). " - NO CONVERSION NEEDED ($newengine)\n";
$skipped++;
continue;
}
echo str_pad($table->name, 40). " - ";
try {
$DB->change_database_structure("ALTER TABLE {$table->name} ENGINE = $engine");
$newengine = mysql_get_table_engine($table->name);
if (strtoupper($newengine) !== strtoupper($engine)) {
echo "ERROR ($newengine)\n";
$errors++;
continue;
}
echo "DONE ($newengine)\n";
$converted++;
} catch (moodle_exception $e) {
echo $e->getMessage()."\n";
$errors++;
continue;
}
}
$rs->close();
echo "Converted: $converted, skipped: $skipped, errors: $errors\n";
exit(0); // success
} else if (!empty($options['list'])) {
echo "List of tables for $CFG->wwwroot:\n";
$prefix = $DB->get_prefix();
$prefix = str_replace('_', '\\_', $prefix);
$sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
$rs = $DB->get_recordset_sql($sql);
$counts = array();
foreach ($rs as $table) {
if (isset($counts[$table->engine])) {
$counts[$table->engine]++;
} else {
$counts[$table->engine] = 1;
}
echo str_pad($table->engine, 10);
echo $table->name . "\n";
}
$rs->close();
echo "\n";
echo "Table engines summary for $CFG->wwwroot:\n";
foreach ($counts as $engine => $count) {
echo "$engine: $count\n";
}
exit(0); // success
} else if (!empty($options['available'])) {
echo "List of available MySQL engines for $CFG->wwwroot:\n";
$engines = mysql_get_engines();
foreach ($engines as $engine) {
echo " $engine\n";
}
die;
} else {
echo $help;
die;
}
// ========== Some functions ==============
function mysql_get_engines() {
global $DB;
$sql = "SHOW Engines";
$rs = $DB->get_recordset_sql($sql);
$engines = array();
foreach ($rs as $engine) {
if (strtoupper($engine->support) !== 'YES' and strtoupper($engine->support) !== 'DEFAULT') {
continue;
}
$engines[strtoupper($engine->engine)] = $engine->engine;
if (strtoupper($engine->support) === 'DEFAULT') {
$engines[strtoupper($engine->engine)] .= ' (default)';
}
}
$rs->close();
return $engines;
}
function mysql_get_table_engine($tablename) {
global $DB;
$engine = null;
$sql = "SHOW TABLE STATUS WHERE Name = '$tablename'"; // no special chars expected here
$rs = $DB->get_recordset_sql($sql);
if ($rs->valid()) {
$record = $rs->current();
$engine = $record->engine;
}
$rs->close();
return $engine;
}
+1 -1
View File
@@ -94,7 +94,7 @@ if ($options['password'] == '' ) {
$errmsg = '';//prevent eclipse warning
if (!$options['ignore-password-policy'] ) {
if (!check_password_policy($password, $errmsg, $user)) {
if (!check_password_policy($password, $errmsg)) {
cli_error(html_to_text($errmsg, 0));
}
}
-109
View File
@@ -1,109 +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 restore a course from CLI.
*
* @package core
* @subpackage cli
* @copyright 2020 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/restore_includes.php");
list($options, $unrecognized) = cli_get_params([
'file' => '',
'categoryid' => '',
'showdebugging' => false,
'help' => false,
], [
'f' => 'file',
'c' => 'categoryid',
's' => 'showdebugging',
'h' => 'help',
]);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] || !($options['file']) || !($options['categoryid'])) {
$help = <<<EOL
Restore backup into provided category.
Options:
-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
EOL;
echo $help;
exit(0);
}
if ($options['showdebugging']) {
set_debugging(DEBUG_DEVELOPER, true);
}
if (!$admin = get_admin()) {
throw new \moodle_exception('noadmins');
}
if (!file_exists($options['file'])) {
throw new \moodle_exception('filenotfound');
}
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
throw new \moodle_exception('invalidcategoryid');
}
$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');
$fp->extract_to_pathname($options['file'], $path);
cli_heading(get_string('preprocessingbackupfile'));
try {
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
get_string('restoringcourseshortname', 'backup'));
$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();
} catch (Exception $e) {
cli_heading(get_string('cleaningtempdata'));
fulldelete($path);
throw new \moodle_exception('generalexceptionmessage', 'error', '', $e->getMessage());
}
cli_heading(get_string('restoredcourseid', 'backup', $courseid));
exit(0);
-168
View File
@@ -1,168 +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/>.
/**
* CLI task execution.
*
* @package core
* @subpackage cli
* @copyright 2014 Petr Skoda
* @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");
require_once("$CFG->libdir/cronlib.php");
list($options, $unrecognized) = cli_get_params(
[
'help' => false,
'list' => false,
'execute' => false,
'showsql' => false,
'showdebugging' => false,
'force' => false,
], [
'h' => 'help',
'f' => 'force',
]
);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] or (!$options['list'] and !$options['execute'])) {
$help =
"Scheduled cron tasks.
Options:
--execute=\\some\\task Execute scheduled task manually
--list List all scheduled tasks
--showsql Show sql queries before they are executed
--showdebugging Show developer level debugging information
-h, --help Print out this help
-f, --force Execute task even if cron is disabled
Example:
\$sudo -u www-data /usr/bin/php admin/cli/scheduled_task.php --execute=\\core\\task\\session_cleanup_task
";
echo $help;
die;
}
if ($options['showdebugging'] || !empty($CFG->showcrondebugging)) {
set_debugging(DEBUG_DEVELOPER, true);
}
if ($options['showsql'] || !empty($CFG->showcronsql)) {
$DB->set_debug(true);
}
if ($options['list']) {
cli_heading("List of scheduled tasks ($CFG->wwwroot)");
$shorttime = get_string('strftimedatetimeshort');
$tasks = \core\task\manager::get_all_scheduled_tasks();
echo str_pad(get_string('scheduledtasks', 'tool_task'), 50, ' ') . ' ' . str_pad(get_string('runpattern', 'tool_task'), 17, ' ')
. ' ' . str_pad(get_string('lastruntime', 'tool_task'), 40, ' ') . get_string('nextruntime', 'tool_task') . "\n";
foreach ($tasks as $task) {
$class = '\\' . get_class($task);
$schedule = $task->get_minute() . ' '
. $task->get_hour() . ' '
. $task->get_day() . ' '
. $task->get_day_of_week() . ' '
. $task->get_month() . ' '
. $task->get_day_of_week();
$nextrun = $task->get_next_run_time();
$lastrun = $task->get_last_run_time();
$plugininfo = core_plugin_manager::instance()->get_plugin_info($task->get_component());
$plugindisabled = $plugininfo && $plugininfo->is_enabled() === false && !$task->get_run_if_component_disabled();
if ($plugindisabled) {
$nextrun = get_string('plugindisabled', 'tool_task');
} else if ($task->get_disabled()) {
$nextrun = get_string('taskdisabled', 'tool_task');
} else if ($nextrun > time()) {
$nextrun = userdate($nextrun);
} else {
$nextrun = get_string('asap', 'tool_task');
}
if ($lastrun) {
$lastrun = userdate($lastrun);
} else {
$lastrun = get_string('never');
}
echo str_pad($class, 50, ' ') . ' ' . str_pad($schedule, 17, ' ') .
' ' . str_pad($lastrun, 40, ' ') . ' ' . $nextrun . "\n";
}
exit(0);
}
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);
}
\core\task\manager::scheduled_task_starting($task);
// Increase memory limit.
raise_memory_limit(MEMORY_EXTRA);
// Emulate normal session - we use admin account by default.
cron_setup_user();
// Execute the task.
\core\local\cli\shutdown::script_supports_graceful_exit();
$cronlockfactory = \core\lock\lock_config::get_lock_factory('cron');
if (!$cronlock = $cronlockfactory->get_lock('core_cron', 10)) {
mtrace('Cannot obtain cron lock');
exit(129);
}
if (!$lock = $cronlockfactory->get_lock('\\' . get_class($task), 10)) {
$cronlock->release();
mtrace('Cannot obtain task lock');
exit(130);
}
$task->set_lock($lock);
if (!$task->is_blocking()) {
$cronlock->release();
} else {
$task->set_cron_lock($cronlock);
}
cron_run_inner_scheduled_task($task);
}
+7 -7
View File
@@ -38,17 +38,17 @@ if ($unrecognized) {
}
// If necessary add files that should be ignored - such as in 3rd party plugins.
$ignorelist = array();
$blacklist = array();
$path = $options['path'];
if (!file_exists($path)) {
cli_error("Invalid path $path");
}
if ($options['ie9fix']) {
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_ie9fix', $ignorelist);
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_ie9fix', $blacklist);
} else if ($options['noaspectratio']) {
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_noaspectratio', $ignorelist);
core_admin_recurse_svgs($path, '', 'core_admin_svgtool_noaspectratio', $blacklist);
} else {
$help =
@@ -153,9 +153,9 @@ function core_admin_svgtool_noaspectratio($file) {
* @param string $base
* @param string $sub
* @param string $filecallback
* @param array $ignorelist List of files to be ignored and skipped.
* @param array $blacklist
*/
function core_admin_recurse_svgs($base, $sub, $filecallback, $ignorelist) {
function core_admin_recurse_svgs($base, $sub, $filecallback, $blacklist) {
if (is_dir("$base/$sub")) {
$items = new DirectoryIterator("$base/$sub");
foreach ($items as $item) {
@@ -163,7 +163,7 @@ function core_admin_recurse_svgs($base, $sub, $filecallback, $ignorelist) {
continue;
}
$file = $item->getFilename();
core_admin_recurse_svgs("$base/$sub", $file, $filecallback, $ignorelist);
core_admin_recurse_svgs("$base/$sub", $file, $filecallback, $blacklist);
}
unset($item);
unset($items);
@@ -174,7 +174,7 @@ function core_admin_recurse_svgs($base, $sub, $filecallback, $ignorelist) {
return;
}
$file = realpath("$base/$sub");
if (in_array($file, $ignorelist)) {
if (in_array($file, $blacklist)) {
return;
}
$filecallback($file);
-183
View File
@@ -1,183 +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/>.
/**
* CLI script to uninstall plugins.
*
* @package core
* @subpackage cli
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @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');
require_once($CFG->libdir . '/adminlib.php');
$help = "Command line tool to uninstall plugins.
Options:
-h --help Print this help.
--show-all Displays a list of all installed plugins.
--show-contrib Displays a list of all third-party installed plugins.
--show-missing Displays a list of plugins missing from disk.
--purge-missing Uninstall all missing from disk plugins.
--plugins=<plugin name> A comma separated list of plugins to be uninstalled. E.g. mod_assign,mod_forum
--run Execute uninstall. If this option is not set, then the script will be run in a dry mode.
--showsql Show sql queries before they are executed.
--showdebugging Show developer level debugging information.
Examples:
# php uninstall_plugins.php --show-all
Prints tab-separated list of all installed plugins.
# php uninstall_plugins.php --show-contrib
Prints tab-separated list of all third-party installed plugins.
# php uninstall_plugins.php --show-missing
Prints tab-separated list of all missing from disk plugins.
# php uninstall_plugins.php --purge-missing
A dry run of uninstalling all missing plugins.
# php uninstall_plugins.php --purge-missing --run
Run uninstall of all missing plugins.
# php uninstall_plugins.php --plugins=mod_assign,mod_forum
A dry run of uninstalling mod_assign and mod_forum plugins.
# php uninstall_plugins.php --plugins=mod_assign,mod_forum --run
Run uninstall for mod_assign and mod_forum plugins.
";
list($options, $unrecognised) = cli_get_params([
'help' => false,
'show-all' => false,
'show-contrib' => false,
'show-missing' => false,
'purge-missing' => false,
'plugins' => false,
'run' => false,
'showsql' => false,
'showdebugging' => false,
], [
'h' => 'help'
]);
if ($unrecognised) {
$unrecognised = implode(PHP_EOL.' ', $unrecognised);
cli_error(get_string('cliunknowoption', 'core_admin', $unrecognised));
}
if ($options['help']) {
cli_writeln($help);
exit(0);
}
if ($options['showdebugging']) {
set_debugging(DEBUG_DEVELOPER, true);
}
if ($options['showsql']) {
$DB->set_debug(true);
}
$pluginman = core_plugin_manager::instance();
$plugininfo = $pluginman->get_plugins();
if ($options['show-all'] || $options['show-missing'] || $options['show-contrib']) {
foreach ($plugininfo as $type => $plugins) {
foreach ($plugins as $name => $plugin) {
if ($options['show-contrib'] && $plugin->is_standard()) {
continue;
}
$pluginstring = $plugin->component . "\t" . $plugin->displayname;
if ($options['show-all'] || $options['show-contrib']) {
cli_writeln($pluginstring);
} else {
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
cli_writeln($pluginstring);
}
}
}
}
exit(0);
}
if ($options['purge-missing']) {
foreach ($plugininfo as $type => $plugins) {
foreach ($plugins as $name => $plugin) {
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
$pluginstring = $plugin->component . "\t" . $plugin->displayname;
if ($pluginman->can_uninstall_plugin($plugin->component)) {
if ($options['run']) {
cli_writeln('Uninstalling: ' . $pluginstring);
$progress = new progress_trace_buffer(new text_progress_trace(), true);
$pluginman->uninstall_plugin($plugin->component, $progress);
$progress->finished();
cli_write($progress->get_buffer());
} else {
cli_writeln('Will be uninstalled: ' . $pluginstring);
}
} else {
cli_writeln('Can not be uninstalled: ' . $pluginstring);
}
}
}
}
exit(0);
}
if ($options['plugins']) {
$components = explode(',', $options['plugins']);
foreach ($components as $component) {
$plugin = $pluginman->get_plugin_info($component);
if (is_null($plugin)) {
cli_writeln('Unknown plugin: ' . $component);
} else {
$pluginstring = $plugin->component . "\t" . $plugin->displayname;
if ($pluginman->can_uninstall_plugin($plugin->component)) {
if ($options['run']) {
cli_writeln('Uninstalling: ' . $pluginstring);
$progress = new progress_trace_buffer(new text_progress_trace(), true);
$pluginman->uninstall_plugin($plugin->component, $progress);
$progress->finished();
cli_write($progress->get_buffer());
} else {
cli_writeln('Will be uninstalled: ' . $pluginstring);
}
} else {
cli_writeln('Can not be uninstalled: ' . $pluginstring);
}
}
}
exit(0);
}
cli_writeln($help);
exit(0);
+2 -18
View File
@@ -52,8 +52,7 @@ list($options, $unrecognized) = cli_get_params(
'allow-unstable' => false,
'help' => false,
'lang' => $lang,
'verbose-settings' => false,
'is-pending' => false,
'verbose-settings' => false
),
array(
'h' => 'help'
@@ -89,8 +88,6 @@ Options:
--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:
@@ -119,10 +116,6 @@ if (!moodle_needs_upgrading()) {
cli_error(get_string('cliupgradenoneed', 'core_admin', $newversion), 0);
}
if ($options['is-pending']) {
cli_error(get_string('cliupgradepending', 'core_admin'), 2);
}
// Test environment first.
list($envstatus, $environment_results) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
if (!$envstatus) {
@@ -135,18 +128,9 @@ if (!$envstatus) {
exit(1);
}
// Make sure there are no files left over from previous versions.
if (upgrade_stale_php_files_present()) {
cli_problem(get_string('upgradestalefiles', 'admin'));
// Stale file info contains HTML elements which aren't suitable for CLI.
$upgradestalefilesinfo = get_string('upgradestalefilesinfo', 'admin', get_docs_url('Upgrading'));
cli_error(strip_tags($upgradestalefilesinfo));
}
// Test plugin dependencies.
$failed = array();
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
cli_error(get_string('pluginschecktodo', 'admin'));
}
-87
View File
@@ -1,87 +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/>.
/**
* Content bank and its plugins settings.
*
* @package core
* @subpackage contentbank
* @copyright 2020 Amaia Anabitarte <amaia@moodle.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/contentbank.php');
$PAGE->set_context($syscontext);
require_admin();
require_sesskey();
$return = new moodle_url('/admin/settings.php', array('section' => 'managecontentbanktypes'));
$plugins = core_plugin_manager::instance()->get_plugins_of_type('contenttype');
$sortorder = array_flip(array_keys($plugins));
if (!isset($plugins[$name])) {
throw new \moodle_exception('contenttypenotfound', 'error', $return, $name);
}
switch ($action) {
case 'disable':
if ($plugins[$name]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('contenttype');
$class::enable_plugin($name, false);
}
break;
case 'enable':
if (!$plugins[$name]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('contenttype');
$class::enable_plugin($name, true);
}
break;
case 'up':
if ($sortorder[$name]) {
$currentindex = $sortorder[$name];
$seq = array_keys($plugins);
$seq[$currentindex] = $seq[$currentindex - 1];
$seq[$currentindex - 1] = $name;
set_config('contentbank_plugins_sortorder', implode(',', $seq));
core_plugin_manager::reset_caches();
}
break;
case 'down':
if ($sortorder[$name] < count($sortorder) - 1) {
$currentindex = $sortorder[$name];
$seq = array_keys($plugins);
$seq[$currentindex] = $seq[$currentindex + 1];
$seq[$currentindex + 1] = $name;
set_config('contentbank_plugins_sortorder', implode(',', $seq));
core_plugin_manager::reset_caches();
}
break;
}
$cache = cache::make('core', 'contentbank_enabled_extensions');
$cache->purge();
$cache = cache::make('core', 'contentbank_context_extensions');
$cache->purge();
redirect($return);
-78
View File
@@ -1,78 +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'
);
$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();
+10 -6
View File
@@ -32,7 +32,8 @@ $syscontext = context_system::instance();
$PAGE->set_url('/admin/courseformats.php');
$PAGE->set_context($syscontext);
require_admin();
require_login();
require_capability('moodle/site:config', $syscontext);
require_sesskey();
$return = new moodle_url('/admin/settings.php', array('section' => 'manageformats'));
@@ -41,20 +42,23 @@ $formatplugins = core_plugin_manager::instance()->get_plugins_of_type('format');
$sortorder = array_flip(array_keys($formatplugins));
if (!isset($formatplugins[$formatname])) {
throw new \moodle_exception('courseformatnotfound', 'error', $return, $formatname);
print_error('courseformatnotfound', 'error', $return, $formatname);
}
switch ($action) {
case 'disable':
if ($formatplugins[$formatname]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('format');
$class::enable_plugin($formatname, false);
if (get_config('moodlecourse', 'format') === $formatname) {
print_error('cannotdisableformat', 'error', $return);
}
set_config('disabled', 1, 'format_'. $formatname);
core_plugin_manager::reset_caches();
}
break;
case 'enable':
if (!$formatplugins[$formatname]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('format');
$class::enable_plugin($formatname, true);
unset_config('disabled', 'format_'. $formatname);
core_plugin_manager::reset_caches();
}
break;
case 'up':
+2 -2
View File
@@ -58,7 +58,7 @@ require_once($CFG->libdir.'/cronlib.php');
// check if execution allowed
if (!empty($CFG->cronclionly)) {
// This script can only be run via the cli.
throw new \moodle_exception('cronerrorclionly', 'admin');
print_error('cronerrorclionly', 'admin');
exit;
}
// This script is being called via the web, so check the password if there is one.
@@ -66,7 +66,7 @@ if (!empty($CFG->cronremotepassword)) {
$pass = optional_param('password', '', PARAM_RAW);
if ($pass != $CFG->cronremotepassword) {
// wrong password.
throw new \moodle_exception('cronerrorpassword', 'admin');
print_error('cronerrorpassword', 'admin');
exit;
}
}
-61
View File
@@ -1,61 +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/>.
/**
* Allows the admin to enable, disable and uninstall custom fields
*
* @package core_admin
* @copyright 2018 Daniel Neis Araujo
* @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);
$customfieldname = required_param('field', PARAM_PLUGIN);
$syscontext = context_system::instance();
$PAGE->set_url('/admin/customfields.php');
$PAGE->set_context($syscontext);
require_admin();
require_sesskey();
$return = new moodle_url('/admin/settings.php', array('section' => 'managecustomfields'));
$customfieldplugins = core_plugin_manager::instance()->get_plugins_of_type('customfield');
$sortorder = array_flip(array_keys($customfieldplugins));
if (!isset($customfieldplugins[$customfieldname])) {
throw new \moodle_exception('customfieldnotfound', 'error', $return, $customfieldname);
}
switch ($action) {
case 'disable':
if ($customfieldplugins[$customfieldname]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('customfield');
$class::enable_plugin($customfieldname, false);
}
break;
case 'enable':
if (!$customfieldplugins[$customfieldname]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('customfield');
$class::enable_plugin($customfieldname, true);
}
break;
}
redirect($return);
+8 -6
View File
@@ -33,7 +33,8 @@ $syscontext = context_system::instance();
$PAGE->set_url('/admin/dataformats.php');
$PAGE->set_context($syscontext);
require_admin();
require_login();
require_capability('moodle/site:config', $syscontext);
require_sesskey();
$return = new moodle_url('/admin/settings.php', array('section' => 'managedataformats'));
@@ -42,20 +43,20 @@ $plugins = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
$sortorder = array_flip(array_keys($plugins));
if (!isset($plugins[$name])) {
throw new \moodle_exception('courseformatnotfound', 'error', $return, $name);
print_error('courseformatnotfound', 'error', $return, $name);
}
switch ($action) {
case 'disable':
if ($plugins[$name]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('dataformat');
$class::enable_plugin($name, false);
set_config('disabled', 1, 'dataformat_'. $name);
core_plugin_manager::reset_caches();
}
break;
case 'enable':
if (!$plugins[$name]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('dataformat');
$class::enable_plugin($name, true);
unset_config('disabled', 'dataformat_'. $name);
core_plugin_manager::reset_caches();
}
break;
case 'up':
@@ -78,3 +79,4 @@ switch ($action) {
break;
}
redirect($return);
+19 -11
View File
@@ -15,7 +15,8 @@ $confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/admin/editors.php', array('action'=>$action, 'editor'=>$editor));
$PAGE->set_context(context_system::instance());
require_admin();
require_login();
require_capability('moodle/site:config', context_system::instance());
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageeditors";
@@ -39,19 +40,22 @@ 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($editor, false);
// remove from enabled list
$key = array_search($editor, $active_editors);
unset($active_editors[$key]);
add_to_config_log('editor_visibility', '1', '0', $editor);
break;
case 'enable':
// Add to enabled list.
// add to enabled list
if (!in_array($editor, $active_editors)) {
$class = \core_plugin_manager::resolve_plugininfo_class('editor');
$class::enable_plugin($editor, true);
$active_editors[] = $editor;
$active_editors = array_unique($active_editors);
add_to_config_log('editor_visibility', '0', '1', $editor);
}
break;
@@ -65,8 +69,6 @@ switch ($action) {
$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;
@@ -81,8 +83,6 @@ switch ($action) {
$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;
@@ -91,6 +91,14 @@ switch ($action) {
break;
}
// at least one editor must be active
if (empty($active_editors)) {
$active_editors = array('textarea');
}
set_config('texteditors', implode(',', $active_editors));
core_plugin_manager::reset_caches();
if ($return) {
redirect ($returnurl);
}
+14 -6
View File
@@ -35,7 +35,8 @@ $confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/admin/enrol.php');
$PAGE->set_context(context_system::instance());
require_admin();
require_login();
require_capability('moodle/site:config', context_system::instance());
require_sesskey();
$enabled = enrol_get_plugins(true);
@@ -43,18 +44,25 @@ $all = enrol_get_plugins(false);
$return = new moodle_url('/admin/settings.php', array('section'=>'manageenrols'));
$syscontext = context_system::instance();
switch ($action) {
case 'disable':
$class = \core_plugin_manager::resolve_plugininfo_class('enrol');
$class::enable_plugin($enrol, false);
unset($enabled[$enrol]);
set_config('enrol_plugins_enabled', implode(',', array_keys($enabled)));
core_plugin_manager::reset_caches();
$syscontext->mark_dirty(); // resets all enrol caches
break;
case 'enable':
if (!isset($all[$enrol])) {
break;
}
$class = \core_plugin_manager::resolve_plugininfo_class('enrol');
$class::enable_plugin($enrol, true);
$enabled = array_keys($enabled);
$enabled[] = $enrol;
set_config('enrol_plugins_enabled', implode(',', $enabled));
core_plugin_manager::reset_caches();
$syscontext->mark_dirty(); // resets all enrol caches
break;
case 'up':
@@ -122,4 +130,4 @@ switch ($action) {
}
redirect($return);
redirect($return);
+2 -2
View File
@@ -55,11 +55,11 @@ if ($action == 'updatecomponent' && confirm_sesskey()) {
$a = new stdClass();
$a->url = 'https://download.moodle.org/environment/environment.zip';
$a->dest = $CFG->dataroot . '/';
throw new \moodle_exception($cd->get_error(), 'error', $PAGE->url, $a);
print_error($cd->get_error(), 'error', $PAGE->url, $a);
die();
} else {
throw new \moodle_exception($cd->get_error(), 'error', $PAGE->url);
print_error($cd->get_error(), 'error', $PAGE->url);
die();
}
File diff suppressed because it is too large Load Diff
+33 -43
View File
@@ -31,15 +31,14 @@ $filterpath = optional_param('filterpath', '', PARAM_PLUGIN);
admin_externalpage_setup('managefilters');
// Clean up bogus filter states first.
/** @var core\plugininfo\filter[] $plugininfos */
$plugininfos = core_plugin_manager::instance()->get_plugins_of_type('filter');
$filters = [];
$filters = array();
$states = filter_get_global_states();
foreach ($states as $state) {
if (!isset($plugininfos[$state->filter]) and !get_config('filter_'.$state->filter, 'version')) {
// Purge messy leftovers after incorrectly uninstalled plugins and unfinished installations.
$DB->delete_records('filter_active', ['filter' => $state->filter]);
$DB->delete_records('filter_config', ['filter' => $state->filter]);
// Purge messy leftovers after incorrectly uninstalled plugins and unfinished installs.
$DB->delete_records('filter_active', array('filter' => $state->filter));
$DB->delete_records('filter_config', array('filter' => $state->filter));
error_log('Deleted bogus "filter_'.$state->filter.'" states and config data.');
} else {
$filters[$state->filter] = $state;
@@ -51,6 +50,7 @@ foreach ($plugininfos as $filter => $info) {
if (isset($filters[$filter])) {
continue;
}
/** @var \core\plugininfo\base $info */
if ($info->is_installed_and_upgraded()) {
filter_set_global_state($filter, TEXTFILTER_DISABLED);
$states = filter_get_global_states();
@@ -72,9 +72,10 @@ switch ($action) {
case 'setstate':
if (isset($filters[$filterpath]) and $newstate = optional_param('newstate', '', PARAM_INT)) {
/** @var \core\plugininfo\filter $class */
$class = core_plugin_manager::resolve_plugininfo_class('filter');
$class::enable_plugin($filterpath, $newstate);
filter_set_global_state($filterpath, $newstate);
if ($newstate == TEXTFILTER_DISABLED) {
filter_set_applies_to_strings($filterpath, false);
}
}
break;
@@ -82,16 +83,12 @@ switch ($action) {
if (isset($filters[$filterpath])) {
$applytostrings = optional_param('stringstoo', false, PARAM_BOOL);
filter_set_applies_to_strings($filterpath, $applytostrings);
reset_text_filters_cache();
core_plugin_manager::reset_caches();
}
break;
case 'down':
if (isset($filters[$filterpath])) {
filter_set_global_state($filterpath, $filters[$filterpath]->active, 1);
reset_text_filters_cache();
core_plugin_manager::reset_caches();
}
break;
@@ -99,14 +96,14 @@ switch ($action) {
if (isset($filters[$filterpath])) {
$oldpos = $filters[$filterpath]->sortorder;
filter_set_global_state($filterpath, $filters[$filterpath]->active, -1);
reset_text_filters_cache();
core_plugin_manager::reset_caches();
}
break;
}
// Return.
// Reset caches and return.
if ($action) {
reset_text_filters_cache();
core_plugin_manager::reset_caches();
redirect(new moodle_url('/admin/filters.php'));
}
@@ -118,12 +115,12 @@ $states = filter_get_global_states();
$stringfilters = filter_get_string_filters();
$table = new html_table();
$table->head = [get_string('filter'), get_string('isactive', 'filters'),
get_string('order'), get_string('applyto', 'filters'), get_string('settings'), get_string('uninstallplugin', 'core_admin')];
$table->head = array(get_string('filter'), get_string('isactive', 'filters'),
get_string('order'), get_string('applyto', 'filters'), get_string('settings'), get_string('uninstallplugin', 'core_admin'));
$table->colclasses = array ('leftalign', 'leftalign', 'centeralign', 'leftalign', 'leftalign', 'leftalign');
$table->attributes['class'] = 'admintable generaltable';
$table->id = 'filterssetting';
$table->data = [];
$table->data = array();
$lastactive = null;
foreach ($states as $state) {
@@ -160,16 +157,15 @@ die;
/**
* Return action URL.
*
* @param string $filterpath which filter to get the URL for.
* @param string $action which action to get the URL for.
* @return moodle_url|null the requested URL.
* @param string $filterpath
* @param string $action
* @return moodle_url
*/
function filters_action_url(string $filterpath, string $action): ?moodle_url {
function filters_action_url($filterpath, $action) {
if ($action === 'delete') {
return core_plugin_manager::instance()->get_uninstall_url('filter_'.$filterpath, 'manage');
}
return new moodle_url('/admin/filters.php',
['sesskey' => sesskey(), 'filterpath' => $filterpath, 'action' => $action]);
return new moodle_url('/admin/filters.php', array('sesskey'=>sesskey(), 'filterpath'=>$filterpath, 'action'=>$action));
}
/**
@@ -182,25 +178,24 @@ function filters_action_url(string $filterpath, string $action): ?moodle_url {
* @param bool $applytostrings
* @return array data
*/
function get_table_row(\core\plugininfo\filter $plugininfo, stdClass $state,
bool $isfirstrow, bool $islastactive, bool $applytostrings): array {
function get_table_row(\core\plugininfo\filter $plugininfo, $state, $isfirstrow, $islastactive, $applytostrings) {
global $OUTPUT;
$row = [];
$row = array();
$filter = $state->filter;
$active = $plugininfo->is_installed_and_upgraded();
static $activechoices;
static $applytochoices;
if (!isset($activechoices)) {
$activechoices = [
$activechoices = array(
TEXTFILTER_DISABLED => get_string('disabled', 'core_filters'),
TEXTFILTER_OFF => get_string('offbutavailable', 'core_filters'),
TEXTFILTER_ON => get_string('on', 'core_filters'),
];
$applytochoices = [
);
$applytochoices = array(
0 => get_string('content', 'core_filters'),
1 => get_string('contentandheadings', 'core_filters'),
];
);
}
// Filter name.
@@ -214,7 +209,7 @@ function get_table_row(\core\plugininfo\filter $plugininfo, stdClass $state,
// Disable/off/on.
$select = new single_select(filters_action_url($filter, 'setstate'), 'newstate', $activechoices, $state->active, null, 'active' . $filter);
$select->set_label(get_string('isactive', 'filters'), ['class' => 'accesshide']);
$select->set_label(get_string('isactive', 'filters'), array('class' => 'accesshide'));
$row[] = $OUTPUT->render($select);
// Re-order.
@@ -222,14 +217,12 @@ function get_table_row(\core\plugininfo\filter $plugininfo, stdClass $state,
$spacer = $OUTPUT->spacer();
if ($state->active != TEXTFILTER_DISABLED) {
if (!$isfirstrow) {
$updown .= $OUTPUT->action_icon(filters_action_url($filter, 'up'),
new pix_icon('t/up', get_string('up'), '', ['class' => 'iconsmall']));
$updown .= $OUTPUT->action_icon(filters_action_url($filter, 'up'), new pix_icon('t/up', get_string('up'), '', array('class' => 'iconsmall')));
} else {
$updown .= $spacer;
}
if (!$islastactive) {
$updown .= $OUTPUT->action_icon(filters_action_url($filter, 'down'),
new pix_icon('t/down', get_string('down'), '', ['class' => 'iconsmall']));
$updown .= $OUTPUT->action_icon(filters_action_url($filter, 'down'), new pix_icon('t/down', get_string('down'), '', array('class' => 'iconsmall')));
} else {
$updown .= $spacer;
}
@@ -237,23 +230,20 @@ function get_table_row(\core\plugininfo\filter $plugininfo, stdClass $state,
$row[] = $updown;
// Apply to strings.
$select = new single_select(filters_action_url($filter, 'setapplyto'),
'stringstoo', $applytochoices, $applytostrings, null, 'applyto' . $filter);
$select->set_label(get_string('applyto', 'filters'), ['class' => 'accesshide']);
$select = new single_select(filters_action_url($filter, 'setapplyto'), 'stringstoo', $applytochoices, $applytostrings, null, 'applyto' . $filter);
$select->set_label(get_string('applyto', 'filters'), array('class' => 'accesshide'));
$select->disabled = ($state->active == TEXTFILTER_DISABLED);
$row[] = $OUTPUT->render($select);
// Settings link, if required.
if ($active and filter_has_global_settings($filter)) {
$row[] = html_writer::link(new moodle_url('/admin/settings.php',
['section' => 'filtersetting'.$filter]), get_string('settings'));
$row[] = html_writer::link(new moodle_url('/admin/settings.php', array('section'=>'filtersetting'.$filter)), get_string('settings'));
} else {
$row[] = '';
}
// Uninstall.
$row[] = html_writer::link(filters_action_url($filter, 'delete'),
get_string('uninstallplugin', 'core_admin'));
$row[] = html_writer::link(filters_action_url($filter, 'delete'), get_string('uninstallplugin', 'core_admin'));
return $row;
}
+24 -78
View File
@@ -53,12 +53,6 @@ if (!extension_loaded('xml')) {
die();
}
// Make sure mbstring extension is available.
if (!extension_loaded('mbstring')) {
echo 'Moodle requires the mbstring PHP extension. Please install or enable the mbstring extension.';
die();
}
define('NO_OUTPUT_BUFFERING', true);
if (isset($_POST['upgradekey'])) {
@@ -174,17 +168,15 @@ $documentationlink = '<a href="http://docs.moodle.org/en/Installation">Installat
// Check some PHP server settings
if (ini_get_bool('session.auto_start')) {
throw new \moodle_exception('phpvaroff', 'debug', '',
(object)array('name' => 'session.auto_start', 'link' => $documentationlink));
print_error('phpvaroff', 'debug', '', (object)array('name'=>'session.auto_start', 'link'=>$documentationlink));
}
if (!ini_get_bool('file_uploads')) {
throw new \moodle_exception('phpvaron', 'debug', '',
(object)array('name' => 'file_uploads', 'link' => $documentationlink));
print_error('phpvaron', 'debug', '', (object)array('name'=>'file_uploads', 'link'=>$documentationlink));
}
if (is_float_problem()) {
throw new \moodle_exception('phpfloatproblem', 'admin', '', $documentationlink);
print_error('phpfloatproblem', 'admin', '', $documentationlink);
}
// Set some necessary variables during set-up to avoid PHP warnings later on this page
@@ -205,7 +197,7 @@ require("$CFG->dirroot/version.php"); // defines $version, $release, $bran
$CFG->target_release = $release; // used during installation and upgrades
if (!$version or !$release) {
throw new \moodle_exception('withoutversion', 'debug'); // Without version, stop.
print_error('withoutversion', 'debug'); // without version, stop
}
if (!core_tables_exist()) {
@@ -234,7 +226,7 @@ if (!core_tables_exist()) {
}
if (empty($confirmrelease)) {
require_once($CFG->libdir.'/environmentlib.php');
list($envstatus, $environmentresults) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
list($envstatus, $environment_results) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
$strcurrentrelease = get_string('currentrelease');
$PAGE->navbar->add($strcurrentrelease);
@@ -243,13 +235,13 @@ if (!core_tables_exist()) {
$PAGE->set_cacheable(false);
$output = $PAGE->get_renderer('core', 'admin');
echo $output->install_environment_page($maturity, $envstatus, $environmentresults, $release);
echo $output->install_environment_page($maturity, $envstatus, $environment_results, $release);
die();
}
// check plugin dependencies
$failed = array();
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed, $CFG->branch)) {
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
$PAGE->navbar->add(get_string('pluginscheck', 'admin'));
$PAGE->set_title($strinstallation);
$PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
@@ -277,7 +269,7 @@ if (!core_tables_exist()) {
if (!$DB->setup_is_unicodedb()) {
if (!$DB->change_db_encoding()) {
// If could not convert successfully, throw error, and prevent installation
throw new \moodle_exception('unicoderequired', 'admin');
print_error('unicoderequired', 'admin');
}
}
@@ -299,7 +291,7 @@ $stradministration = get_string('administration');
$PAGE->set_context(context_system::instance());
if (empty($CFG->version)) {
throw new \moodle_exception('missingconfigversion', 'debug');
print_error('missingconfigversion', 'debug');
}
// Detect config cache inconsistency, this happens when you switch branches on dev servers.
@@ -366,9 +358,9 @@ if (!$cache and $version > $CFG->version) { // upgrade
echo $output->upgrade_confirm_page($a->newversion, $maturity, $testsite);
die();
} else if (empty($confirmrelease)) {
} else if (empty($confirmrelease)){
require_once($CFG->libdir.'/environmentlib.php');
list($envstatus, $environmentresults) = check_moodle_environment($release, ENV_SELECT_RELEASE);
list($envstatus, $environment_results) = check_moodle_environment($release, ENV_SELECT_RELEASE);
$strcurrentrelease = get_string('currentrelease');
$PAGE->navbar->add($strcurrentrelease);
@@ -376,7 +368,7 @@ if (!$cache and $version > $CFG->version) { // upgrade
$PAGE->set_heading($strcurrentrelease);
$PAGE->set_cacheable(false);
echo $output->upgrade_environment_page($release, $envstatus, $environmentresults);
echo $output->upgrade_environment_page($release, $envstatus, $environment_results);
die();
} else if (empty($confirmplugins)) {
@@ -516,9 +508,8 @@ if (!$cache and $version > $CFG->version) { // upgrade
} 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)));
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
die();
}
unset($failed);
@@ -542,10 +533,7 @@ if (!$cache and $branch <> $CFG->branch) { // Update the branch
if (!$cache and moodle_needs_upgrading()) {
$PAGE->set_url(new moodle_url($PAGE->url, array(
'confirmrelease' => $confirmrelease,
'confirmplugincheck' => $confirmplugins,
)));
$PAGE->set_url(new moodle_url($PAGE->url, array('confirmplugincheck' => $confirmplugins)));
check_upgrade_key($upgradekeyhash);
@@ -555,21 +543,7 @@ if (!$cache and moodle_needs_upgrading()) {
$pluginman = core_plugin_manager::instance();
$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) {
if (!$confirmplugins) {
$strplugincheck = get_string('plugincheck');
$PAGE->navbar->add($strplugincheck);
@@ -708,10 +682,9 @@ if (!$cache and moodle_needs_upgrading()) {
// Make sure plugin dependencies are always checked.
$failed = array();
if (!$pluginman->all_plugins_ok($version, $failed, $CFG->branch)) {
if (!$pluginman->all_plugins_ok($version, $failed)) {
$output = $PAGE->get_renderer('core', 'admin');
echo $output->unsatisfied_dependencies_page($version, $failed, new moodle_url($PAGE->url,
array('confirmplugincheck' => 0)));
echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
die();
}
unset($failed);
@@ -727,12 +700,6 @@ 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.
// 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);
}
// we need this redirect to setup proper session
upgrade_finished("index.php?sessionstarted=1&amp;lang=$CFG->lang");
}
@@ -750,7 +717,7 @@ if (during_initial_install()) {
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");
print_error('installsessionerror', 'admin', "index.php?sessionstarted=1&lang=$CFG->lang");
}
unset($SESSION->sessionverify);
}
@@ -767,7 +734,7 @@ if (during_initial_install()) {
if ($adminuser->password === 'adminsetuppending') {
// prevent installation hijacking
if ($adminuser->lastip !== getremoteaddr()) {
throw new \moodle_exception('installhijacked', 'admin');
print_error('installhijacked', 'admin');
}
// login user and let him set password and admin details
$adminuser->newadminuser = 1;
@@ -833,10 +800,9 @@ $insecuredataroot = is_dataroot_insecure(true);
$SESSION->admin_critical_warning = ($insecuredataroot==INSECURE_DATAROOT_ERROR);
$adminroot = admin_get_root();
$PAGE->set_primary_active_tab('siteadminnode');
// Check if there are any new admin settings which have still yet to be set
if (any_new_admin_settings($adminroot)) {
if (any_new_admin_settings($adminroot)){
redirect('upgradesettings.php');
}
@@ -857,12 +823,9 @@ if (isset($SESSION->pluginuninstallreturn)) {
// Print default admin page with notifications.
$errorsdisplayed = defined('WARN_DISPLAY_ERRORS_ENABLED');
$lastcron = get_config('tool_task', 'lastcronstart');
// We make the assumption that at least one schedule task should run once per day.
$lastcron = $DB->get_field_sql('SELECT MAX(lastruntime) FROM {task_scheduled}');
$cronoverdue = ($lastcron < time() - 3600 * 24);
$lastcroninterval = get_config('tool_task', 'lastcroninterval');
$expectedfrequency = $CFG->expectedcronfrequency ?? MINSECS;
$croninfrequent = !$cronoverdue && ($lastcroninterval > ($expectedfrequency + MINSECS) || $lastcron < time() - $expectedfrequency);
$dbproblems = $DB->diagnose();
$maintenancemode = !empty($CFG->maintenance_enabled);
@@ -916,21 +879,6 @@ if (empty($CFG->disabledevlibdirscheck) && (is_dir($CFG->dirroot.'/vendor') || i
// Check if the site is being foced onto ssl.
$overridetossl = !empty($CFG->overridetossl);
// Check if moodle campaign content setting is enabled or not.
$showcampaigncontent = !isset($CFG->showcampaigncontent) || $CFG->showcampaigncontent;
// Encourage admins to enable the user feedback feature if it is not enabled already.
$showfeedbackencouragement = empty($CFG->enableuserfeedback);
// Check if the service and support content setting is enabled or not.
$servicesandsupportcontent = !isset($CFG->showservicesandsupportcontent) || $CFG->showservicesandsupportcontent;
// Check whether the XML-RPC protocol is enabled or not.
require_once($CFG->libdir . '/environmentlib.php');
$result = new environment_results('custom_checks');
$result = check_xmlrpc_usage($result);
$xmlrpcwarning = !is_null($result) ? get_string($result->getFeedbackStr(), 'admin') : '';
admin_externalpage_setup('adminnotifications');
$output = $PAGE->get_renderer('core', 'admin');
@@ -938,6 +886,4 @@ $output = $PAGE->get_renderer('core', 'admin');
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
$maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
$registered, $cachewarnings, $eventshandlers, $themedesignermode, $devlibdir,
$mobileconfigured, $overridetossl, $invalidforgottenpasswordurl, $croninfrequent,
$showcampaigncontent, $showfeedbackencouragement, $servicesandsupportcontent,
$xmlrpcwarning);
$mobileconfigured, $overridetossl, $invalidforgottenpasswordurl);
+9 -5
View File
@@ -55,7 +55,7 @@ function admin_page_type_list($pagetype, $parentcontext, $currentcontext) {
function core_admin_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) {
global $CFG;
if (in_array($filearea, ['logo', 'logocompact', 'favicon'])) {
if (in_array($filearea, ['logo', 'logocompact'])) {
$size = array_shift($args); // The path hides the size.
$itemid = clean_param(array_shift($args), PARAM_INT);
$filename = clean_param(array_shift($args), PARAM_FILE);
@@ -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);
+57
View File
@@ -0,0 +1,57 @@
<?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 admin to configure licenses.
*/
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/licenselib.php');
require_login();
require_capability('moodle/site:config', context_system::instance());
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=managelicenses";
$action = optional_param('action', '', PARAM_ALPHANUMEXT);
$license = optional_param('license', '', PARAM_SAFEDIR);
////////////////////////////////////////////////////////////////////////////////
// process actions
if (!confirm_sesskey()) {
redirect($returnurl);
}
$return = true;
switch ($action) {
case 'disable':
license_manager::disable($license);
break;
case 'enable':
license_manager::enable($license);
break;
default:
break;
}
if ($return) {
redirect ($returnurl);
}
+1 -1
View File
@@ -45,7 +45,7 @@ if (isset($_ENV['TMPDIR']) && is_dir($_ENV['TMPDIR'])) {
$tmpfile = $tmpdir . '/moodle-mailout.log';
$fh = fopen($tmpfile, 'a+', false)
or mdie("Error openning $tmpfile on append\n");
fwrite($fh, "==== ".date("D M d H:i:s Y", time())." ====\n");
fwrite($fh, "==== ".strftime("%a %b %e %H:%M:%S %Y", time())." ====\n");
fwrite($fh, "==== Commandline: " . implode(' ',$argv) . "\n");
$stdin = fopen('php://stdin', 'r');
+4 -5
View File
@@ -35,7 +35,8 @@ $confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/admin/media.php');
$PAGE->set_context(context_system::instance());
require_admin();
require_login();
require_capability('moodle/site:config', context_system::instance());
require_sesskey();
$plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
@@ -49,13 +50,11 @@ if (!array_key_exists($media, $plugins)) {
switch ($action) {
case 'disable':
$class = \core_plugin_manager::resolve_plugininfo_class('media');
$class::enable_plugin($media, false);
$plugins[$media]->set_enabled(false);
break;
case 'enable':
$class = \core_plugin_manager::resolve_plugininfo_class('media');
$class::enable_plugin($media, true);
$plugins[$media]->set_enabled(true);
break;
case 'up':
+28 -90
View File
@@ -25,109 +25,47 @@ require_once(__DIR__ . '/../config.php');
require_once($CFG->dirroot . '/message/lib.php');
require_once($CFG->libdir.'/adminlib.php');
// This is an admin page.
// This is an admin page
admin_externalpage_setup('managemessageoutputs');
// Fetch processors.
$allprocessors = get_message_processors();
$processors = array_filter($allprocessors, function($processor) {
return $processor->enabled;
});
$disabledprocessors = array_filter($allprocessors, function($processor) {
return !$processor->enabled;
});
// Get the submitted params
$disable = optional_param('disable', 0, PARAM_INT);
$enable = optional_param('enable', 0, PARAM_INT);
// Fetch message providers.
$providers = get_message_providers();
// Fetch the manage message outputs interface.
$preferences = get_message_output_default_preferences();
$headingtitle = get_string('managemessageoutputs', 'message');
if (($form = data_submitted()) && confirm_sesskey()) {
$newpreferences = array();
// Prepare default message outputs settings.
foreach ($providers as $provider) {
$componentproviderbase = $provider->component.'_'.$provider->name;
$disableprovidersetting = $componentproviderbase.'_disable';
if (!isset($form->$disableprovidersetting)) {
$newpreferences[$disableprovidersetting] = 1;
} else {
$newpreferences[$disableprovidersetting] = 0;
}
$componentprovidersetting = $componentproviderbase.'_locked';
foreach ($processors as $processor) {
$value = 0;
if (isset($form->{$componentprovidersetting}[$processor->name])) {
$value = $form->{$componentprovidersetting}[$processor->name];
if ($value == 'on') {
$value = 1;
}
}
// Record the site preference.
$newpreferences[$processor->name.'_provider_'.$componentprovidersetting] = $value;
}
$componentprovidersetting = $componentproviderbase.'_enabled';
$newsettings = [];
if (isset($form->$componentprovidersetting)) {
// Store defined comma-separated processors as setting value.
// Using array_filter eliminates elements set to 0 above.
$newsettings = array_keys(array_filter($form->{$componentprovidersetting}));
}
// Let's join existing setting values for disabled processors.
$property = 'message_provider_'.$componentprovidersetting;
if (property_exists($preferences, $property)) {
$existingsetting = $preferences->$property;
foreach ($disabledprocessors as $disable) {
if (strpos($existingsetting, $disable->name) > -1) {
$newsettings[] = $disable->name;
}
}
}
$value = join(',', $newsettings);
if (empty($value)) {
$value = null;
}
// Record the site preference.
$newpreferences['message_provider_'.$componentprovidersetting] = $value;
if (!empty($disable) && confirm_sesskey()) {
if (!$processor = $DB->get_record('message_processors', array('id'=>$disable))) {
print_error('outputdoesnotexist', 'message');
}
// Update database.
$transaction = $DB->start_delegated_transaction();
// Save processors enabled/disabled status.
foreach ($allprocessors as $processor) {
$enabled = isset($form->{$processor->name});
$class = \core_plugin_manager::resolve_plugininfo_class('message');
$class::enable_plugin($processor->name, $enabled);
}
foreach ($newpreferences as $name => $value) {
$old = isset($preferences->$name) ? $preferences->$name : '';
if ($old != $value) {
add_to_config_log($name, $old, $value, 'core');
}
set_config($name, $value, 'message');
}
$transaction->allow_commit();
\core_message\api::update_processor_status($processor, 0); // Disable output.
core_plugin_manager::reset_caches();
}
if (!empty($enable) && confirm_sesskey()) {
if (!$processor = $DB->get_record('message_processors', array('id'=>$enable))) {
print_error('outputdoesnotexist', 'message');
}
\core_message\api::update_processor_status($processor, 1); // Enable output.
core_plugin_manager::reset_caches();
}
if ($disable || $enable) {
$url = new moodle_url('message.php');
redirect($url);
}
// Page settings
$PAGE->set_context(context_system::instance());
// Grab the renderer
$renderer = $PAGE->get_renderer('core', 'message');
// Display the page.
// Display the manage message outputs interface
$processors = get_message_processors();
$messageoutputs = $renderer->manage_messageoutputs($processors);
// Display the page
echo $OUTPUT->header();
echo $renderer->manage_messageoutput_settings($allprocessors, $processors, $providers, $preferences);
echo $OUTPUT->heading($headingtitle);
echo $messageoutputs;
echo $OUTPUT->footer();
+8 -16
View File
@@ -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);
@@ -15,7 +15,7 @@ $action = trim(strtolower(optional_param('action', '', PARAM_ALPHA)));
admin_externalpage_setup('ssoaccesscontrol');
if (!extension_loaded('openssl')) {
throw new \moodle_exception('requiresopenssl', 'mnet');
print_error('requiresopenssl', 'mnet');
}
$sitecontext = context_system::instance();
@@ -35,13 +35,13 @@ if (!empty($action) and confirm_sesskey()) {
// boot if insufficient permission
if (!has_capability('moodle/user:delete', $sitecontext)) {
throw new \moodle_exception('nomodifyacl', 'mnet');
print_error('nomodifyacl','mnet');
}
// fetch the record in question
$id = required_param('id', PARAM_INT);
if (!$idrec = $DB->get_record('mnet_sso_access_control', array('id'=>$id))) {
throw new \moodle_exception('recordnoexists', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
print_error('recordnoexists','mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
}
switch ($action) {
@@ -56,7 +56,7 @@ if (!empty($action) and confirm_sesskey()) {
// require the access parameter, and it must be 'allow' or 'deny'
$accessctrl = trim(strtolower(required_param('accessctrl', PARAM_ALPHA)));
if ($accessctrl != 'allow' and $accessctrl != 'deny') {
throw new \moodle_exception('invalidaccessparam', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
print_error('invalidaccessparam', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
}
if (mnet_update_sso_access_control($idrec->username, $idrec->mnet_host_id, $accessctrl)) {
@@ -71,7 +71,7 @@ if (!empty($action) and confirm_sesskey()) {
break;
default:
throw new \moodle_exception('invalidactionparam', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
print_error('invalidactionparam', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
}
}
@@ -82,7 +82,7 @@ if ($form = data_submitted() and confirm_sesskey()) {
// check permissions and verify form input
if (!has_capability('moodle/user:delete', $sitecontext)) {
throw new \moodle_exception('nomodifyacl', 'mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
print_error('nomodifyacl','mnet', "$CFG->wwwroot/$CFG->admin/mnet/access_control.php");
}
if (empty($form->username)) {
$formerror['username'] = get_string('enterausername','mnet');
@@ -153,15 +153,7 @@ foreach ($columns as $column) {
$headings[$column] = "<a href=\"?sort=$column&amp;dir=$columndir&amp;\">".$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) {
+3
View File
@@ -34,6 +34,9 @@ $step = optional_param('step', 'verify', PARAM_ALPHA);
$hostid = required_param('hostid', PARAM_INT);
$context = context_system::instance();
$mnet = get_mnet_environment();
$PAGE->set_url('/admin/mnet/delete.php');
+7 -22
View File
@@ -17,13 +17,13 @@
if (!extension_loaded('openssl')) {
echo $OUTPUT->header();
set_config('mnet_dispatcher_mode', 'off');
throw new \moodle_exception('requiresopenssl', 'mnet');
print_error('requiresopenssl', 'mnet');
}
if (!function_exists('curl_init') ) {
echo $OUTPUT->header();
set_config('mnet_dispatcher_mode', 'off');
throw new \moodle_exception('nocurl', 'mnet');
print_error('nocurl', 'mnet');
}
if (!isset($CFG->mnet_dispatcher_mode)) {
@@ -37,7 +37,7 @@
if (set_config('mnet_dispatcher_mode', $form->mode)) {
redirect('index.php', get_string('changessaved'));
} else {
throw new \moodle_exception('invalidaction', '', 'index.php');
print_error('invalidaction', '', 'index.php');
}
}
} elseif (!empty($form->submit) && $form->submit == get_string('delete')) {
@@ -46,23 +46,11 @@
$formcontinue = new single_button(new moodle_url('index.php', array('confirm' => md5($mnet->public_key))), get_string('yes'));
$formcancel = new single_button(new moodle_url('index.php', array()), get_string('no'));
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string("deletekeycheck", "mnet"), $formcontinue, $formcancel);
echo $OUTPUT->footer();
exit;
} else {
// We're deleting
// If no/cancel then redirect back to the network setting page.
if (!isset($form->confirm)) {
redirect(
new moodle_url('/admin/mnet/index.php'),
get_string('keydeletedcancelled', 'mnet'),
null,
\core\output\notification::NOTIFY_SUCCESS
);
}
if (!isset($SESSION->mnet_confirm_delete_key)) {
// fail - you're being attacked?
@@ -75,22 +63,19 @@
if($time < time() - 60) {
// fail - you're out of time.
redirect(
new moodle_url('/admin/mnet/index.php'),
get_string('deleteoutoftime', 'mnet'),
null,
\core\output\notification::NOTIFY_WARNING
);
print_error ('deleteoutoftime', 'mnet', 'index.php');
exit;
}
if ($key != md5(sha1($mnet->keypair['keypair_PEM']))) {
// fail - you're being attacked?
throw new \moodle_exception ('deletewrongkeyvalue', 'mnet', 'index.php');
print_error ('deletewrongkeyvalue', 'mnet', 'index.php');
exit;
}
$mnet->replace_keys();
redirect('index.php', get_string('keydeleted','mnet'));
exit;
}
}
$hosts = $DB->get_records_select('mnet_host', "id <> ? AND deleted = 0", array($CFG->mnet_localhost_id), 'wwwroot ASC');
+4 -3
View File
@@ -59,8 +59,9 @@ class mnet_simple_host_form extends moodleform {
$wwwroot = 'http://'.$wwwroot;
}
if ($host = $DB->get_record('mnet_host', array('wwwroot' => $wwwroot))) {
$str = get_string('hostexists', 'mnet', (new moodle_url('/admin/mnet/peers.php', ['hostid' => $host->id]))->out());
return array('wwwroot' => $str);
global $CFG;
return array('wwwroot' => get_string('hostexists', 'mnet',
new moodle_url('/admin/mnet/peers.php', array('hostid' => $host->id))));
}
return array();
}
@@ -155,7 +156,7 @@ class mnet_review_host_form extends moodleform {
if ($mnet_peer && !empty($mnet_peer->deleted)) {
$radioarray = array();
$radioarray[] = $mform->createElement('static', 'deletedinfo', '',
$OUTPUT->container(get_string('deletedhostinfo', 'mnet'), 'alert alert-warning'));
$OUTPUT->container(get_string('deletedhostinfo', 'mnet'), 'deletedhostinfo'));
$radioarray[] = $mform->createElement('radio', 'deleted', '', get_string('yes'), 1);
$radioarray[] = $mform->createElement('radio', 'deleted', '', get_string('no'), 0);
$mform->addGroup($radioarray, 'radioar', get_string('deleted'), array(' ', ' '), false);
+7 -3
View File
@@ -52,11 +52,15 @@ $PAGE->set_url('/admin/mnet/peers.php');
admin_externalpage_setup($adminsection);
if (!extension_loaded('openssl')) {
throw new \moodle_exception('requiresopenssl', 'mnet');
print_error('requiresopenssl', 'mnet');
}
if (!function_exists('curl_init') ) {
throw new \moodle_exception('nocurl', 'mnet');
print_error('nocurl', 'mnet');
}
if (!function_exists('xmlrpc_encode_request')) {
print_error('xmlrpc-missing', 'mnet');
}
if (!isset($CFG->mnet_dispatcher_mode)) {
@@ -169,7 +173,7 @@ if ($formdata = $reviewform->get_data()) {
if ($mnet_peer->commit()) {
redirect(new moodle_url('/admin/mnet/peers.php', array('hostid' => $mnet_peer->id)), get_string('changessaved'));
} else {
throw new \moodle_exception('invalidaction', 'error', 'index.php');
print_error('invalidaction', 'error', 'index.php');
}
} else if ($reviewform->is_submitted()) { // submitted, but errors
echo $OUTPUT->header();
+2 -2
View File
@@ -18,7 +18,7 @@ require_once($CFG->libdir.'/adminlib.php');
include_once($CFG->dirroot.'/mnet/lib.php');
if ($CFG->mnet_dispatcher_mode === 'off') {
throw new \moodle_exception('mnetdisabled', 'mnet');
print_error('mnetdisabled', 'mnet');
}
admin_externalpage_setup('mnettestclient');
@@ -27,7 +27,7 @@ error_reporting(DEBUG_ALL);
echo $OUTPUT->header();
if (!extension_loaded('openssl')) {
throw new \moodle_exception('requiresopenssl', 'mnet', '', null, true);
print_error('requiresopenssl', 'mnet', '', NULL, true);
}
// optional drilling down parameters
+1 -1
View File
@@ -10,7 +10,7 @@
if (!extension_loaded('openssl')) {
echo $OUTPUT->header();
throw new \moodle_exception('requiresopenssl', 'mnet', '', null, true);
print_error('requiresopenssl', 'mnet', '', NULL, true);
}
$site = get_site();
+38 -15
View File
@@ -30,21 +30,42 @@
/// If data submitted, then process and store.
if (!empty($hide) and confirm_sesskey()) {
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
if ($class::enable_plugin($hide, false)) {
// Settings not required - only pages.
admin_get_root(true, false);
if (!$module = $DB->get_record("modules", array("name"=>$hide))) {
print_error('moduledoesnotexist', 'error');
}
redirect(new moodle_url('/admin/modules.php'));
$DB->set_field("modules", "visible", "0", array("id"=>$module->id)); // Hide main module
// Remember the visibility status in visibleold
// and hide...
$sql = "UPDATE {course_modules}
SET visibleold=visible, visible=0
WHERE module=?";
$DB->execute($sql, array($module->id));
// Increment course.cacherev for courses where we just made something invisible.
// This will force cache rebuilding on the next request.
increment_revision_number('course', 'cacherev',
"id IN (SELECT DISTINCT course
FROM {course_modules}
WHERE visibleold=1 AND module=?)",
array($module->id));
core_plugin_manager::reset_caches();
admin_get_root(true, false); // settings not required - only pages
}
if (!empty($show) && confirm_sesskey()) {
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
if ($class::enable_plugin($show, true)) {
// Settings not required - only pages.
admin_get_root(true, false);
if (!empty($show) and confirm_sesskey()) {
if (!$module = $DB->get_record("modules", array("name"=>$show))) {
print_error('moduledoesnotexist', 'error');
}
redirect(new moodle_url('/admin/modules.php'));
$DB->set_field("modules", "visible", "1", array("id"=>$module->id)); // Show main module
$DB->set_field('course_modules', 'visible', '1', array('visibleold'=>1, 'module'=>$module->id)); // Get the previous saved visible state for the course module.
// Increment course.cacherev for courses where we just made something visible.
// This will force cache rebuilding on the next request.
increment_revision_number('course', 'cacherev',
"id IN (SELECT DISTINCT course
FROM {course_modules}
WHERE visible=1 AND module=?)",
array($module->id));
core_plugin_manager::reset_caches();
admin_get_root(true, false); // settings not required - only pages
}
echo $OUTPUT->header();
@@ -53,7 +74,7 @@
/// Get and sort the existing modules
if (!$modules = $DB->get_records('modules', array(), 'name ASC')) {
throw new \moodle_exception('moduledoesnotexist', 'error');
print_error('moduledoesnotexist', 'error');
}
/// Print the table of all modules
@@ -77,7 +98,7 @@
$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=\"\" />";
$icon = "<img src=\"" . $OUTPUT->image_url('icon', $module->name) . "\" class=\"icon\" alt=\"\" />";
$strmodulename = $icon.' '.get_string('modulename', $module->name);
$missing = false;
}
@@ -100,8 +121,8 @@
$count = -1;
}
if ($count>0) {
$countlink = $OUTPUT->action_link(new moodle_url('/course/search.php', ['modulelist' => $module->name]),
$count, null, ['title' => $strshowmodulecourse]);
$countlink = "<a href=\"{$CFG->wwwroot}/course/search.php?modulelist=$module->name" .
"&amp;sesskey=".sesskey()."\" title=\"$strshowmodulecourse\">$count</a>";
} else if ($count < 0) {
$countlink = get_string('error');
} else {
@@ -140,3 +161,5 @@
$table->print_html();
echo $OUTPUT->footer();
+12 -25
View File
@@ -30,41 +30,28 @@
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) {
print_error($message);
} else {
print_error($error);
}
// Not logged in or the sesskey verification failed, redirect to login + show errors.
$SESSION->loginerrormsg = $message ?? $error;
redirect(new moodle_url(get_login_url()));
die();
}
// 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);
redirect($redirecturl);
} else {
$SESSION->loginerrormsg = get_string('invalidsesskey', 'error');
redirect(new moodle_url(get_login_url()));
print_error('invalidsesskey');
}
+3 -4
View File
@@ -43,8 +43,9 @@ $confirminstallupdate = optional_param('confirminstallupdate', false, PARAM_BOOL
// NOTE: do not use admin_externalpage_setup() here because it loads
// full admin tree which is not possible during uninstallation.
require_admin();
require_login();
$syscontext = context_system::instance();
require_capability('moodle/site:config', $syscontext);
// URL params we want to maintain on redirects.
$pageparams = array('updatesonly' => $updatesonly, 'contribonly' => $contribonly);
@@ -52,9 +53,8 @@ $pageurl = new moodle_url('/admin/plugins.php', $pageparams);
$pluginman = core_plugin_manager::instance();
$PAGE->set_primary_active_tab('siteadminnode');
if ($uninstall) {
require_sesskey();
if (!$confirmed) {
admin_externalpage_setup('pluginsoverview', '', $pageparams);
@@ -93,7 +93,6 @@ if ($uninstall) {
exit();
} else {
require_sesskey();
$SESSION->pluginuninstallreturn = $pluginfo->get_return_url_after_uninstall($return);
$progress = new progress_trace_buffer(new text_progress_trace(), false);
$pluginman->uninstall_plugin($pluginfo->component, $progress);
+11 -5
View File
@@ -102,27 +102,32 @@ if (($action == 'edit') || ($action == 'new')) {
require_sesskey();
$instance = portfolio_instance($portfolio);
$plugin = $instance->get('plugin');
$current = $instance->get('visible');
if (empty($current) && $instance->instance_sanity_check()) {
print_error('cannotsetvisible', 'portfolio', $baseurl);
}
if ($action == 'show') {
$visible = 1;
} else {
$visible = 0;
}
$class = \core_plugin_manager::resolve_plugininfo_class('portfolio');
$class::enable_plugin($plugin, $visible);
$instance->set('visible', $visible);
$instance->save();
core_plugin_manager::reset_caches();
$return = true;
} else if ($action == 'delete') {
$instance = portfolio_instance($portfolio);
if ($sure) {
if (!confirm_sesskey()) {
throw new \moodle_exception('confirmsesskeybad', '', $baseurl);
print_error('confirmsesskeybad', '', $baseurl);
}
if ($instance->delete()) {
$deletedstr = get_string('instancedeleted', 'portfolio');
redirect($baseurl, $deletedstr, 1);
} else {
throw new \moodle_exception('instancenotdeleted', 'portfolio', $baseurl);
print_error('instancenotdeleted', 'portfolio', $baseurl);
}
exit;
} else {
@@ -241,3 +246,4 @@ if ($return) {
}
echo $OUTPUT->footer();
-390
View File
@@ -1,390 +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_adminpresets;
/**
* Admin presets helper class.
*
* @package core_adminpresets
* @copyright 2021 Sara Arjona (sara@moodle.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Create an empty preset.
*
* @param array $data Preset data. Supported values:
* - name. To define the preset name.
* - comments. To change the comments field.
* - author. To update the author field.
* - iscore. Whether the preset is a core preset or not. Valid values on \core_adminpresets\manager class.
* @return int The identifier of the preset created.
*/
public static function create_preset(array $data): int {
global $CFG, $USER, $DB;
$name = array_key_exists('name', $data) ? $data['name'] : '';
$comments = array_key_exists('comments', $data) ? $data['comments'] : '';
$author = array_key_exists('author', $data) ? $data['author'] : fullname($USER);
$iscore = array_key_exists('iscore', $data) ? $data['iscore'] : manager::NONCORE_PRESET;
// Validate iscore value.
$allowed = [manager::NONCORE_PRESET, manager::STARTER_PRESET, manager::FULL_PRESET];
if (!in_array($iscore, $allowed)) {
$iscore = manager::NONCORE_PRESET;
}
$preset = [
'userid' => $USER->id,
'name' => $name,
'comments' => $comments,
'site' => $CFG->wwwroot,
'author' => $author,
'moodleversion' => $CFG->version,
'moodlerelease' => $CFG->release,
'iscore' => $iscore,
'timecreated' => time(),
'timeimported' => 0,
];
$presetid = $DB->insert_record('adminpresets', $preset);
return $presetid;
}
/**
* Helper method to add a setting item to a preset.
*
* @param int $presetid Preset identifier where the item will belong.
* @param string $name Item name.
* @param string $value Item value.
* @param string|null $plugin Item plugin.
* @param string|null $advname If the item is an advanced setting, the name of the advanced setting should be specified here.
* @param string|null $advvalue If the item is an advanced setting, the value of the advanced setting should be specified here.
* @return int The item identificator.
*/
public static function add_item(int $presetid, string $name, string $value, ?string $plugin = 'none',
?string $advname = null, ?string $advvalue = null): int {
global $DB;
$presetitem = [
'adminpresetid' => $presetid,
'plugin' => $plugin,
'name' => $name,
'value' => $value,
];
$itemid = $DB->insert_record('adminpresets_it', $presetitem);
if (!empty($advname)) {
$presetadv = [
'itemid' => $itemid,
'name' => $advname,
'value' => $advvalue,
];
$DB->insert_record('adminpresets_it_a', $presetadv);
}
return $itemid;
}
/**
* Helper method to add a plugin to a preset.
*
* @param int $presetid Preset identifier where the item will belong.
* @param string $plugin Plugin type.
* @param string $name Plugin name.
* @param int $enabled Whether the plugin will be enabled or not.
* @return int The plugin identificator.
*/
public static function add_plugin(int $presetid, string $plugin, string $name, int $enabled): int {
global $DB;
$pluginentry = [
'adminpresetid' => $presetid,
'plugin' => $plugin,
'name' => $name,
'enabled' => $enabled,
];
$pluginid = $DB->insert_record('adminpresets_plug', $pluginentry);
return $pluginid;
}
/**
* Apply the given preset. If it's a filename, the preset will be imported and then applied.
*
* @param string $presetnameorfile The preset name to be applied or a valid preset file to be imported and applied.
* @return int|null The preset identifier that has been applied or null if the given value was not valid.
*/
public static function change_default_preset(string $presetnameorfile): ?int {
global $DB;
$presetid = null;
// Check if the given variable points to a valid preset file to be imported and applied.
if (is_readable($presetnameorfile)) {
$xmlcontent = file_get_contents($presetnameorfile);
$manager = new manager();
list($xmlnotused, $preset) = $manager->import_preset($xmlcontent);
if (!is_null($preset)) {
list($applied) = $manager->apply_preset($preset->id);
if (!empty($applied)) {
$presetid = $preset->id;
}
}
} else {
// Check if the given preset exists; if that's the case, it will be applied.
$stringmanager = get_string_manager();
if ($stringmanager->string_exists($presetnameorfile . 'preset', 'core_adminpresets')) {
$params = ['name' => get_string($presetnameorfile . 'preset', 'core_adminpresets')];
} else {
$params = ['name' => $presetnameorfile];
}
if ($preset = $DB->get_record('adminpresets', $params)) {
$manager = new manager();
list($applied) = $manager->apply_preset($preset->id);
if (!empty($applied)) {
$presetid = $preset->id;
}
}
}
return $presetid;
}
/**
* Helper method to create default site admin presets and initialize them.
*/
public static function create_default_presets(): void {
// Create the "Starter" site admin preset.
$data = [
'name' => get_string('starterpreset', 'core_adminpresets'),
'comments' => get_string('starterpresetdescription', 'core_adminpresets'),
'iscore' => manager::STARTER_PRESET,
];
$presetid = static::create_preset($data);
// Add settings to the "Starter" site admin preset.
static::add_item($presetid, 'usecomments', '0');
static::add_item($presetid, 'usetags', '0');
static::add_item($presetid, 'enablenotes', '0');
static::add_item($presetid, 'enableblogs', '0');
static::add_item($presetid, 'enablebadges', '0');
static::add_item($presetid, 'enableanalytics', '0');
static::add_item($presetid, 'enabled', '0', 'core_competency');
static::add_item($presetid, 'pushcourseratingstouserplans', '0', 'core_competency');
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, 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);
static::add_plugin($presetid, 'mod', 'data', false);
static::add_plugin($presetid, 'mod', 'lti', false);
static::add_plugin($presetid, 'mod', 'imscp', false);
static::add_plugin($presetid, 'mod', 'lesson', false);
static::add_plugin($presetid, 'mod', 'scorm', false);
static::add_plugin($presetid, 'mod', 'survey', false);
static::add_plugin($presetid, 'mod', 'wiki', false);
static::add_plugin($presetid, 'mod', 'workshop', false);
// Availability restrictions: Hide Grouping, User profile.
static::add_plugin($presetid, 'availability', 'grouping', false);
static::add_plugin($presetid, 'availability', 'profile', false);
// Blocks: Hide Activities, Blog menu, Blog tags, Comments, Course completion status, Courses, Flickr,
// Global search, Latest badges, Learning plans, Logged in user, Login, Main menu, Mentees, Network servers, Online users,
// Private files, Recent blog entries, Recently accessed courses, Search forums, Section links, Social activities,
// Starred courses, Tags, YouTube.
// Hidden by default: Course/site summary, RSS feeds, Self completion, Feedback.
static::add_plugin($presetid, 'block', 'activity_modules', false);
static::add_plugin($presetid, 'block', 'blog_menu', false);
static::add_plugin($presetid, 'block', 'blog_tags', false);
static::add_plugin($presetid, 'block', 'comments', false);
static::add_plugin($presetid, 'block', 'completionstatus', false);
static::add_plugin($presetid, 'block', 'course_summary', false);
static::add_plugin($presetid, 'block', 'course_list', false);
static::add_plugin($presetid, 'block', 'tag_flickr', false);
static::add_plugin($presetid, 'block', 'globalsearch', false);
static::add_plugin($presetid, 'block', 'badges', false);
static::add_plugin($presetid, 'block', 'lp', false);
static::add_plugin($presetid, 'block', 'myprofile', false);
static::add_plugin($presetid, 'block', 'login', false);
static::add_plugin($presetid, 'block', 'site_main_menu', false);
static::add_plugin($presetid, 'block', 'mentees', false);
static::add_plugin($presetid, 'block', 'mnet_hosts', false);
static::add_plugin($presetid, 'block', 'private_files', false);
static::add_plugin($presetid, 'block', 'blog_recent', false);
static::add_plugin($presetid, 'block', 'rss_client', false);
static::add_plugin($presetid, 'block', 'search_forums', false);
static::add_plugin($presetid, 'block', 'section_links', false);
static::add_plugin($presetid, 'block', 'selfcompletion', false);
static::add_plugin($presetid, 'block', 'social_activities', false);
static::add_plugin($presetid, 'block', 'tags', false);
static::add_plugin($presetid, 'block', 'tag_youtube', false);
static::add_plugin($presetid, 'block', 'feedback', false);
static::add_plugin($presetid, 'block', 'online_users', false);
static::add_plugin($presetid, 'block', 'recentlyaccessedcourses', false);
static::add_plugin($presetid, 'block', 'starredcourses', false);
// Course formats: Disable Social format.
static::add_plugin($presetid, 'format', 'social', false);
// Data formats: Disable Javascript Object Notation (.json).
static::add_plugin($presetid, 'dataformat', 'json', false);
// Enrolments: Disable Cohort sync, Guest access.
static::add_plugin($presetid, 'enrol', 'cohort', false);
static::add_plugin($presetid, 'enrol', 'guest', false);
// Filter: Disable MathJax, Activity names auto-linking.
static::add_plugin($presetid, 'filter', 'mathjaxloader', TEXTFILTER_DISABLED);
static::add_plugin($presetid, 'filter', 'activitynames', TEXTFILTER_DISABLED);
// Question behaviours: Disable Adaptive mode (no penalties), Deferred feedback with CBM, Immediate feedback with CBM.
static::add_plugin($presetid, 'qbehaviour', 'adaptivenopenalty', false);
static::add_plugin($presetid, 'qbehaviour', 'deferredcbm', false);
static::add_plugin($presetid, 'qbehaviour', 'immediatecbm', false);
// Question types: Disable Calculated, Calculated multichoice, Calculated simple, Drag and drop markers,
// Drag and drop onto image, Embedded answers (Cloze), Numerical, Random short-answer matching.
static::add_plugin($presetid, 'qtype', 'calculated', false);
static::add_plugin($presetid, 'qtype', 'calculatedmulti', false);
static::add_plugin($presetid, 'qtype', 'calculatedsimple', false);
static::add_plugin($presetid, 'qtype', 'ddmarker', false);
static::add_plugin($presetid, 'qtype', 'ddimageortext', false);
static::add_plugin($presetid, 'qtype', 'multianswer', false);
static::add_plugin($presetid, 'qtype', 'numerical', false);
static::add_plugin($presetid, 'qtype', 'randomsamatch', false);
// Repositories: Disable Server files, URL downloader, Wikimedia.
static::add_plugin($presetid, 'repository', 'local', false);
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'),
'comments' => get_string('fullpresetdescription', 'core_adminpresets'),
'iscore' => manager::FULL_PRESET,
];
$presetid = static::create_preset($data);
// Add settings to the "Full" site admin preset.
static::add_item($presetid, 'usecomments', '1');
static::add_item($presetid, 'usetags', '1');
static::add_item($presetid, 'enablenotes', '1');
static::add_item($presetid, 'enableblogs', '1');
static::add_item($presetid, 'enablebadges', '1');
static::add_item($presetid, 'enableanalytics', '1');
static::add_item($presetid, 'enabled', '1', 'core_competency');
static::add_item($presetid, 'pushcourseratingstouserplans', '1', 'core_competency');
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, All, Activities, Resources, Recommended").
static::add_item($presetid, 'activitychoosertabmode', '0');
// 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);
// Availability restrictions: Enable Grouping, User profile.
static::add_plugin($presetid, 'availability', 'grouping', true);
static::add_plugin($presetid, 'availability', 'profile', true);
// Blocks: Enable Activities, Blog menu, Blog tags, Comments, Course completion status, Courses, Flickr,
// Global search, Latest badges, Learning plans, Logged in user, Login, Main menu, Mentees, Network servers, Online users,
// Private files, Recent blog entries, Recently accessed courses, Search forums, Section links, Social activities,
// Starred courses, Tags, YouTube.
// Hidden by default: Course/site summary, RSS feeds, Self completion, Feedback.
static::add_plugin($presetid, 'block', 'activity_modules', true);
static::add_plugin($presetid, 'block', 'blog_menu', true);
static::add_plugin($presetid, 'block', 'blog_tags', true);
static::add_plugin($presetid, 'block', 'comments', true);
static::add_plugin($presetid, 'block', 'completionstatus', true);
static::add_plugin($presetid, 'block', 'course_list', true);
static::add_plugin($presetid, 'block', 'tag_flickr', true);
static::add_plugin($presetid, 'block', 'globalsearch', true);
static::add_plugin($presetid, 'block', 'badges', true);
static::add_plugin($presetid, 'block', 'lp', true);
static::add_plugin($presetid, 'block', 'myprofile', true);
static::add_plugin($presetid, 'block', 'login', true);
static::add_plugin($presetid, 'block', 'site_main_menu', true);
static::add_plugin($presetid, 'block', 'mentees', true);
static::add_plugin($presetid, 'block', 'mnet_hosts', true);
static::add_plugin($presetid, 'block', 'private_files', true);
static::add_plugin($presetid, 'block', 'blog_recent', true);
static::add_plugin($presetid, 'block', 'search_forums', true);
static::add_plugin($presetid, 'block', 'section_links', true);
static::add_plugin($presetid, 'block', 'social_activities', true);
static::add_plugin($presetid, 'block', 'tags', true);
static::add_plugin($presetid, 'block', 'online_users', true);
static::add_plugin($presetid, 'block', 'recentlyaccessedcourses', true);
static::add_plugin($presetid, 'block', 'starredcourses', true);
// Course formats: Enable Social format.
static::add_plugin($presetid, 'format', 'social', true);
// Data formats: Enable Javascript Object Notation (.json).
static::add_plugin($presetid, 'dataformat', 'json', true);
// Enrolments: Enable Cohort sync, Guest access.
static::add_plugin($presetid, 'enrol', 'cohort', true);
static::add_plugin($presetid, 'enrol', 'guest', true);
// Filter: Enable MathJax, Activity names auto-linking.
static::add_plugin($presetid, 'filter', 'mathjaxloader', TEXTFILTER_ON);
static::add_plugin($presetid, 'filter', 'activitynames', TEXTFILTER_ON);
// Question behaviours: Enable Adaptive mode (no penalties), Deferred feedback with CBM, Immediate feedback with CBM.
static::add_plugin($presetid, 'qbehaviour', 'adaptivenopenalty', true);
static::add_plugin($presetid, 'qbehaviour', 'deferredcbm', true);
static::add_plugin($presetid, 'qbehaviour', 'immediatecbm', true);
// Question types: Enable Calculated, Calculated multichoice, Calculated simple, Drag and drop markers,
// Drag and drop onto image, Embedded answers (Cloze), Numerical, Random short-answer matching.
static::add_plugin($presetid, 'qtype', 'calculated', true);
static::add_plugin($presetid, 'qtype', 'calculatedmulti', true);
static::add_plugin($presetid, 'qtype', 'calculatedsimple', true);
static::add_plugin($presetid, 'qtype', 'ddmarker', true);
static::add_plugin($presetid, 'qtype', 'ddimageortext', true);
static::add_plugin($presetid, 'qtype', 'multianswer', true);
static::add_plugin($presetid, 'qtype', 'numerical', true);
static::add_plugin($presetid, 'qtype', 'randomsamatch', true);
// Repositories: Enable Server files, URL downloader, Wikimedia.
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);
}
}
@@ -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/>.
namespace core_adminpresets\local\setting;
/**
* Select setting for blog's bloglevel setting.
*
* @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
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class adminpresets_admin_setting_bloglevel extends adminpresets_admin_setting_configselect {
/**
* Extended to change the block visibility.
*
* @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 value has not been saved.
*/
public function save_value($name = false, $value = null) {
global $DB;
if (!$id = parent::save_value($name, $value)) {
return false;
}
// Object values if no arguments.
if ($value === null) {
$value = $this->value;
}
// Pasted from admin_setting_bloglevel (can't use write_config).
if ($value == 0) {
$DB->set_field('block', 'visible', 0, ['name' => 'blog_menu']);
} else {
$DB->set_field('block', 'visible', 1, ['name' => 'blog_menu']);
}
return $id;
}
}
@@ -1,47 +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_adminpresets\local\setting;
use admin_setting_configcheckbox;
/**
* Checkbox setting.
*
* @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
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class adminpresets_admin_setting_configcheckbox extends adminpresets_setting {
/**
* Sets the visible name for the setting selected value
*/
protected function set_visiblevalue() {
/** @var admin_setting_configcheckbox $settingdata */
$settingdata = $this->get_settingdata();
// We need to compare the "yes" value of the inner checkbox, which isn't necessarily boolean.
if ($this->value == $settingdata->yes) {
$str = get_string('yes');
} else {
$str = get_string('no');
}
$this->visiblevalue = $str;
}
}
@@ -1,48 +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_adminpresets\local\setting;
use admin_setting;
/**
* Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting.
*
* @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
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class adminpresets_admin_setting_configcheckbox_with_advanced extends adminpresets_admin_setting_configcheckbox {
public function __construct(admin_setting $settingdata, $dbsettingvalue) {
// To look for other values.
$this->attributes = ['adv' => $settingdata->name . '_adv'];
parent::__construct($settingdata, $dbsettingvalue);
}
/**
* Uses delegation
*/
protected function set_visiblevalue() {
parent::set_visiblevalue();
if (!is_null($this->attributesvalues) && array_key_exists($this->attributes['adv'], $this->attributesvalues)) {
$value = $this->attributesvalues[$this->attributes['adv']];
$this->visiblevalue .= $this->delegation->extra_set_visiblevalue($value, 'advanced');
}
}
}

Some files were not shown because too many files have changed in this diff Show More