Compare commits

..

914 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 25c9c6336b Moodle release 3.7.3 2019-11-09 11:57:47 +01:00
Sara Arjona a88baa553a weekly release 3.7.2+ 2019-11-08 15:39:46 +01:00
Sara Arjona 2b0e7a4ea9 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-11-08 15:39:43 +01:00
Adrian Greeve 46cb3afcfe Merge branch 'MDL-67169_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-11-08 10:44:19 +08:00
Jake Dallimore b7bb837d2b Merge branch 'MDL-67016-37-user-profile-see-own-courses' of https://github.com/danowar2k/moodle into MOODLE_37_STABLE 2019-11-08 10:22:26 +08:00
Andrew Nicols bf1e1b917f Merge branch 'MDL-67149-m37' of https://github.com/sammarshallou/moodle into MOODLE_37_STABLE 2019-11-08 10:10:36 +08:00
Sara Arjona 35c54f8ea8 Merge branch 'MDL-66683-37' of git://github.com/cescobedo/moodle into MOODLE_37_STABLE 2019-11-07 17:41:30 +01:00
cescobedo ffc5dc3245 MDL-66683 core: Revert MDL-66181 because created regressions
This reverts commit ed080a580f.
This issue reverts the behaviour modified in MDL-66181, as that change
negatively impacted course-creation workflows. As this appears to be
the intended functionality, the Security team has agreed to revert
this change.
2019-11-07 17:30:19 +01:00
Jake Dallimore 64f1c9d901 MDL-66257 tool_cohortroles: unit test for users in multiple cohorts 2019-11-07 23:47:33 +08:00
cescobedo b7ee5cb2ea MDL-66257 tool_cohortroles: Unassign the role on removal cohortroles. 2019-11-07 23:47:33 +08:00
Eloy Lafuente (stronk7) 0581a99241 MDL-67169 phpunit: fix clear flaw in unit test provider
Basically the provider is ignoring the CRLF to LF normalization
results and loading the original file again.

This doesn't have any impact normally, because all moodle
files are LF ones and people using other systems have their
git configurations set to work that way (not modify or force LF).

But there may be checkouts out there (for example travis) where
the git configuration by defult is to convert to the OS, causing
windows runs to fail badly there. See the issue for more info
and links.
2019-11-07 13:43:46 +01:00
Jun Pataleta d084e4194c Merge branch 'MDL-67084-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-11-07 19:37:48 +08:00
Marina Glancy 56f3b3f412 MDL-67084 core_form: duration element should export arrays 2019-11-07 19:22:05 +08:00
Jun Pataleta 0ecc1a8eab MDL-66598 auth_oauth2: OAuth2 upgrade step
This basically does two things:
1. Updates all non-Facebook/Google/Microsoft issuers and sets their
'requireconfirmation' field to 1 so that future OAuth2 logins on these
issuers will always have an email confirmation sent to them.
2. Deletes the linked logins of users with non-Facebook/Google/Microsoft
OAuth2 issuers.
2019-11-07 18:43:30 +08:00
Jun Pataleta 6cb4bd65d3 MDL-66598 auth_oauth2: Add warning messages in confirm emails 2019-11-07 18:43:30 +08:00
Jun Pataleta 034729a5ce MDL-66598 tool_oauth2: Make account confirmation required by default
* Only Facebook, Google, and Microsoft issuers can optionally offer to
require account confirmation via email. We will require email
confirmation for the rest of the issuers.
2019-11-07 18:43:30 +08:00
Mihail Geshoski 4676d5ad35 MDL-66762 tool_dataprivacy: Sanitize the extra fields in the webservice 2019-11-07 09:02:35 +08:00
Paul Holden a722b44a09 MDL-66762 user: escape extra/email user fields. 2019-11-07 09:02:35 +08:00
Paul Holden 8d111d5136 MDL-66762 user: stricter email validation. 2019-11-07 09:02:34 +08:00
Eloy Lafuente (stronk7) a423038589 Merge branch 'MDL-42638-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-11-06 22:47:29 +01:00
sam marshall cff7de72ed MDL-67149 Accessibility: Help popups fail WCAG 1.4.13 (Dismissable)
It must be possible to dismiss the help popups (popovers) with the
Escape key, without changing focus.
2019-11-06 16:27:17 +00:00
Sara Arjona 18b60b3d2b Merge branch 'MDL-66984-change_password_url-with-user-MOODLE_37_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_37_STABLE 2019-11-06 08:30:55 +01:00
AMOS bot fb9553cac0 Automatically generated installer lang files 2019-11-06 00:16:32 +00:00
Luca Bösch 2b746fc34a MDL-42638 filters: Have emoticons respect <pre>. 2019-11-05 16:09:20 +01:00
Michael Hawkins 87c1819e2f MDL-66161 output: Escaping fatal error message and URL strings 2019-11-05 13:47:43 +01:00
Juan Leyva 2e4684f51c MDL-66377 user: Only allow active users to retrieve files via tokenpluginfile.php 2019-11-05 13:47:43 +01:00
Paul Holden f68e327afa MDL-66228 mod_lesson: ensure return URL parameters are always local. 2019-11-05 13:47:43 +01:00
Eloy Lafuente (stronk7) 7471e92601 weekly release 3.7.2+ 2019-11-05 13:34:30 +01:00
Eloy Lafuente (stronk7) 5dbf43b0de Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-11-05 13:34:27 +01:00
Jake Dallimore 98c155a433 Merge branch 'MDL-66455-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-11-05 11:43:06 +08:00
AMOS bot 7c2d448bf8 Automatically generated installer lang files 2019-11-05 00:10:27 +00:00
Brendan Heywood fb5ed6a5ca MDL-66984 auth: Allow $USER to be used in change_password_url 2019-11-05 10:24:48 +11:00
Jun Pataleta beed18a8e9 Merge branch 'MDL-66582-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-11-04 19:35:33 +08:00
Jake Dallimore 79d23bb46b Merge branch 'MDL-67093-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-11-04 15:40:30 +08:00
Adrian Greeve 145c57f2f9 Merge branch 'MDL-43189-37' of git://github.com/snake/moodle into MOODLE_37_STABLE 2019-11-04 09:24:13 +08:00
Eloy Lafuente (stronk7) 385e7e0c26 Merge branch 'MDL-66990-37-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-11-03 23:15:18 +01:00
AMOS bot e848d21f9e Automatically generated installer lang files 2019-11-02 00:09:30 +00:00
Helen Foster e8014f4833 MDL-66990 lang: Import fixed English strings (en_fix)
Significant string changes:

* hidegrader_help,mod_assign - note about setting having no effect on
  comments box
* configenablecompletion,core_completion - including reason for setting
  activity completion conditions
* setuplink_desc,tool_mobile - including where the app download page
  link is displayed and leaving the setting empty
2019-11-01 11:22:19 +01:00
Shamim Rezaie 66b2dcd7be MDL-43189 core: improve validating db settings during cli install 2019-11-01 15:41:36 +08:00
Shamim Rezaie f41a30229e MDL-43189 core: Validate db prefix during installation 2019-11-01 15:41:36 +08:00
Daniel Poggenpohl d8a7f2aeb7 MDL-67016 profile: current user should see his own courses 2019-10-31 14:36:43 +01:00
Juan Leyva e7cdd0e77c MDL-66582 tool_mobile: Clean URLs from auth plugins
In order to avoid the WebService to break we must double check that URLs coming from auth plugins are valid.
2019-10-31 14:22:51 +01:00
Johan Dobbelstein cf889e4fbd MDL-66582 auth: Fix empty auth_logo in CAS/Shibboleth auth plugins
* set $idp['iconurl'] = null if no auth_logo
* lib/templates/loginform.mustache will skip NULL iconurls
* lib/ajax/service?info=tool_mobile_get_public_config will validate the NULL values
2019-10-31 14:22:51 +01:00
Eloy Lafuente (stronk7) bb519b05b1 weekly release 3.7.2+ 2019-10-31 13:33:21 +01:00
Simey Lameze ad796334cb MDL-66455 calendar: add coverage for event types in subscription page 2019-10-31 18:48:05 +08:00
Simey Lameze 0e903c3f7f MDL-66455 calendar: show site level subscriptions 2019-10-31 18:48:04 +08:00
Adrian Greeve 63c0acc5e9 Merge branch 'MDL-66247-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-10-31 14:38:29 +08:00
Andrew Nicols 307600962c MDL-67093 grading: Fetch cm with get_fast_modinfo 2019-10-31 13:28:56 +08:00
Andrew Nicols d0cf886bf8 Merge branch 'MDL-67088-37' of git://github.com/marinaglancy/moodle into MOODLE_37_STABLE 2019-10-31 11:08:20 +08:00
Marina Glancy 0c8ad6a113 MDL-67088 mod_assign: compare time without case for MacOS compat 2019-10-30 19:20:02 +01:00
Andrew Nicols bff4d30a79 MDL-66247 accessibility: Correct notification alert role support 2019-10-30 09:01:18 +08:00
Eloy Lafuente (stronk7) 3d9b0a9b1b weekly release 3.7.2+ 2019-10-29 21:01:50 +01:00
Eloy Lafuente (stronk7) 5570436ef3 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-10-29 21:01:44 +01:00
Jake Dallimore 96d6f625f3 Merge branch 'MDL-66945_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-10-29 14:56:13 +08:00
Andrew Nicols 9c8a6c45f9 Merge branch 'MDL-67027-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-10-29 09:35:42 +08:00
Andrew Nicols be328441a2 MDL-66945 composer: Update behat extension
(using php71 for this branch)

This uses a new version of the moodlehq-behat-extension which ensures
that a node is visible and in the view port before it is clicked on.

This resolves an issue with Firefox on Ubuntu 18.04 whereby the node is
only brought into the viewport instead of clicked on.
2019-10-28 13:18:30 +01:00
Jun Pataleta e282b1f1fc Merge branch 'm37_MDL-65811_Fix_Incorrect_ORDER_BY_Search' of https://github.com/scara/moodle into MOODLE_37_STABLE 2019-10-28 11:30:40 +08:00
AMOS bot 28ccb81e87 Automatically generated installer lang files 2019-10-28 00:09:18 +00:00
AMOS bot bf84c3f075 Automatically generated installer lang files 2019-10-27 00:09:15 +00:00
Matteo Scaramuccia 429de834fa MDL-65811 database: Fix subsetting in MSSQL 2019-10-25 23:04:02 +02:00
Paul Holden 77c0308e74 MDL-67027 calendar: fix event update form validation. 2019-10-25 17:36:41 +01:00
Eloy Lafuente (stronk7) 991ac49b61 weekly release 3.7.2+ 2019-10-25 15:29:45 +02:00
Eloy Lafuente (stronk7) 56a0e6ed87 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-10-25 15:29:42 +02:00
Jake Dallimore 710bfa00e7 Merge branch 'MOODLE_37_MDL-66973' of https://github.com/golenkovm/moodle into MOODLE_37_STABLE 2019-10-25 11:10:18 +08:00
Jun Pataleta 5d70a8d5ad Merge branch 'MDL-66543-37' of git://github.com/tobiasreischmann/moodle into MOODLE_37_STABLE 2019-10-24 23:08:36 +08:00
Tobias Reischmann 39a390f1f5 MDL-66543 forms: Make (hard) frozen textareas readonly (or disabled) 2019-10-24 13:44:22 +02:00
Eloy Lafuente (stronk7) 978ed33fb1 Merge branch 'MDL-66935-lock-clashes-MOODLE_37_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_37_STABLE 2019-10-24 10:03:46 +02:00
Adrian Greeve 666d420194 Merge branch 'MDL-66876-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-10-24 15:16:21 +08:00
Jun Pataleta bdf64b7eec Merge branch 'MDL-66927-run-new-adhoc-37' of https://github.com/brendanheywood/moodle into MOODLE_37_STABLE 2019-10-24 13:46:12 +08:00
Brendan Heywood 413b321344 MDL-66935 core_lock: Fix resource key clashes in db and postgres locks 2019-10-24 15:09:16 +11:00
AMOS bot 4497ed3938 Automatically generated installer lang files 2019-10-24 00:09:26 +00:00
Eloy Lafuente (stronk7) fc992c94af Merge branch 'MDL-64298-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-10-23 22:21:49 +02:00
Eloy Lafuente (stronk7) 7b04b19e06 Merge branch 'MDL-67001-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-10-23 22:17:34 +02:00
Sara Arjona 7dfa4d625b Merge branch 'MOODLE_37_STABLE_MDL-66225_async_backup_state' of https://github.com/mattporritt/moodle into MOODLE_37_STABLE 2019-10-23 17:39:22 +02:00
Juan Leyva 648ec6857b MDL-64298 gradereport_user: Fix WS returned parameter description
feedbackformat must be optional always
2019-10-23 17:16:24 +02:00
Juan Leyva f6f931728a MDL-66876 core_filter: Fix context in Web Service warning 2019-10-23 17:07:41 +02:00
Luca Bösch de254adfd3 MDL-67001 question: alignment and form spaces. 2019-10-23 11:00:11 +02:00
Matt Porritt bf0a0ed189 MDL-66225 Backup: fix irrecoverable state
Fix condition where if an asynchronous backup
completes via the UI and the user refreshes the
page a new backup was created with a mismatched
backup id.
This caused a permanently failing ad-hoc task
and blocked further backups for that course.
2019-10-23 04:18:42 +00:00
Adrian Greeve 76ebea9add Merge branch 'MDL-63125-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-10-23 11:07:10 +08:00
Sara Arjona 4fef7d1c87 weekly release 3.7.2+ 2019-10-22 14:48:08 +02:00
Sara Arjona 582a3baf70 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-10-22 14:48:05 +02:00
Paul Holden 9961411a12 MDL-63125 forms: Behat test for form autocomplete element. 2019-10-21 23:25:28 +01:00
Eloy Lafuente (stronk7) ace0fcf5b4 Merge branch 'MDL-66980_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-21 20:26:49 +02:00
Sara Arjona d3750e40ae Merge branch 'MDL-61121-37-5' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-10-21 14:46:29 +02:00
Tim Hunt 8e506aa53c MDL-66980 question bank: fix load_many_for_cache missing record check 2019-10-21 11:18:46 +01:00
Jun Pataleta 687e3b53c0 Merge branch 'MDL-66009-37' of https://github.com/grabs/moodle into MOODLE_37_STABLE 2019-10-21 16:15:13 +08:00
Jake Dallimore 285bc3e242 Merge branch 'MDL-66915-37' of https://github.com/MartinGauk/moodle into MOODLE_37_STABLE 2019-10-21 15:56:06 +08:00
Mikhail Golenkov 8dc826354d MDL-66973 search: Reset Content writer after test. 2019-10-21 17:48:45 +11:00
Andrew Nicols d5409002be Merge branch 'MDL-66962-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-10-21 14:23:27 +08:00
Luca Bösch 3e1e159efa MDL-66962 questions: Question bank table T title non breaking. 2019-10-21 08:17:15 +02:00
Andrew Nicols a4ed555b2f Merge branch 'MDL-66944_37' of https://github.com/t-schroeder/moodle into MOODLE_37_STABLE 2019-10-21 13:48:41 +08:00
Andrew Nicols 07b3e80ed1 Merge branch 'MDL-66946_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-21 12:56:54 +08:00
Jake Dallimore 023ebdb1af Merge branch 'MDL-66930-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-10-21 11:55:39 +08:00
Jake Dallimore b09d19d5bd Merge branch 'MDL-66960-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-10-21 10:41:44 +08:00
AMOS bot 3acc7fba61 Automatically generated installer lang files 2019-10-19 00:09:18 +00:00
Tim Schroeder 66039dbc91 MDL-66944 course: fixed copy-paste-error in comment 2019-10-18 22:47:11 +02:00
Tim Hunt 90766fb12b MDL-66946 quiz reports: incorrectly show teachers sometimes 2019-10-18 17:40:37 +01:00
Luca Bösch 3984d03fda MDL-66960 questions: Top align all question bank titles exc "select all" 2019-10-18 16:35:38 +02:00
Luca Bösch 0a9eae8b7a MDL-66930 quiz: Question type icon size/alignment in Boost and Classic. 2019-10-18 13:53:02 +02:00
Eloy Lafuente (stronk7) aac11a3c4b weekly release 3.7.2+ 2019-10-18 10:31:33 +02:00
Mihail Geshoski 84801cd656 MDL-61121 assign: Declare variables in the local scope 2019-10-18 13:59:58 +08:00
Mihail Geshoski 542e7b52f2 MDL-61121 assign: Improve accessibility in quick grading page tables 2019-10-18 13:59:58 +08:00
Mihail Geshoski cbc680eb33 MDL-61121 assign: Improve accessibility - view full/view summary control 2019-10-18 13:59:58 +08:00
Jun Pataleta 9a9542a238 Merge branch 'MDL-66806_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-10-18 09:36:43 +08:00
Andrew Nicols 5b3308939d Merge branch 'MDL-66919_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-10-18 08:27:52 +08:00
Eloy Lafuente (stronk7) da348e315a Merge branch 'MDL-64064-m37' of https://github.com/NeillM/moodle into MOODLE_37_STABLE 2019-10-17 23:09:10 +02:00
Andreas Grabs ba8bc23906 MDL-66009 mod_feedback: Nested dependency fails again 2019-10-17 09:19:49 +02:00
Brendan Heywood 9c1f81775e MDL-66927 cron: Process new adhoc tasks immediately 2019-10-16 20:29:45 +11:00
Eloy Lafuente (stronk7) c6e6c935af MDL-66919 behat: fix typo in error message
Also fix a couple of phpdocs that were incorrect.
2019-10-16 00:48:55 +02:00
Eloy Lafuente (stronk7) 474159da70 weekly release 3.7.2+ 2019-10-15 23:00:02 +02:00
Martin Gauk 9ccc9ec175 MDL-66915 assign: Notify only if grade was updated in past 24 hours
Send notifications only if a grade was updated in the past 24 hours,
whether marking workflow is enabled or not.
2019-10-15 17:03:33 +02:00
Tim Hunt 2903b1ae22 MDL-66796 question bank: fix more bugs with category editing 2019-10-15 10:55:19 +08:00
Jun Pataleta 5316b73d41 Merge branch 'MDL-66821_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-15 07:36:58 +08:00
Andrew Nicols 2669dd7963 Merge branch 'MDL-66335_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-10-15 07:31:17 +08:00
Eloy Lafuente (stronk7) 4705bff0e1 MDL-66335 behat: Avoid double processing the page type
resolve_page_instance_helper() already processes the type, returning
the correct context that should be processing the navigation URL.

With that extra call to parse_page_name() the 2nd call always returns
"core", ultimately leading to tons of behat failures because "core" is
not aware of those (plugin, quiz for now) pages typology.
2019-10-15 00:02:41 +02:00
Eloy Lafuente (stronk7) 19bd02eabd Merge branch 'MDL-66335_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-14 18:55:37 +02:00
Paul Holden 0701f2f08c MDL-63125 forms: allow item removal from single-select autocomplete. 2019-10-14 17:07:54 +01:00
Eloy Lafuente (stronk7) d18f809ec4 Merge branch 'MDL-66559-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-10-14 16:37:30 +02:00
Tim Hunt 87252eae2c MDL-66335 quiz behat: using the new generic navigation steps
This converts all the navigation to quiz pages when that is not
the thing under test. Also, I decided that the Quiz settings form
belonged to the course, so did not do that here.
2019-10-14 13:13:03 +01:00
Tim Hunt df143c2923 MDL-66335 behat: new step to log in and go straight to a particular page
I did not think thought through if this new URL parameter would be a
potential security hole. The simple cop-out option is to make it only
work on Behat sites for now.
2019-10-14 13:13:01 +01:00
Tim Hunt 621e8888e5 MDL-66335 behat: generic step for navigating direct to specific pages 2019-10-14 13:12:59 +01:00
Tim Hunt ff76a9d590 MDL-66821 question behat: new step for acting on questions in the bank
There is a proposed change MDL-66816 which will change the question
bank UI. This will break any Behat tests which uses low-level steps
like

    When I click on "Duplicate" "link" in the "Test question" "table_row"

to perform an action on a question in the question bank. This commit
introduces a new step:

    When I choose "Duplicate" action for "Test question" in the question bank

This commit also converts all core Behat tests to use the new step.
2019-10-14 11:55:56 +01:00
Sara Arjona a9a9fd455a Merge branch 'MDL-66836-m37' of https://github.com/sammarshallou/moodle into MOODLE_37_STABLE 2019-10-14 12:27:10 +02:00
Jake Dallimore 81bbf95756 Merge branch 'MDL-66659-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-10-14 15:33:38 +08:00
Andrew Nicols 30702cc0bd MDL-66559 behat: Register component selectors earlier 2019-10-14 14:24:05 +08:00
Andrew Nicols 5eb80c4af6 MDL-66559 behat: Update running suite 2019-10-14 14:17:47 +08:00
Jun Pataleta 1f19dc8237 Merge branch 'MDL-66796-37-fix' of https://github.com/snake/moodle into MOODLE_37_STABLE 2019-10-14 13:48:24 +08:00
Jake Dallimore ca42dbc0dd MDL-66796 mod_quiz: only update the id number if changed
If the idnumber is present in the DB, it's set to null. In this case,
don't update the value.
2019-10-14 13:40:05 +08:00
Jake Dallimore 04ed69e387 Merge branch 'MDL-66559-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-10-14 11:10:19 +08:00
Jake Dallimore b30c16ec86 Merge branch 'MDL-66796_37' of git://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-14 07:41:48 +08:00
Eloy Lafuente (stronk7) 532b7c9462 Merge branch 'MDL-66792-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-10-13 17:10:27 +02:00
Eloy Lafuente (stronk7) d09616d194 Merge branch 'MDL-66851-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-10-13 16:49:48 +02:00
Eloy Lafuente (stronk7) 6c06678c34 Merge branch 'MDL-65243-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-10-13 16:31:27 +02:00
Eloy Lafuente (stronk7) b089becae9 Merge branch 'MDL-65515-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-10-13 16:13:07 +02:00
Eloy Lafuente (stronk7) 703d8c2784 Merge branch 'MDL-66779-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-10-13 02:12:50 +02:00
Eloy Lafuente (stronk7) 2a7ae663c5 Merge branch 'MOODLE_37_MDL-66864' of https://github.com/golenkovm/moodle into MOODLE_37_STABLE 2019-10-13 02:08:44 +02:00
Eloy Lafuente (stronk7) b303604bf1 Merge branch 'MDL-65584-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-10-13 01:49:47 +02:00
Eloy Lafuente (stronk7) 9f0a5cf2f5 weekly release 3.7.2+ 2019-10-11 22:43:54 +02:00
Eloy Lafuente (stronk7) 75232c7d34 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-10-11 22:43:42 +02:00
Neill Magill 0e57a3dede MDL-64064 block_timeline: Confusing when event is not in this year
If an event is not in the current year it can be confusing as the
months and days may appear to be in the wrong order.

This change adds the year to the displayed date to make the reason
for the order clear.
2019-10-11 08:38:29 +01:00
Tim Hunt d9dc216897 MDL-66559 behat: Documentation for component selectors 2019-10-11 12:58:16 +08:00
Andrew Nicols 814f15a05d MDL-66559 message: Move behat selectors to message subsystem 2019-10-11 12:58:16 +08:00
Andrew Nicols 50cd119caa MDL-66559 behat: Allow per-component selectors and replacements 2019-10-11 12:58:16 +08:00
Jake Dallimore caaf2427a7 Merge branch 'MDL-66804-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-10-11 09:58:16 +08:00
AMOS bot 88c69c2dcf Automatically generated installer lang files 2019-10-11 00:11:35 +00:00
Eloy Lafuente (stronk7) 4398cdace0 Merge branch 'MDL-66815_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-11 00:50:42 +02:00
David Monllaó 519142291c MDL-66806 analytics: No predictions for hidden courses 2019-10-10 10:09:28 +08:00
AMOS bot 20b96798d7 Automatically generated installer lang files 2019-10-10 00:09:26 +00:00
sam marshall 3816bd8776 MDL-66836 Behat: Reset unknown config variables between scenarios
In the Behat CLI run (not in the individual web requests), if you
modified an existing $CFG variable then this would be reset at the
start of the next scenario. However, if you added a completely new
one, it would not be reset. This change removes those variables.
2019-10-09 17:49:24 +01:00
Jun Pataleta 760ffcd6bf Merge branch 'MDL-66835_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-09 20:44:36 +08:00
Jun Pataleta 76bd81c69c Merge branch 'MDL-66450-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-10-09 20:39:59 +08:00
Bas Brands 4a8e6db894 MDL-66450 themes: form autocomplete truncate listitems 2019-10-09 14:27:08 +02:00
Tim Hunt f5fbfb4d6b MDL-66835 behat: steps for setting/checking fields in containers 2019-10-09 13:24:56 +01:00
Sara Arjona 621f04de6a Merge branch 'MDL-66852-37' of github.com:lucaboesch/moodle into MOODLE_37_STABLE 2019-10-09 12:58:07 +02:00
Damyon Wiese 93d309cce2 MDL-65243 badges: Use real time api
Never add or subtract timestamps - use the time api to do it correctly.
2019-10-09 11:55:22 +08:00
Mihail Geshoski 53cc513636 MDL-65515 badges: Split install/upgrade
Use badges/upgradelib.php for functions that only affect install/upgrade.

All credit goes to Damyon Wiese.
2019-10-09 11:43:43 +08:00
Adrian Greeve bf4f5df33e Merge branch 'MDL-66011-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-10-09 10:51:29 +08:00
Andrew Nicols d784d3751c MDL-66779 phpunit: Correct component name for core_grades 2019-10-09 09:35:27 +08:00
Andrew Nicols 7ef7de84a2 Merge branch 'MDL-66118-37-byebyemoodlenet' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-10-09 08:51:21 +08:00
Luca Bösch 259bbd1960 MDL-66852 quiz: Style "Try another question like this one" button. 2019-10-08 11:27:22 +02:00
Eloy Lafuente (stronk7) 765579d021 weekly release 3.7.2+ 2019-10-08 10:43:35 +02:00
Eloy Lafuente (stronk7) a7e0f274f5 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-10-08 10:43:28 +02:00
Mihail Geshoski bdef5416c3 MDL-66851 block_starredcourses: Hide 'hidden' courses from students
Thanks to Mark Sharp for the bug report and fix suggestion.
2019-10-08 09:54:15 +08:00
AMOS bot ad35c1ca2f Automatically generated installer lang files 2019-10-08 00:10:05 +00:00
Paul Holden 958b331ada MDL-65584 blog: safer deletion of associations in privacy provider.
It's possible that the given context list contains no posts, which caused
an exception to be thrown when passing an empty array to get_in_or_equal.
2019-10-08 00:23:40 +01:00
Eloy Lafuente (stronk7) 470ba08790 Merge branch 'MDL-66801_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-08 01:16:36 +02:00
Eloy Lafuente (stronk7) 7ac967501b Merge branch 'MDL-66734-37' of https://github.com/snake/moodle into MOODLE_37_STABLE 2019-10-07 23:04:10 +02:00
Eloy Lafuente (stronk7) 4bb12ff74d Merge branch 'MDL-66764_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-07 22:51:11 +02:00
Eloy Lafuente (stronk7) 0ffb67352b Merge branch 'MDL-66750_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-10-07 22:00:13 +02:00
Adrian Greeve 713a5cdb97 Merge branch 'MOODLE_37-MDL-66794' of https://github.com/golenkovm/moodle into MOODLE_37_STABLE 2019-10-07 14:30:53 +08:00
Mikhail Golenkov bf61d3f2b7 MDL-66864 upgrade: Delete non-mutual contacts in chunks. 2019-10-07 16:28:16 +11:00
Marina Glancy f7ea6feec7 MDL-65187 core_hub: truncate registration request, use post 2019-10-07 11:46:31 +08:00
Marina Glancy b46eb4266d MDL-65187 core_hub: send more important info first to moodle.net
Rumor has it that some browsers may truncate the GET request to 2000 characters,
make sure that all important info is sent first
Everything else will be updated on the first registration update request.
2019-10-07 11:46:20 +08:00
David Mudrák e8bc91383d MDL-66118 hub: Remove the mentions of moodle.net
This is an update of the site registration admin page and some relevant
backend code to remove the mentions of moodle.net.

AMOS BEGIN
 CPY [registerwithmoodleorg,core_admin],[registerwithmoodleorg,core_hub]
AMOS END
2019-10-04 21:38:07 +02:00
David Mudrák 75bb4372ca MDL-66118 hub: Stop using the hub URL as the setting name suffix
Site indicators shared with the registration hub used to have the hub
URL in the relevant setting names - such as site_name_httpsmoodlenet.
This upgrade step converts all such settings and drops the URL suffix
because we do not support alternative hubs any more.

Additionally the upgrade step renames the official hub and updates its
URL so that existing registrations with https://moodle.net are still
valid.
2019-10-04 21:38:07 +02:00
David Mudrák 1d0dc3102a MDL-66118 hub: Define the new sites directory URL
The Moodle sites now register with stats.moodle.org so use that as a new
official hub's URL. Beside that, allow for the alternative value be
provided in config.php for development and testing purposes.
2019-10-04 21:34:53 +02:00
Eloy Lafuente (stronk7) 8b89ab5798 weekly release 3.7.2+ 2019-10-04 16:01:45 +02:00
Eloy Lafuente (stronk7) 67ccb85794 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-10-04 16:01:39 +02:00
Jun Pataleta 60e2e906f1 Merge branch 'MDL-65315-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-10-04 10:25:07 +08:00
Andrew Nicols aeccf1b188 MDL-66011 test: remove magic @covers lines 2019-10-04 09:40:50 +08:00
Andrew Nicols 512320cd6c MDL-66011 tests: Stop forcing coverage annoation 2019-10-04 09:40:50 +08:00
AMOS bot aefc7f7f70 Automatically generated installer lang files 2019-10-04 00:11:51 +00:00
Eloy Lafuente (stronk7) 2ab788bcf8 Merge branch 'MDL-56649-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-10-03 19:37:24 +02:00
Jun Pataleta 2ecdf811f3 Merge branch 'MDL-61450-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-10-03 15:42:08 +08:00
Jun Pataleta 8a6d5c8c88 MDL-61450 calendar: Unit test for calendar_view_event_allowed()
* Unit test for calendar_view_event_allowed() when dealing with course
events.
2019-10-03 15:39:17 +08:00
Simey Lameze 765ef31f00 MDL-61450 calendar: fix course event type permissions 2019-10-03 15:39:17 +08:00
Eloy Lafuente (stronk7) e011fc3dfb Merge branch 'MDL-66774-37-macedonia' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-10-03 00:58:25 +02:00
Eloy Lafuente (stronk7) b08e192757 Merge branch 'MDL-66197-37' of git://github.com/marinaglancy/moodle into MOODLE_37_STABLE 2019-10-03 00:45:42 +02:00
Eloy Lafuente (stronk7) a4ec901a4d Merge branch 'MDL-65957-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-10-02 16:49:39 +02:00
Mihail Geshoski a99105cc33 MDL-65957 repository_upload: Throw exception if @_file_upload is missing 2019-10-02 09:27:32 +08:00
Eloy Lafuente (stronk7) 8278f79219 Merge branch 'MDL-65335_37_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_37_STABLE 2019-10-01 23:22:32 +02:00
Tim Hunt 5fa3dccf4b MDL-66815 behat: question category generator must find right parent id
This is implemented in a bit of a hacky way, because the only other
alternative would be a large rewrite of the whole class, which is
not feasible for me right now. Note that many other types of thing
that can be generated suffer from the same issue. (E.g. if you ever
wanted to generate two groups with the same name in two different
courses and then add group memebers.)

It is worth doing a special-case fix for question categories, because
way Moodle works, it is inevitable that we end up with many categories
called 'top' in the database.
2019-10-01 16:48:15 +01:00
Eloy Lafuente (stronk7) b306a159de Merge branch 'MDL-65522-m37' of https://github.com/NeillM/moodle into MOODLE_37_STABLE 2019-10-01 16:10:34 +02:00
Eloy Lafuente (stronk7) 14d1be23c1 Merge branch 'MDL-66542_37' of https://github.com/t-schroeder/moodle into MOODLE_37_STABLE 2019-10-01 15:58:20 +02:00
Paul Holden 3f4935dfda MDL-66659 core: observe viewfullnames capability in flexible_table. 2019-10-01 10:15:15 +01:00
Jake Dallimore 3958f4a302 MDL-66734 core_comment: fix get_comment ordering when timestamps match
Include id in the sorting, to be sure that we always get the correct
record in cases where the comment timestamps are the same.
2019-10-01 09:18:56 +08:00
Paul Holden 3c7f5e8472 MDL-66792 tool_dataprivacy: correct fa classes in privacy registry. 2019-09-30 23:54:52 +01:00
Paul Holden 7db4bf3b34 MDL-66804 user: consistent user access times in privacy export. 2019-09-30 23:14:55 +01:00
Eloy Lafuente (stronk7) baa5130e0a Merge branch 'MDL-65876-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-10-01 00:07:41 +02:00
Tim Hunt 01d1ae9a5b MDL-66801 questions: XML import/export should include category idnumbers 2019-09-30 19:00:20 +01:00
Tim Hunt 1fa5fe2104 MDL-66796 question bank: 0 is a valid question category idnumber 2019-09-30 14:19:37 +01:00
Tim Schroeder c91312545d MDL-66542 lib: Fix quote escaping in JS quote helper 2019-09-30 10:17:59 +02:00
Neill Magill 68e8070295 MDL-65522 block_social_activities: Improve behat steps documentation
The documentation for these steps was not helpful in the Acceptance
testing admin tool page.
2019-09-30 08:58:51 +01:00
Mikhail Golenkov c2ba01fe9e MDL-66794 core_customfield: Reset Course handler after unit tests run. 2019-09-30 11:12:33 +10:00
Luca Bösch 6714c137c8 MDL-65876 forum: same arrows forum/activity navigation 2019-09-27 14:20:09 +02:00
Jun Pataleta 31f8f75672 weekly release 3.7.2+ 2019-09-27 11:12:23 +08:00
Jun Pataleta 8d268a8d04 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-09-27 11:12:22 +08:00
David Mudrák ac210ad583 MDL-66774 lang: Update the list of countries as per ISO 3166-1
Source: https://www.iso.org/obp/ui/

Two significant changes are:

* North Macedonia
* Eswatini

All other changes are formal, such as changing the letter case of the
"And" (the current ISO uses the lower case "and").  Our own existing
modifications of the list (such as having just "United States" and
"United Kingdom" instead of the full long name) were kept.
2019-09-26 10:44:56 +02:00
Jun Pataleta 29d555ab48 Merge branch 'MDL-66262_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-09-26 11:34:39 +08:00
Eloy Lafuente (stronk7) 86fa1ca83d Merge branch 'MDL-66106-37' of https://github.com/snake/moodle into MOODLE_37_STABLE 2019-09-26 00:54:25 +02:00
Jake Dallimore 8a5783c2be MDL-66169 admin: properly set debugsmtp, which is a config.php only var
This may not be set, so care must be taken to conditionally reinstate
the value, once the test email has been sent.
2019-09-26 00:48:30 +02:00
Eloy Lafuente (stronk7) fc71bf1e4a Merge branch 'MDL-51327-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-09-26 00:04:53 +02:00
Eloy Lafuente (stronk7) 0845113531 Merge branch 'MDL-66685_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-09-25 23:57:55 +02:00
Eloy Lafuente (stronk7) c131927ae5 Merge branch 'MDL-66675-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-25 20:06:11 +02:00
Marina Glancy f1b71b0199 MDL-66197 core: correct get parent language 2019-09-25 17:41:53 +02:00
Bas Brands 952b0caf57 MDL-56649 themes: filepicker file exists buttons spacing 2019-09-25 12:20:39 +02:00
Tim Hunt 2366f12757 MDL-66764 quiz: redo question should not repeat random questions
Before this fix, it was only considering questions seen in previous attempts.

It should avoid the questions in the current attmept too.
2019-09-25 11:05:13 +01:00
Jun Pataleta 3135b6f694 Merge branch 'MDL-66354-37' of http://github.com/dravek/moodle into MOODLE_37_STABLE 2019-09-25 16:42:59 +08:00
David Matamoros 4be324b42a MDL-66354 core_calendar: Notices in error.log on calendar events 2019-09-25 09:11:32 +02:00
Jun Pataleta 2d887636e6 Merge branch 'MDL-66644-37-versionrequires' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-09-25 14:53:44 +08:00
Adrian Greeve 4e0b890955 Merge branch 'wip_MDL-66656_m37' of git://github.com/gjb2048/moodle into MOODLE_37_STABLE 2019-09-25 11:41:18 +08:00
Eloy Lafuente (stronk7) ee1fac1fd8 Merge branch 'MDL-65621-dimmed-courses-MOODLE_3.7' of https://github.com/stopfstedt/moodle into MOODLE_37_STABLE 2019-09-24 19:08:37 +02:00
David Monllaó 0a397e3fd2 MDL-66394 analytics: Extra GC during analysis
(backport of MDL-66234)
2019-09-24 14:08:24 +02:00
Mihail Geshoski f4397e3098 MDL-51327 core_course: Allow subdirs in edit section form 2019-09-24 09:08:54 +08:00
AMOS bot cc2932aefa Automatically generated installer lang files 2019-09-24 00:09:34 +00:00
Peter ce20bd7a73 MDL-65315 badges: Update the class and issuer OBv2.0 url 2019-09-24 07:59:18 +08:00
Tim Hunt f5f5bfbdf7 MDL-66750 formslib selects: handle size attribute properly 2019-09-23 12:15:08 +01:00
AMOS bot e3e8ee312b Automatically generated installer lang files 2019-09-22 00:09:19 +00:00
Gareth Barnard 5f2dd1bd50 MDL-66656 format_social: Edit Summary Icon leads to 'File not found'. 2019-09-20 21:46:43 +01:00
Sara Arjona 26c79027ff Merge branch 'MDL-46978-MOODLE_37_STABLE' of github.com:tuanngocnguyen/moodle into MOODLE_37_STABLE 2019-09-20 13:07:39 +02:00
Sara Arjona cfbcdc97e5 Merge branch 'MDL-66090_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-09-20 12:46:24 +02:00
Mark Johnson 6bdfddc463 MDL-65335 auth: Make oauth2 enabled check more efficient 2019-09-20 08:55:32 +01:00
Jake Dallimore 481d6f6387 Merge branch 'MDL-65970-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-09-20 14:28:36 +08:00
Jake Dallimore a174ed3736 MDL-66106 core_form: fix client side validation bug caused by MDL-65217
Forms with randomised ids need to support client side validation.
2019-09-20 09:04:37 +08:00
Sara Arjona eb77088991 weekly release 3.7.2+ 2019-09-19 21:19:19 +02:00
Stefan Topfstedt a9c3e2f95e MDL-66433 block_myoverview: tag courses as "hidden from students"
This is intended to visually separate hidden course from open courses in the course overview block
by applying a "Hidden from students" tag to the various views in this block.
To achive this, the course summary exporter's output must be augmented with a "visiblity" attribute,
carrying the given course's corresponding visibility setting.
Since the exporter now expects this data point as part of its input, the output of the course_get_recent_courses()
function had to also be augmented with the course visibility setting to provide this value.
2019-09-19 10:11:03 -07:00
Nathan Nguyen 9cab0bb465 MDL-46978 core_grades: preserve category total visibility 2019-09-19 14:11:16 +10:00
Andrew Nicols 53c04bafc2 MDL-66675 behat: Fix typo in step function name 2019-09-19 07:31:07 +08:00
Andrew Nicols 409b3bbd81 MDL-66675 behat: Add option to pause on behat failures 2019-09-19 07:31:06 +08:00
Andrew Nicols fcad36339a MDL-66675 CLI: Add ANSI formatting options 2019-09-19 07:31:06 +08:00
Eloy Lafuente (stronk7) 10892d50d2 Merge branch 'MDL-66548-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-09-19 01:01:46 +02:00
Eloy Lafuente (stronk7) 69aca65995 Merge branch 'MDL-66641_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-09-18 20:30:04 +02:00
Eloy Lafuente (stronk7) ec5aca167c Merge branch 'MDL-65878-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-09-18 20:07:59 +02:00
Luca Bösch 59cf70e977 MDL-65878 core_output: Move button not sticky to select field. 2019-09-18 19:11:37 +02:00
Eloy Lafuente (stronk7) 1c8d4b0bce Merge branch 'MDL-63895-37' of git://github.com/vmdef/moodle into MOODLE_37_STABLE 2019-09-18 17:33:26 +02:00
Sara Arjona ed401f9445 Merge branch 'MDL-66614_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-09-18 17:11:07 +02:00
Eloy Lafuente (stronk7) a80c888892 Merge branch 'MDL-66091_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-09-18 16:47:09 +02:00
Sara Arjona 6354c24aed Merge branch 'MDL-63293-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-09-18 13:40:01 +02:00
Sara Arjona 5d21bf1b16 Merge branch 'MDL-66156-37' of https://github.com/snake/moodle into MOODLE_37_STABLE 2019-09-18 12:25:48 +02:00
David Monllaó 4a3f3ee3e4 MDL-66091 report_insights: Unify contextwithinsights cache sets 2019-09-18 13:00:26 +08:00
David Monllaó b2d9aaa126 MDL-66091 analytics: Targets choose if there should be a report or not 2019-09-18 13:00:25 +08:00
David Monllaó 5e17f2faeb MDL-66091 report_insights: Usability improvements
- More feedback provided for the user once they click on useful/notuseful from the email.
- Replace the indicator calculations table headers for the table caption and
  replace the text by just "Indicators"
- Replace "System" for the site name for insights generated at system
  level
- Replace "$modelname prediction" for "$modelname" in report/insights/prediction.php
  heading

MDL-66091
2019-09-18 13:00:25 +08:00
Eloy Lafuente (stronk7) 92e745c293 Merge branch 'MDL-65026-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-09-18 01:01:42 +02:00
Juan Leyva f4670d9e85 MDL-65970 airnotifier: Set lower timeout for Push curl requests 2019-09-17 16:51:06 +02:00
Eloy Lafuente (stronk7) cc1968a042 Merge branch 'MDL-62915-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-09-17 16:21:57 +02:00
Sara Arjona 7e107b3a98 Merge branch 'MDL-66113-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-09-17 12:03:53 +02:00
David Monllaó 6c15dc2f3c MDL-66090 analytics: Support user for notifications 2019-09-17 07:54:22 +08:00
Eloy Lafuente (stronk7) 072c1ad68e Merge branch 'MDL-65025-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-09-17 00:06:03 +02:00
Paul Holden 0590e71eeb MDL-62915 tool_dataprivacy: don't let primary admin delete themselves. 2019-09-16 22:31:40 +01:00
Eloy Lafuente (stronk7) 3536e97dc8 Merge branch 'MDL-66293-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-09-16 20:37:08 +02:00
Bas Brands f5cb0ec042 MDL-66548 theme_classic: secure layout block position fixes
- the secure layout for theme classic used an icorrect layout for blocks
and content. A fix has been submitted by G J Barnard.
2019-09-16 16:03:50 +02:00
Tim Hunt 40ed8aa97a MDL-66685 questions: should able to save an empty question usage 2019-09-16 14:36:47 +01:00
Juan Leyva 309550be69 MDL-65026 course: Fix modules intro formatting in WS
The Web Service seems to be doing excessive text cleaning.
2019-09-16 13:04:06 +02:00
Juan Leyva 535caf12c6 MDL-66113 assign: Apply user overrides in get_submission_status WS 2019-09-16 12:06:18 +02:00
Paul Holden e4bb1b0d75 MDL-63293 enrol_manual: observe user paging config in enrol dialog. 2019-09-15 21:48:13 +01:00
Eloy Lafuente (stronk7) bd3ce90c13 MDL-66262 env: Moodle 3.6.x and 3.7.x do not support PHP 7.4 2019-09-13 17:43:52 +02:00
Jake Dallimore 1542213b00 weekly release 3.7.2+ 2019-09-13 11:30:20 +08:00
Jake Dallimore 6a838cd4a0 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-09-13 11:30:19 +08:00
Eloy Lafuente (stronk7) c0858f7068 Merge branch 'MDL-66550-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-12 15:31:44 +02:00
Andrew Nicols 1128545ebf MDL-66550 admin: The execute wrapper MUST be used in behat 2019-09-12 20:58:10 +08:00
Andrew Nicols 484606eb08 MDL-66550 theme: Wrap JS calls in pendingJS 2019-09-12 20:58:10 +08:00
Víctor Déniz Falcón 2d28f15a3a MDL-63895 user: Hide suspended enrolments to user without capability
Users without course:viewsuspendedusers capability should not view
suspended users on the participant list
2019-09-12 11:46:41 +01:00
Shamim Rezaie e6f2757f3c MDL-66293 javascript: set maximum paging bar size to 10 2019-09-12 14:22:13 +10:00
Shamim Rezaie f525ed2bdc MDL-66293 javascript: Added support to set bar size for paging bars 2019-09-12 14:22:13 +10:00
Jake Dallimore df991a4d53 MDL-66156 block_myoverview: remove orphaned course favourite records 2019-09-12 12:09:49 +08:00
Jake Dallimore d72a6fc04c MDL-66156 block_myoverview: purge course favourites on course deletion. 2019-09-12 11:47:50 +08:00
Andrew Nicols 83ecf18e34 Merge branch 'MDL-66498_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-09-12 11:16:44 +08:00
Jake Dallimore 49b92a4a70 Merge branch 'MDL-64917-MOODLE_37_STABLE' of https://github.com/tuanngocnguyen/moodle into MOODLE_37_STABLE 2019-09-12 09:28:13 +08:00
Nathan Nguyen d540a0ae0b MDL-64917 filepicker: change event dispatch 2019-09-12 11:01:19 +10:00
AMOS bot a2f1de61a0 Automatically generated installer lang files 2019-09-12 00:09:22 +00:00
Andrew Nicols ae89df663a Merge branch 'MDL-66489-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-09-12 07:06:43 +08:00
Shamim Rezaie ee8d64f6ef MDL-66489 enrol: Send all form data to WS and do all busines logic there
It is discouraged to use JS Date functions. We should pass all raw data to PHP.
2019-09-11 20:31:56 +10:00
Andrew Nicols 11ac4acdb1 Merge branch 'MDL-65429-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-09-11 14:22:46 +08:00
Jake Dallimore c3fbb0278b Merge branch 'MDL-65493-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-11 13:45:40 +08:00
David Monllaó 375c1b8e20 MDL-66498 analytics: get_samples() with no params limit 2019-09-11 12:44:38 +08:00
David Monllaó 868cd1eacb MDL-66498 analytics: Avoid get_in_or_equal for big arrays
Also, join directly with context table.
2019-09-11 12:44:38 +08:00
David Monllao 4996652352 MDL-66498 analytics: SQL IN in chunks 2019-09-11 12:44:38 +08:00
Andrew Nicols 3857644a5c Merge branch 'MDL-66328_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-09-11 12:21:33 +08:00
Jake Dallimore eb8ecb04b6 Merge branch 'MDL-66550-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-11 10:39:57 +08:00
Eloy Lafuente (stronk7) 8e6fdc1cdb Merge branch 'MDL-66436-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-09-11 01:21:49 +02:00
Eloy Lafuente (stronk7) 733a5b75e9 Merge branch 'MDL-65310-37' of https://github.com/tsmilan/moodle into MOODLE_37_STABLE 2019-09-11 00:44:39 +02:00
David Mudrák af58905893 MDL-66644 admin: Display required moodle version only when declared
The minimum required Moodle version specified in the plugin's
version.php file is not a mandatory field. If it is not declared, do not
display "Moodle {$a}".
2019-09-10 17:40:07 +02:00
Andrew Nicols af0fd8128f MDL-66550 forum: Target fields in a fieldset for behat test 2019-09-10 21:29:03 +08:00
Andrew Nicols b559117706 MDL-66550 behat: Transform fields to search in a fieldset 2019-09-10 21:29:03 +08:00
Andrew Nicols 4e6831d51c MDL-66550 behat: Standardise finding in core functionality 2019-09-10 21:29:03 +08:00
Andrew Nicols e60183e163 MDL-66550 behat: Add ability to transform a specific selector 2019-09-10 21:29:00 +08:00
Andrew Nicols 59b30e3dae MDL-66550 behat: Normalise selectors better 2019-09-10 21:28:47 +08:00
Tim Hunt 87cc8008f4 MDL-66641 quiz stats: discriminativeefficiency is already out of 100 2019-09-10 12:12:00 +01:00
Jake Dallimore 35a8f83e2c Merge branch 'MDL-66409-edit-numerical/moodle37' of https://github.com/RaAstons/moodle into MOODLE_37_STABLE 2019-09-10 13:35:00 +08:00
Andrew Nicols a31372df3f Merge branch 'MDL-63250-37' of https://github.com/Kathrin84/moodle into MOODLE_37_STABLE 2019-09-10 12:40:41 +08:00
Jake Dallimore 252cc45466 Merge branch 'MDL-66599_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-09-10 10:47:00 +08:00
Tim Hunt b652d2afc7 MDL-66328 groups: overview page can require lots of memory 2019-09-09 11:20:00 +01:00
Raphaël Santos 070453243b MDL-66409 mod_lesson: Fix editing of numerical pages
This avoids using the "magic" `isset` function implemented
within the lesson_base class (which returns the `empty` function).
In the case of the answer beeing `0`, the test fails and the answer
is considered to be deleted.
2019-09-09 09:43:32 +02:00
David Monllaó 991a4c0fd1 MDL-66599 analytics: New index for analytics_used_analysables 2019-09-09 08:32:51 +08:00
Jake Dallimore 6a30269d98 Moodle release 3.7.2 2019-09-06 11:50:45 +08:00
Trisha Milan 8faaa5da65 MDL-65310 block_timeline: Hide activities without due date 2019-09-06 13:48:24 +10:00
Andrew Nicols f6dd23d9a2 MDL-65493 core: Add pendingJS around pubsub.publish 2019-09-06 08:40:56 +08:00
Andrew Nicols b82faf7eda MDL-65493 message: The execute wrapper MUST be used 2019-09-06 08:40:56 +08:00
Andrew Nicols 191c5c293a MDL-65493 message: JS fixes for random behat fails 2019-09-06 08:40:56 +08:00
Luca Bösch 8d2bae85ed MDL-66436 glossary: Edit and delete categories form styles. 2019-09-05 18:02:28 +02:00
Eloy Lafuente (stronk7) e064cef324 weekly release 3.7.1+ 2019-09-05 17:14:43 +02:00
Eloy Lafuente (stronk7) eca36ffd7c Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-09-05 17:14:41 +02:00
Andrew Nicols 4f32de51a9 MDL-66614 pgsql DML: Update get_records_sql to consume less memory
This is a backport of MDL-66327.

It's more memory efficient to use `pg_fetch_assoc` for each row than to
call `pg_fetch_all` and release memory immediately. This is because we
can treat the assoc fetch like an iterator and it only fetches the
current record into memory one at a time, whilst the all fetch fetches
all records and never unsets them. Attempting to unset them is extremely
time consuming.
2019-09-05 16:01:44 +01:00
Jake Dallimore 5f115af823 Merge branch 'MDL-56223-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-09-05 17:20:28 +08:00
Simey Lameze 474a338a97 MDL-56223 calendar: fix wrong create_calendar_events WS phpdoc 2019-09-05 17:16:06 +08:00
Simey Lameze 7bbc73ce0c MDL-56223 calendar: show the number of deleted events 2019-09-05 17:16:05 +08:00
Simey Lameze cb5145334d MDL-56223 calendar: skip events updating if nothing has changed 2019-09-05 17:16:05 +08:00
Jake Dallimore 5a552ad6f3 Merge branch 'MDL-66551-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-09-05 11:15:16 +08:00
Simey Lameze 5c1115ba0b MDL-66551 core_user: remove orphaned calendar subscriptions 2019-09-05 11:07:47 +08:00
Simey Lameze 7ec6835728 MDL-66551 core_user: delete_user() should remove users calendar subs 2019-09-05 10:52:10 +08:00
Andrew Nicols e567e64d12 Merge branch 'MDL-66391-37' of https://bitbucket.org/isprynt/moodle into MOODLE_37_STABLE 2019-09-05 09:59:28 +08:00
Eloy Lafuente (stronk7) bade4a18e5 Merge branch 'MDL-66072-37-2' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-09-05 02:48:17 +02:00
Eloy Lafuente (stronk7) 49ab08f771 Merge branch 'MDL-66560-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-09-05 02:17:37 +02:00
AMOS bot 3923a219bd Automatically generated installer lang files 2019-09-05 00:11:58 +00:00
Segun Babalola 750ec445bd MDL-66391 core_course: Fix to send correct Ajax parameter for userid 2019-09-04 12:26:11 +01:00
Andrew Nicols 1dfd080f54 Merge branch 'MDL-66137-37_mod_assign_marking_workflow_incorrect_grade_display' of https://github.com/tomdickman/moodle into MOODLE_37_STABLE 2019-09-04 13:47:50 +08:00
Tom Dickman 3c239a6a11 MDL-66137 mod_assign: fixed marking workflow incorrect grade display
Aligned logic between quick grading changes and set marking workflow state changes to accurately
finalise or remove final grade from the gradebook, depending on the marking workflow state if
being used.
2019-09-04 15:23:09 +10:00
Andrew Nicols 4da24e858c Merge branch 'MDL-66554-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-09-04 12:39:29 +08:00
Andrew Nicols 4d4a8423b0 Merge branch 'MDL-66500-37-unoconvwarning' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-09-04 12:14:23 +08:00
Ryan Wyllie b937159eed MDL-62284 javascript: prevent nested JS mustache handler calls
Prevent the JS mustache helper from being executed from within
the render call of another mustache helper because it can allow
users to inject JS into the page.
2019-09-04 11:23:35 +08:00
Ryan Wyllie 0c4d9eff86 MDL-62284 output: prevent nested JS mustache handler calls
Prevent the JS mustache helper from being executed from within
the render call of another mustache helper because it can allow
users to inject JS into the page.
2019-09-04 11:23:35 +08:00
Jake Dallimore 25f23432f3 Merge branch 'MDL-66265-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-04 11:06:42 +08:00
Andrew Nicols 3a0efca438 MDL-66265 javascript: More specific overrides in eslintrc 2019-09-04 10:48:57 +08:00
Eloy Lafuente (stronk7) 1124ceea9a Merge branch 'MDL-66265-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-04 02:12:52 +02:00
AMOS bot e5cddc8c7e Automatically generated installer lang files 2019-09-04 00:11:10 +00:00
Eloy Lafuente (stronk7) 1f6ca1e497 Merge branch 'MDL-66532-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-04 02:01:15 +02:00
Peter 332da1d527 MDL-66072 core: Remove ancillary sharing functions and code 2019-09-04 07:34:06 +08:00
Peter 645beae25f MDL-66072 core: Remove course sharing and related capabilities 2019-09-04 07:33:33 +08:00
Andrew Nicols 1831e2b2fc MDL-66265 javascript: Add jshint ignore for ES6 files in root dir 2019-09-04 06:52:07 +08:00
Andrew Nicols ca88210f3f MDL-66265 javascript: Add basic jshint ignores 2019-09-04 06:50:55 +08:00
Andrew Nicols 05582654f2 MDL-66265 javascript: Bump jshint version 2019-09-04 06:50:55 +08:00
Andrew Nicols c5f693dede MDL-66532 javascript: Lock NPM version for NVM 2019-09-04 06:50:55 +08:00
Andrew Nicols 7f9d364fd2 MDL-66532 javascript: Lock NPM version for NVM 2019-09-04 06:45:51 +08:00
Eloy Lafuente (stronk7) b1f0f049d0 Merge branch 'MDL-63315-m37' of https://github.com/sammarshallou/moodle into MOODLE_37_STABLE 2019-09-04 00:15:07 +02:00
Eloy Lafuente (stronk7) 0ac06b7216 Merge branch 'MDL-66120-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-09-03 12:13:36 +02:00
Andrew Nicols 499dfeff2a Merge branch 'MDL-66434-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-09-03 12:41:11 +08:00
Andrew Nicols 59d7f7f2cb Merge branch 'MDL-62161-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-09-03 11:50:17 +08:00
Andrew Nicols 57e38ad969 Merge branch 'MDL-65042-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-09-03 09:29:24 +08:00
AMOS bot 54a8fef92f Automatically generated installer lang files 2019-09-03 00:11:33 +00:00
Eloy Lafuente (stronk7) cdbe521e62 Merge branch 'MDL-66457-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-09-03 00:54:54 +02:00
sam marshall 8571a061e7 MDL-63315 DB: Postgres - Clear cursors in persistent connection
If there is a PHP fatal error and destructors do not run (this can
happen in out-of-memory errors, and maybe if there is an error in a
previous destructor) then Postgres cursors may be left open.

Usually this does not cause a problem because the connection is
closed anyway, but if using persistent connections, a future
request may reuse the connection with a cursor open. It then gets
errors when it tries to create a new cursor with the same name.

This change closes all cursors at the start of a persistent
connection.
2019-09-02 14:10:05 +01:00
Peter 19069c7f28 MDL-66120 block_community: Disable community block and related caps
Disable community block access
2019-09-02 15:51:52 +08:00
Juan Leyva 18b42d9835 MDL-66501 tool_mobile: Prevent URLs in custom scheme 2019-09-02 15:29:27 +08:00
Jun Pataleta ebd3da32b5 MDL-66187 format_singleactivity: Make sure available types is not empty 2019-09-02 05:07:37 +02:00
Andrew Nicols b70e27f531 MDL-66187 course: Respect :addinstance in single activity format 2019-09-02 05:07:37 +02:00
Simey Lameze bd7217b3d8 MDL-65749 lib: fix phpmailer file handling 2019-09-02 05:07:37 +02:00
Andrew Nicols d99d036b44 MDL-66181 course: Only assign roles that the user is allowed to assign 2019-09-02 05:07:37 +02:00
Andrew Nicols 858f188c0f MDL-66181 behat: You check checkboxes, not click them 2019-09-02 05:07:37 +02:00
Michael Hawkins d31f12bcbd MDL-55451 mod_forum: Limit subscription redirect to internal URLs 2019-09-02 05:07:37 +02:00
David Monllaó b7f8d08706 MDL-66069 mlbackend_python: Bump to a new version of the package 2019-09-02 05:07:37 +02:00
Andrew Nicols ee4a93267f Merge branch 'MDL-66472-37' of https://github.com/Dagefoerde/moodle into MOODLE_37_STABLE 2019-09-02 11:03:00 +08:00
Andrew Nicols da7d965e01 Merge branch 'MDL-33087-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-09-02 10:48:05 +08:00
David Mudrák 5e52542b1e MDL-66504 lang: Use the new strings in the Behat scenario 2019-09-01 12:34:53 +02:00
Helen Foster 767b4df9c3 MDL-66504 lang: Import fixed English strings (en_fix)
Significant string changes:

- mobilenotificationsdisabledwarning,tool_mobile - location corrected
- statsreport14,core - 'views/posts' corrected to 'posts/views'
- err_nousers,core_completion - explanation of who completion
- information is displayed for errorcourselisting,block_community - note
  about sunsetting moodle.net
2019-09-01 12:34:25 +02:00
Paul Holden 10539bfad8 MDL-62161 user: preserve all selected users between searches. 2019-08-30 14:37:20 +01:00
Paul Holden 69f5ad8f36 MDL-33087 tool_capability: correct role override link. 2019-08-30 14:34:34 +01:00
Luca Bösch 8d650c02c4 MDL-66560 import: Format course search UI elements. 2019-08-30 11:32:16 +02:00
Andrew Nicols e971f11251 MDL-66457 behat: simplify selector search 2019-08-30 15:13:07 +08:00
Luca Bösch 1ca2f014bb MDL-66434 mod_data: Align 'Field description' field as all other fields. 2019-08-30 07:57:30 +02:00
Jake Dallimore f3c2624fbc weekly release 3.7.1+ 2019-08-30 13:12:12 +08:00
Jake Dallimore 543191e0dc Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-08-30 13:12:11 +08:00
Peter 341c68c779 MDL-65429 mod_forum: Indicate subs fetch completion with no subs
Unit tests updated to make sure only a single query is executed after
multiple reads
2019-08-30 09:08:29 +08:00
Juan Leyva ecf1a221dc MDL-66554 mod_scorm: Set module viewed in WS 2019-08-29 20:46:11 +01:00
Jake Dallimore 2a1ef8b3a7 Merge branch 'MDL-66139_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-08-29 11:51:42 +08:00
Netica Informática 77399dd147 MDL-66139 cachestore_redis: Fix connection problems when port is not set
Due to some changes in Redis 5 php extension Moodle fails to connect via TCP when
no port is set. It's fixed upstream in phpredis repo (version 5.0.0, 5.0.1 and
5.0.2 affected so far), but with this patch we'll send the right port anyway.
2019-08-28 20:58:46 +02:00
Eloy Lafuente (stronk7) 48aad65284 Merge branch 'MOODLE_37_STABLE_MDL-65116' of https://github.com/yao9394/moodle into MOODLE_37_STABLE 2019-08-28 16:40:08 +02:00
Adrian Greeve a5eac2bf95 Merge branch 'MDL-66230-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-08-28 14:55:55 +08:00
Pau Ferrer Ocaña 15ebf11b5e MDL-66458 forum: Fix noviewdiscussionspermission string 2019-08-28 11:27:01 +08:00
Adrian Greeve f0c559d33b Merge branch 'MDL-66461-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-08-28 11:17:09 +08:00
Adrian Greeve 8da3995f30 Merge branch 'MDL-66468-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-08-28 08:56:30 +08:00
AMOS bot 903f4721c9 Automatically generated installer lang files 2019-08-28 00:10:47 +00:00
Adrian Greeve 810e115d6f Merge branch 'MDL-65653-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-08-27 15:09:07 +08:00
Eloy Lafuente (stronk7) 3b7968954c MDL-66184 core: Update composer to apply for php 7.1.0 as min
With behat extension v3.37.2 we started requiring php 7.1.0
(same requirement than core 3.7.x). This bumps all the components
in the lock file to suit that requirement.

Generated with php 7.1.x.
2019-08-27 00:37:45 +02:00
David Mudrák 15847cecbf MDL-66500 lang: Do not mark unoconvwarning as deprecated
It has been deprecated by mistake.
2019-08-26 21:29:16 +02:00
Eloy Lafuente (stronk7) 4e41fc8b18 Merge branch 'MDL-66309-m37' of https://github.com/sammarshallou/moodle into MOODLE_37_STABLE 2019-08-26 20:23:13 +02:00
Eloy Lafuente (stronk7) c4e65af6f3 Merge branch 'MDL-66312-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-26 19:40:27 +02:00
Jan Dageförde 5ab6beeb50 MDL-66472 forms: Fix regression autocomplete not closing 2019-08-26 17:58:05 +02:00
Eloy Lafuente (stronk7) 684d142401 weekly release 3.7.1+ 2019-08-23 19:16:34 +02:00
Jun Pataleta 78d57d0ae7 Merge branch 'MDL-66483_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-08-23 20:15:16 +08:00
sam marshall df8633b8d0 MDL-66309 block_recentlyaccesseditems: Improve upgrade performance 2019-08-23 11:35:35 +01:00
Eloy Lafuente (stronk7) a22c821033 MDL-66483 lib: remove recent xmlize dep on setuplib/CFG
This removes the dependency added by MDL-66110 (aiming to fix
a CI job). So we keep things as they were and will fix the
CI job separately.
2019-08-23 11:30:50 +02:00
Adrian Greeve e3bd18d3d7 weekly release 3.7.1+ 2019-08-23 12:55:36 +08:00
Adrian Greeve 9856202e71 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-08-23 12:55:28 +08:00
John Yao c5892e5e37 MDL-65116 mod_assign : Assignment due date does not update for groups
This commit fixes the assignment due date not showing correctly according to groups selected by users who can view grades
2019-08-23 13:11:36 +10:00
Jun Pataleta 9c0aa6e6d0 Merge branch 'MDL-66110-37-fix' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-08-23 10:21:25 +08:00
Jun Pataleta 97a6abc12f MDL-66110 core: Require setuplib.php once as it's required by xmlize.php 2019-08-23 10:16:08 +08:00
Juan Leyva 7cea622409 MDL-66468 file: Return text content when using IGNORE_FILE_MERGE 2019-08-22 13:11:58 +01:00
Jun Pataleta 085d6e79e1 Merge branch 'MDL-66110-37-fix' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-08-22 16:26:07 +08:00
Jun Pataleta ddc3699107 MDL-66110 dml: Undo table name fix when table name's used as parameter 2019-08-22 16:17:55 +08:00
Ryan Wyllie a0d8aefacf MDL-66110 dml: use fix_table_name for all mysql table names
Changed all of the places that were manually prefixing the table
name to instead fix the table name with the fix_table_name
function.
2019-08-22 16:17:55 +08:00
Adrian Greeve 3017d2bab8 Merge branch 'MDL-66378-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-22 09:29:33 +08:00
Andrew Nicols 93c5807711 MDL-66378 behat: Increase window size for rubric tests 2019-08-22 07:55:59 +08:00
Andrew Nicols 5bc2cb3c0e MDL-66378 behat: Change screen size to small to work around UI bugs 2019-08-22 07:55:59 +08:00
Jun Pataleta caca47f50a Merge branch 'MDL-66336_37_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_37_STABLE 2019-08-21 22:41:30 +08:00
Juan Leyva cf24975d2e MDL-66461 forum: Use correct component for forum strings 2019-08-21 13:22:08 +01:00
Juan Leyva da048e60db MDL-66461 forum: Use correct notification class 2019-08-21 13:22:08 +01:00
Jun Pataleta fc0bb48542 Merge branch 'MDL-66241_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-08-21 19:51:56 +08:00
Jun Pataleta 9234d79fd1 Merge branch 'MDL-66210_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-08-21 19:48:00 +08:00
Jun Pataleta 7971d7270c Merge branch 'MDL-65993_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-08-21 19:31:54 +08:00
Adrian Greeve 5ca6cce026 Merge branch 'MDL-65443-m37' of https://github.com/NeillM/moodle into MOODLE_37_STABLE 2019-08-21 16:38:49 +08:00
Neill Magill 8b0bf17160 MDL-65443 core: Improve class descriptions for locking events 2019-08-21 09:03:25 +01:00
Jun Pataleta e65777fd22 Merge branch 'MDL-66110-37' of https://github.com/ryanwyllie/moodle into MOODLE_37_STABLE 2019-08-21 09:57:33 +08:00
Adrian Greeve f6735cb3e0 Merge branch 'MDL-66378-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-21 09:01:21 +08:00
Andrew Nicols 3c3a806f6b MDL-66378 behat: Correct grammar of resize step 2019-08-21 08:39:51 +08:00
Andrew Nicols bf52d11f1e MDL-66378 grade: Set window size to large for rubric tests 2019-08-21 08:39:28 +08:00
Andrew Nicols 1a11bf4706 MDL-66378 behat: All args are required for document.evaluate 2019-08-21 08:24:08 +08:00
AMOS bot da428650cd Automatically generated installer lang files 2019-08-21 00:11:16 +00:00
Adrian Greeve de186ff27f Merge branch 'MDL-65972-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-08-20 16:51:13 +08:00
Neill Magill 3aa7b0df78 MDL-65443 core: Log when a context is locked or unlocked 2019-08-20 08:57:04 +01:00
Jun Pataleta d329ada4b9 Merge branch 'MDL-64437-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-08-20 14:19:27 +08:00
Adrian Greeve 77d0435c3e Merge branch 'MDL-66378-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-20 14:07:42 +08:00
Jun Pataleta d64f8235fe Merge branch 'MDL-65507-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-08-20 11:57:20 +08:00
Adrian Greeve 3ebe724736 Merge branch 'MDL-65083-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-08-20 10:04:56 +08:00
Adrian Greeve 4f41f8407d Merge branch 'MDL-65561-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-08-20 09:37:18 +08:00
AMOS bot a95b434f3e Automatically generated installer lang files 2019-08-20 00:10:43 +00:00
Adrian Greeve 827473833d Merge branch 'MDL-65604-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-19 16:28:04 +08:00
Bas Brands 84720307c3 MDL-65972 course: add a bigger margin above the activity navigation
* this will help making it easier to distinguish between form and
activity navigation
2019-08-19 08:29:01 +02:00
Bas Brands d70fb8fefe MDL-65561 themes: user date filters display fixes 2019-08-19 08:24:38 +02:00
Bas Brands 559b686e5b MDL-65083 theme_boost: update uses of pull-xs-right 2019-08-19 08:19:49 +02:00
Adrian Greeve dda635074d Merge branch 'MDL-65886-MOODLE-37' of https://github.com/kristian-94/moodle into MOODLE_37_STABLE 2019-08-19 14:18:29 +08:00
Mihail Geshoski 0ada61fdcf MDL-64437 assignment: Fix element overlaping in low screen resolution 2019-08-19 13:31:29 +08:00
Mihail Geshoski dbc5a45cc6 MDL-65507 mod_data: Remove unnecessary record created event 2019-08-19 13:27:14 +08:00
Andrew Nicols 8356ee9462 MDL-66378 competency: Add pending promises to competency chooser 2019-08-19 08:16:41 +08:00
Andrew Nicols 710ec0e546 MDL-66378 behat: JS does not work with newlines in an xpath 2019-08-19 08:16:40 +08:00
Andrew Nicols 3c3f5965d3 MDL-66378 behat: Fix use of before/after selectors 2019-08-19 08:16:40 +08:00
Andrew Nicols 6f2760071c MDL-66378 behat: Backport expand autocomplete step 2019-08-17 16:19:48 +08:00
Andrew Nicols 9c3d4683a4 MDL-66378 behat: Add partial named selector for whole autocomplete field 2019-08-17 11:44:48 +08:00
Andrew Nicols dcb7cfd384 MDL-66378 behat: Before/after detection should be constrainable
The default before/after detection checks the entire body. Any match of
the text will therefore be found.

Add support for specification of a container for the nodes.
2019-08-17 11:44:48 +08:00
Andrew Nicols 0fbabd85c6 MDL-66378 behat: Add non-JS fallback for before/after 2019-08-17 11:44:48 +08:00
sam marshall 96482ded5e MDL-66378 Behat: Speed up 'before/after' step in Chrome
On some Chrome versions the xpath used for before/after is slow
and (sometimes) uses a lot of memory. This change uses pure
JavaScript to do the before/after calculation, which should always
be fast.
2019-08-17 11:44:48 +08:00
Andrew Nicols 1cb4d36126 MDL-66378 behat: Correct invalid uses of selection from dropdown 2019-08-17 11:44:48 +08:00
Andrew Nicols 7ae0f78bf2 MDL-66378 report_participation: Correct label for target 2019-08-17 11:44:48 +08:00
Andrew Nicols f214adb270 MDL-66378 gradereport_singleview: Add missing label for dropdown 2019-08-17 11:44:48 +08:00
Juan Leyva 613e3038f8 MDL-65042 rating: Fix incorrect image generated for user in rating 2019-08-16 15:41:44 +01:00
Juan Leyva d2154bafdb MDL-65025 forum: Fix text formatting (check messagetrust) in WS 2019-08-16 12:59:05 +01:00
Mark Johnson 7f45491d4d MDL-66336 courses: Show an error when no course categories are visible 2019-08-16 08:25:42 +01:00
Kristian Ringer 2f39bfc7d8 MDL-65886 assign: Reset numfiles to 0 when removing a file submission 2019-08-16 15:03:59 +10:00
Andrew Nicols 09979fde33 MDL-66378 behat: Update screen sizes to Y2K standards 2019-08-16 11:43:57 +08:00
Andrew Nicols 4fbeed480a MDL-66378 behat: Update dependencies for chrome webdriver fix 2019-08-16 11:43:01 +08:00
Andrew Nicols 39f22c5f7d MDL-66312 js: Autocomplete promises were inside out
The pending promise should nott be resolved until the changes are
complete.
Previously the resolution of the pendingPromise was triggering the other
changes.
2019-08-16 11:40:15 +08:00
Andrew Nicols 5a0c850e50 weekly release 3.7.1+ 2019-08-16 11:07:05 +08:00
Andrew Nicols a408e168cc Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-08-16 11:07:02 +08:00
Juan Leyva bb5b12d936 MDL-65653 book: Display hidden chapters in the structure content 2019-08-15 14:02:30 +01:00
Mihail Geshoski 091faeeb09 MDL-65653 book: Update unit tests 2019-08-15 14:02:30 +01:00
Mihail Geshoski 6c00f683db MDL-65653 book: Display hidden chapters in WS when user has capability 2019-08-15 14:02:30 +01:00
Andrew Nicols 30f719c44c Merge branch 'MDL-35939-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-08-15 12:03:48 +08:00
Jun Pataleta 1893b39bfc Merge branch 'm37_MDL-66140_Mitigate_PECL_Solr_issue_Ref_72740' of https://github.com/scara/moodle into MOODLE_37_STABLE 2019-08-15 11:17:40 +08:00
Shamim Rezaie 102579cf75 MDL-35939 mod_quiz: use descriptive titles for pages 2019-08-15 12:23:03 +10:00
Shamim Rezaie 38629d7f32 MDL-35939 mod_quiz: phpdoc fix 2019-08-15 12:23:03 +10:00
Shamim Rezaie df5bca4acc MDL-35939 mod_quiz: new functions to generate title for attempt pages 2019-08-15 12:22:58 +10:00
AMOS bot 7db7c8e953 Automatically generated installer lang files 2019-08-15 00:12:53 +00:00
Jun Pataleta a77c92bb9c Merge branch 'MDL-65925-grade-page-broken-for-deleted-submission-MOODLE_37_STABLE' of https://github.com/ilya-catalyst/moodle into MOODLE_37_STABLE 2019-08-14 15:28:01 +08:00
David Monllaó 2850311ace MDL-66210 analytics: Unit test for reuseprevanalysed 2019-08-14 14:31:59 +08:00
David Monllaó 8e09ae50b0 MDL-66210 analytics: Update references to ->options 2019-08-14 14:31:59 +08:00
David Monllaó 6ac4aa49aa MDL-65993 analytics: Fix --filter option for by_course models 2019-08-14 14:30:25 +08:00
David Monllaó a639cddc39 MDL-66241 analytics: Verify that activities_due works on at-risk 2019-08-14 14:29:20 +08:00
David Monllaó 4f910adaea MDL-66241 analytics: activities_due compatible with at-risk models 2019-08-14 14:29:20 +08:00
Andrew Nicols 9cb87ef480 Merge branch 'patch-2' of https://github.com/aspark21/moodle into MOODLE_37_STABLE 2019-08-14 11:37:09 +08:00
Adrian Greeve 7cdba7e644 Merge branch 'MDL-52849-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-08-14 09:07:24 +08:00
Jun Pataleta 5e0c8cfd32 Merge branch 'MDL-62034-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-13 14:20:35 +08:00
Andrew Nicols 0566565254 MDL-62034 assign: Add hint for user tour reset 2019-08-13 14:12:56 +08:00
Ryan Wyllie 5068a6ccef MDL-66110 dml: Fix MySQL v8 compatibility with groups table
MySQL v8 has added "groups" to the reserved word list. That is used
as a table name in Moodle so we have to quote it with backticks in the
SQL so that MySQL knows it's being used as an identifier.
2019-08-13 11:15:38 +08:00
Jun Pataleta c98cd8ccc8 Merge branch 'MDL-66104_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-08-12 14:51:52 +08:00
Peter 21010ab799 MDL-52849 core: Focus reader onto popup with ajax errors 2019-08-12 10:52:31 +08:00
Ilya Tregubov 91c036db6f MDL-65925 assign: Grade page broken if submission was deleted. 2019-08-12 09:28:12 +10:00
Matteo Scaramuccia e3d9c87993 MDL-66140 search: Mitigate PECL solr extension regression
Refs:
- https://bugs.php.net/bug.php?id=72740
- https://bugs.php.net/bug.php?id=75631
- https://github.com/php/pecl-search_engine-solr/pull/16
2019-08-11 20:06:01 +02:00
Andrew Nicols 02afdd58e8 MDL-65604 repository: Kill off missing param errors
The file picker template included an img with a src of "#". When the
template was loaded into the modal, the browser fetches the img src, but
it's immediately removed as that section is only used as an in-place
template. The src tag does not need to be present.
2019-08-11 14:52:55 +08:00
AMOS bot 59d22708dc Automatically generated installer lang files 2019-08-10 00:11:18 +00:00
Jun Pataleta 79bd60bff7 weekly release 3.7.1+ 2019-08-09 16:24:07 +08:00
Jun Pataleta 03667bad20 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-08-09 16:24:05 +08:00
Jun Pataleta d92b3f2abb Merge branch 'MDL-65679-37-fix' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-08-09 11:39:24 +08:00
Andrew Nicols d798b75928 MDL-65679 assignfeedback_editpdf: Adjust z-indexes for editpdf 2019-08-09 08:34:15 +08:00
Victor Deniz Falcon 1e364a4f9a MDL-66272 core_renderer: fix favicon method PHPDoc 2019-08-08 12:44:55 +08:00
Amaia Anabitarte f3732b7838 MDL-60636 behat: Fixing modified xpath 2019-08-08 11:58:10 +08:00
Andrew Nicols 5d85b4a272 Merge branch 'MDL-65595-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-08-08 10:28:30 +08:00
Jun Pataleta 12bd0d77d1 Merge branch 'MDL-57239_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-08-08 08:48:55 +08:00
Andrew Nicols 01f6eaed9b Merge branch 'MDL-66039-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-08-07 15:32:54 +08:00
Jun Pataleta 87fa24daaf Merge branch 'MDL-56789-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-08-07 14:01:25 +08:00
Shamim Rezaie db51a593bb MDL-56789 core: Improve unit tests 2019-08-07 15:32:34 +10:00
Shamim Rezaie 3ba7f31c15 MDL-56789 core: Recycle bin warn only if a grade item is being deleted 2019-08-07 15:30:05 +10:00
Sara Arjona 2666fb1069 Merge branch 'MDL-63198-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-08-07 11:08:01 +08:00
Sara Arjona d3ca2c25e5 Merge branch 'MDL-60636-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-08-07 10:00:55 +08:00
Alistair Spark 4b530e5af8 MDL-66071 user: username is required with non-internal auth method 2019-08-07 01:01:27 +02:00
Sara Arjona e3bf98b8ed Merge branch 'MDL-64598-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-08-06 15:30:08 +08:00
Sara Arjona c316d854e9 Merge branch 'MDL-65786-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-08-06 14:19:33 +08:00
Andrew Nicols ea72ffc95c Merge branch 'MDL-65679-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-08-06 13:17:57 +08:00
Andrew Nicols b0d81fce7b Merge branch 'MDL-65651-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-08-06 11:58:20 +08:00
Andrew Nicols 2fb82c256c Merge branch 'MDL-65992-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-08-06 09:13:36 +08:00
Eloy Lafuente (stronk7) d62afa7ae7 Merge branch 'MDL-64757-37_core_output_nested_template_block_string_language' of https://github.com/tomdickman/moodle into MOODLE_37_STABLE 2019-08-05 13:15:08 +02:00
Andrew Nicols 2bf3ee078b Merge branch 'MDL-33884_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-08-05 14:33:55 +08:00
Sara Arjona b0781430e4 Merge branch 'MDL-66281-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-08-05 13:41:16 +08:00
Andrew Nicols 87eb1e7205 Merge branch 'MDL-66279-37' of git://git.cameron1729.xyz/moodle into MOODLE_37_STABLE 2019-08-05 11:51:35 +08:00
Shamim Rezaie ff03600ad0 MDL-63198 forms: click on scrollbar should not close the suggestions box 2019-08-05 13:16:41 +10:00
Tim Hunt 8d4f41b473 MDL-57239 qbehaviour_interactive: fix Try again button when reviewing 2019-08-02 11:46:17 +01:00
Luca Bösch ee5b530ae6 MDL-65651 forum: Middle align last post column entries. 2019-08-02 12:01:49 +02:00
Luca Bösch 0853ab5730 MDL-64598 pix: Adding width/height information to emoji SVG images. 2019-08-02 11:54:59 +02:00
AMOS bot 23e8249b36 Automatically generated installer lang files 2019-08-02 00:11:23 +00:00
AMOS bot 3876b68dd0 Automatically generated installer lang files 2019-08-02 00:11:23 +00:00
Mihail Geshoski 4935c347cf MDL-65679 assign: Collapsing comments
The comments should appear above everything else when expanded, and expanding/collapsing comments
should not affect the position of anything else in the page.

All credit goes to Damyon Wiese.
2019-08-02 07:39:03 +08:00
Eloy Lafuente (stronk7) cd1a80769f MDL-66104 output: HTMLPurifier to allow <nolink> tags everywhere
Before the patch, HTMLPurifier was instructed to handle <nolink>
tags in block mode. That implies that any block tag enclosing it
had to be closed for HTML compliance.

But <noscript> tags are not part of the final output (they are
removed) but just internally used to skip filtering certain areas.

So they can be virtually everywhere, HTMLPurifier just should allow
them without any change, both to parent or children tags.
2019-08-01 17:52:57 +02:00
Eloy Lafuente (stronk7) 0f13016a50 weekly release 3.7.1+ 2019-08-01 17:07:09 +02:00
Eloy Lafuente (stronk7) 141d8cbe64 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-08-01 17:07:06 +02:00
Shamim Rezaie ec564a7b32 MDL-56789 core: Added unit test for course_modules_pending_deletion 2019-08-01 18:58:28 +10:00
Sara Arjona 90528c757d Merge branch 'MDL-42451-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-08-01 09:53:28 +08:00
Eloy Lafuente (stronk7) c76f2e8095 Merge branch 'MDL-50472-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-08-01 00:28:40 +02:00
Eloy Lafuente (stronk7) 4999558ed4 Merge branch 'MDL-57342-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-07-31 18:52:37 +02:00
Tim Hunt 0101cefdca MDL-33884 question export: raise memory limit
Question exports can be quite big, just like imports can. Therefore, we
should raise memory limits in the same way.

(Of course, eventually we should change the API, so that it writes one
questoin at a time, rather than building the whole export file contents
in RAM first, but that would be a much bigger change, and we need a
quick fix now.)
2019-07-31 16:35:36 +01:00
Mathew May 0a39c68105 MDL-65992 travis: Migrate to Xenial distro and default MySQL service 2019-07-31 13:02:19 +08:00
Jun Pataleta 5f9afeb734 Merge branch 'MDL-65831-37' of git://github.com/aanabit/moodle into MOODLE_37_STABLE 2019-07-31 10:55:49 +08:00
Amaia Anabitarte a193f2a1e3 MDL-65831 behat: New steps to switch offline mode for moodle app behats 2019-07-31 10:44:57 +08:00
Peter 148d163013 MDL-65595 core: Remove the nowrap from the form's radio template 2019-07-31 08:15:35 +08:00
AMOS bot c8c11974f2 Automatically generated installer lang files 2019-07-31 00:09:15 +00:00
Paul Holden ecc9069384 MDL-66230 tool_usertours: account for deleted tours in privacy export. 2019-07-30 09:56:48 +01:00
Cameron Ball 0960745ecb MDL-66279 task: Test if logger is_a database_logger 2019-07-30 14:52:35 +08:00
Jun Pataleta c5437625e1 MDL-66281 tool_dataprivacy: Set sensitive data processing default value 2019-07-30 13:59:14 +08:00
Sara Arjona 941b5cc782 Merge branch 'MDL-63458_37' of https://github.com/rlorenzo/moodle into MOODLE_37_STABLE 2019-07-30 11:59:28 +08:00
Adrian Greeve 02bcfb3631 Merge branch 'MDL-66174-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-07-29 14:40:02 +08:00
Mathew May a02b319727 MDL-42451 installation: Allow enter key to proceed 2019-07-29 10:58:49 +08:00
Mathew May 328f918372 MDL-50472 auth: Add maintenance message to the login page. 2019-07-29 10:48:54 +08:00
Jake Dallimore 2f980fec47 Merge branch 'MDL-65219-37' of https://github.com/ryanwyllie/moodle into MOODLE_37_STABLE 2019-07-26 15:21:15 +08:00
Tom Dickman ad5c8a8954 MDL-64757 core_output: fixed incorrect string language mustache blocks
Mustache blocks nested in parent templates were incorrectly rendering the default language Moodle.
This fix correctly passes the current language preference to all nested mustache templates such as blocks
which are children of another template.
2019-07-26 16:02:59 +10:00
Jake Dallimore ebe574ff58 Merge branch 'MDL-65918-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-07-26 10:57:48 +08:00
Eloy Lafuente (stronk7) 1a89704b05 weekly release 3.7.1+ 2019-07-25 13:45:00 +02:00
Jake Dallimore f082899085 Merge branch 'MDL-65858_37' of git://github.com/markn86/moodle into MOODLE_37_STABLE 2019-07-24 14:31:06 +08:00
Adrian Greeve 0fbdc6705a Merge branch 'MDL-65078-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-07-24 09:52:18 +08:00
Mathew May f4da3acc61 MDL-57342 admin: confightml will check if returned data is empty 2019-07-23 13:31:58 +08:00
Jun Pataleta ef24084985 MDL-65918 auth_oauth2: Require profile library once
Thanks to Jason Grimes for the bug report and fix suggestion!
2019-07-23 10:11:59 +08:00
Adrian Greeve 8b44b91c15 Merge branch 'MDL-66021-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-07-23 09:13:45 +08:00
Eloy Lafuente (stronk7) bfdc0244a1 Merge branch 'MDL-65788-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-07-22 21:34:12 +02:00
Eloy Lafuente (stronk7) f7ade2220a Merge branch 'MDL-66132-m37' of https://github.com/sammarshallou/moodle into MOODLE_37_STABLE 2019-07-22 20:56:11 +02:00
Adrian Greeve 5aa0106bc1 Merge branch 'MDL-66136-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-07-22 10:42:01 +08:00
Eloy Lafuente (stronk7) 2b4ff27983 Merge branch 'MDL-50733_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-07-20 00:24:45 +02:00
Mathew May 78ade565c6 MDL-50733 core: Update composer to updated behat-extension 2019-07-19 16:13:51 +02:00
Eloy Lafuente (stronk7) e222b1ed8d weekly release 3.7.1+ 2019-07-18 17:11:45 +02:00
Eloy Lafuente (stronk7) 9bfa3e8f56 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-07-18 17:11:43 +02:00
Kathrin Osswald bed95cdef1 MDL-63250 mediaplugin: Fixed video player size in specific tables 2019-07-18 13:53:22 +02:00
Matt Porritt 1c97c77cb9 MDL-65858 backup: Improve behaviour of ajax calls
When a backup (or restore) is in progress and the user
has another tab open that is taking time to generate and
holding the session lock, a condition arises where
multiple ajax calls are "queued" because the long page
is holding the session lock. When this lock is released,
the queued ajax requests complete.  However, as the ajax
requests also lock this can block other requests until they
complete. This patch decreases the frequency of ajax calls
and stops them from holding the session lock.
2019-07-18 14:12:51 +08:00
Peter 0c73410e6c MDL-66174 mod_assign: Remove the strict widths on the annotation menu 2019-07-18 12:56:19 +08:00
Mathew May ebe8a6726a MDL-65788 tool_policy: Move accept_policy JS call into an array 2019-07-18 10:48:00 +08:00
Andrew Nicols cb9494ddcc Merge branch 'MDL-59911-conv_cleanup_check-37' of git://github.com/leonstr/moodle into MOODLE_37_STABLE 2019-07-18 08:25:34 +08:00
AMOS bot 8ac0f287ee Automatically generated installer lang files 2019-07-18 00:09:04 +00:00
Andrew Nicols 6fad97a975 Merge branch 'MDL-66163-37' of git://github.com/marinaglancy/moodle into MOODLE_37_STABLE 2019-07-18 07:45:38 +08:00
Eloy Lafuente (stronk7) 07b75d56ed Merge branch 'MDL-66115_37' of https://github.com/dvdcastro/moodle into MOODLE_37_STABLE 2019-07-17 23:09:39 +02:00
Bas Brands d959768051 MDL-60636 themes: form autocomplete chevron down on mobile 2019-07-17 13:33:31 +02:00
Peter 62566af752 MDL-66021 restore: Additional restore unit tests with async mode 2019-07-17 10:56:45 +08:00
Peter f910e87c12 MDL-66021 backup: Clear course if required before restore 2019-07-17 10:56:45 +08:00
Andrew Nicols 8960fa5c1f Merge branch 'MDL-65538-37' of git://github.com/sarjona/moodle into MOODLE_37_STABLE 2019-07-17 10:56:13 +08:00
Bas Brands 5eb95aca21 MDL-65357 themes: position enrolment icons in course listing 2019-07-17 09:40:29 +08:00
Eloy Lafuente (stronk7) f417dab602 Merge branch 'MDL-66032-MOODLE_37_STABLE_awarded_badges_criteria' of https://github.com/andrewmadden/moodle into MOODLE_37_STABLE 2019-07-17 01:31:54 +02:00
Eloy Lafuente (stronk7) 334e44fb2c Merge branch 'MDL-65908-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-07-17 01:18:27 +02:00
Marina Glancy ccc7e00cc0 MDL-66163 mod_forum: Add component to unittest sql queries
files from other components may exist in the files table
2019-07-16 20:37:15 +03:00
Leon Stringer c4e1a1518c MDL-59911 fileconverter_unoconv: Fix: test PDF fails after upgrade
When generating the PDF of unoconv_test.docx this file's previous conversions
are removed from mdl_file_conversion.  But these may also be removed by
\core_files\task\conversion_cleanup_task in which case an error occurs as
delete() is invoked with a NULL id.  Added check for non-NULL id prior to
invoking delete().
2019-07-16 17:25:23 +01:00
Eloy Lafuente (stronk7) 12f7d66baf Merge branch 'MDL-65555_MOODLE_37_STABLE' of https://github.com/tuanngocnguyen/moodle into MOODLE_37_STABLE 2019-07-16 12:35:08 +02:00
Andrew Nicols 0d7ff46e11 Merge branch 'MDL-65954-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-07-16 15:15:31 +08:00
Andrew Nicols 91a59718cd Merge branch 'MOODLE_37_STABLE_MDL_65517' of https://github.com/yao9394/moodle into MOODLE_37_STABLE 2019-07-16 12:22:05 +08:00
Andrew Nicols bd5f26b20b Merge branch 'MDL-65409-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-07-16 11:36:42 +08:00
Nathan Nguyen 4ffedd3797 MDL-65555 mod_lesson: fix group override backup and restore 2019-07-16 13:01:27 +10:00
Nathan Nguyen c923621ec0 MDL-65555 mod_quiz: fix group override backup and restore 2019-07-16 13:00:51 +10:00
Ryan Wyllie efc45c2976 MDL-65219 message: add message/pendingcontactrequests.php page back
We previously had this page when contact requests were first introduced
and unfortunately we created a bunch of notifications that reference
this URL directly which now won't work because the page has been removed.

I've added it back but set it to redirect to the message/index.php page
and load the contact requests page there.
2019-07-16 09:51:42 +08:00
Damyon Wiese 916c50484c MDL-65078 competencies: fix webservice
The webservice list_course_module_competencies calls a function that does not exist.

Thanks to Marie-Eve Lévesque for reporting this issue.
2019-07-16 09:43:23 +08:00
Andrew Madden 191bcca9e2 MDL-66032 badges: Prevent empty awarded badges criteria being created.
When creating or editing the awarded badges criteria, the select element should be
required to prevent empty criteria from being created. In addition, if there are
already badges created with the empty criteria, there should be not be an exception
thrown when assessing whether the criteria has been completed.
2019-07-16 09:47:37 +10:00
Sara Arjona 4afc6a5711 MDL-65538 competency: fix behat errors with firefox
There is a random behat error when executing the "Go to the competency
course competencies page." scenario: "Moodle exception: A required parameter
(courseid) was missing More information about this error".
It happens because sometimes the form is sent before the JS and it hasn't
the needed parameters defined. So they have been added as hidden to the
form to avoid the error (which I couldn't reproduce manually).
2019-07-15 14:09:04 +02:00
Eloy Lafuente (stronk7) b32637b7e2 Merge branch 'MDL-58026-37' of https://github.com/MartinGauk/moodle into MOODLE_37_STABLE 2019-07-15 13:38:55 +02:00
David Monllaó 6d6322985d MDL-66026 analytics: No notification if not necessary 2019-07-15 14:24:33 +08:00
Mihail Geshoski a84e91d7f3 MDL-66136 assign: Verify presence of resources in online text submission 2019-07-15 12:03:58 +08:00
Mihail Geshoski 629741d93f MDL-66136 assignfeedback_comments: Extend testcase 2019-07-15 12:03:58 +08:00
Jun Pataleta 727a0a97fe MDL-65954 dataformat_pdf: Convert object records to array
* count() doesn't work quite as expected when the record being written
to the PDF is an object. So make sure to convert the record to an array.
* In addition, instead of comparing the total vs the current cell
counter, it would be more reliable to determine whether we're at the
last element of the array by getting the key for the last element and
comparing it with the key for the element that's currently being
processed.
2019-07-15 10:30:29 +08:00
Peter 8340f83ddc MDL-65908 mod_assign: Remove scroll repositioning.
Absolute positioned elements do not require repositioning on scroll as long as
their immediate parent is relatively positioned.
2019-07-15 08:36:54 +08:00
Peter 8a3a133319 MDL-65908 assign: Overflow and positioning updates
Draw all annotation within the drawing canvas instead of the region
2019-07-15 08:36:54 +08:00
Peter e9822e8851 MDL-65908 assign: Revert overflow scroll fix
Revert "MDL-65484 assign: Scrolling overflow CSS"

This reverts commit 5bda066caa.
2019-07-15 08:36:54 +08:00
Mathew May 559a99c793 MDL-65788 tool_policy: Prevent two modals rendering for guests.
With the Guest registration calling policyactions.js the [data-action="view"]
was having two click handlers set on the inital policy modal trgger.
With this commit we state what we want the click event to be set on.
2019-07-14 18:53:35 +08:00
AMOS bot bcdb7e3031 Automatically generated installer lang files 2019-07-14 00:08:50 +00:00
David Castro 7f0d1164f5 MDL-66115 qtype_ddimageortext: Fixing choice deletion.
Summarising responses fails when question choices have been removed.

AMOS BEGIN
CPY [deletedchoice,qtype_match],[deletedchoice,qtype_ddimageortext]
AMOS END

(cherry picked from commit f0265e6db16caa6d13f8bce291e7da91b0eabb53)
2019-07-12 14:35:54 -05:00
sam marshall aa01e0e574 MDL-66132 Search: Behat tests should use simpledb, fix mock count
When searching using mock results (the 'global search expects the
query' step), the result count is not correctly set. As a result, the
page incorrectly reports that there are no results and doesn't
correctly show the first page of multi-page results.

Additionally, some of the core Behat tests can now be moved to use
real searching with the simpledb engine, rather than using mock
results at all. This gives better tests.

Unfortunately it was not possible to move all of the core Behat tests
and deprecate the mock step, because some of the tests are related to
the UI for 'special' features searching by user or group, neither of
which are supported by the simpledb engine.
2019-07-12 17:41:17 +01:00
Damyon Wiese 8070c74ebc MDL-65409 files: Allow location header
Allow incorrect capitals in location header response.
2019-07-12 08:44:54 +08:00
John Yao 93ade38caa MDL-65517 block_timeline: Hide completed course modules in Timeline
When some activities are manually completed by students, some are still showing in students' timeline.
This commit fix that for module assign,chat,choice,feedback,lesson,quiz,scorm and workshop.
2019-07-12 09:17:33 +10:00
Eloy Lafuente (stronk7) 39ef515a64 weekly release 3.7.1+ 2019-07-11 23:33:54 +02:00
Eloy Lafuente (stronk7) 65462b439d NOBUG: Fixed file access permissions 2019-07-11 23:33:54 +02:00
Eloy Lafuente (stronk7) 481b001f25 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-07-11 23:33:52 +02:00
Jun Pataleta 3098122ac1 Merge branch 'MDL-65926-MOODLE_37_STABLE_lowercase_username_sql_query' of https://github.com/andrewmadden/moodle into MOODLE_37_STABLE 2019-07-11 20:58:47 +02:00
Bas Brands f7a92e6a98 MDL-66039 themes: remove duplicate css
* removed duplicate #page { margin-top: 50px };
2019-07-11 14:54:28 +02:00
AMOS bot 00906c109e Automatically generated installer lang files 2019-07-11 00:09:03 +00:00
Eloy Lafuente (stronk7) 177f92e74b Merge branch 'MDL-66114-37-fix' of git://github.com/marinaglancy/moodle into MOODLE_37_STABLE 2019-07-10 12:45:30 +02:00
Andrew Madden ae464fd7b2 MDL-65926 moodlelib: Convert username to lowercase prior to SQL query
Within a very large project, it was found that searching for a user with their username in the user table using a case insensitive
search was inefficient. Instead it is proposed that the username input is made to be lowercase prior to executing a database query
as the username for each user in the database must be lowercase. This allows for a case sensitive query to find the user data.
Essentially we are moving a case insensitive search for a user from SQL into PHP to increase performance.
2019-07-10 19:55:46 +10:00
Marina Glancy 909d02196f MDL-66114 core_calendar: normalise categoryid value 2019-07-10 11:29:00 +02:00
Andrew Nicols 56d381cba3 Merge branch 'MDL-66114-37-2' of git://github.com/marinaglancy/moodle into MOODLE_37_STABLE 2019-07-10 14:29:41 +08:00
Jun Pataleta 49c2095b74 Merge branch 'MDL-66012-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-07-10 12:16:49 +08:00
Simey Lameze 64b39b7f60 MDL-66012 calendar: fix no event message on calendar views
Ahhh Jun. Thanks legend :)
2019-07-10 11:32:53 +08:00
Eloy Lafuente (stronk7) b0e82e7359 Merge branch 'MDL-56835_37-coursetimecreated' of git://github.com/markn86/moodle into MOODLE_37_STABLE 2019-07-10 00:14:59 +02:00
Marina Glancy 520d73b0d6 MDL-66114 core_calendar: events without category 2019-07-09 18:05:29 +02:00
Jun Pataleta 56b3bec2ff Merge branch 'MDL-66081-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-07-09 17:11:05 +08:00
Andrew Nicols f87569ac6a Merge branch 'MDL-64258-37' of https://github.com/HuongNV13/moodle into MOODLE_37_STABLE 2019-07-09 14:50:44 +08:00
Andrew Nicols 7804b75021 Merge branch 'MDL-65965-37-fix' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-07-09 11:00:30 +08:00
Jun Pataleta 571d588002 MDL-65965 behat: Do not fetch grouping IDs for empty grouping idnumbers 2019-07-09 10:49:10 +08:00
Mark Nelson c5fb5d69b1 MDL-56835 report_participation: remove unreachable if condition 2019-07-09 09:14:55 +08:00
Andrew Nicols 54b4d6726b Merge branch 'MDL-65772-37' of git://github.com/vmdef/moodle into MOODLE_37_STABLE 2019-07-09 08:56:33 +08:00
Mark Nelson af281ecdd6 MDL-56835 report_participation: initialise action variables 2019-07-09 08:30:41 +08:00
Mark Nelson d92119979c MDL-56835 report_participation: use course timecreated as minlog 2019-07-09 08:30:38 +08:00
Matt Porritt d6301a6dd3 MDL-56835 report_participation: release session lock 2019-07-09 08:28:50 +08:00
Eloy Lafuente (stronk7) 2308148e23 Merge branch 'MDL-66054-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-07-09 00:57:23 +02:00
Eloy Lafuente (stronk7) 41fc9f1937 Merge branch 'MDL-65965-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-07-09 00:55:09 +02:00
Martin Gauk 96c24a1912 MDL-58026 question: fix regrading in progress attempt
Do not convert autosave steps to true steps when regrading.

Thanks Eric Merrill for providing the unit test code.
2019-07-08 09:35:51 +00:00
AMOS bot f14bcafc5a Automatically generated installer lang files 2019-07-08 00:10:08 +00:00
AMOS bot fdd756f779 Automatically generated installer lang files 2019-07-07 00:08:55 +00:00
Sara Arjona b198428e41 Moodle release 3.7.1 2019-07-05 12:27:23 +02:00
Simey Lameze b9cd69b372 MDL-66081 calendar: fix typo in attribute description 2019-07-05 17:07:58 +08:00
AMOS bot a5f09bca98 Automatically generated installer lang files 2019-07-05 00:09:46 +00:00
Eloy Lafuente (stronk7) 22124a36ca weekly release 3.7+ 2019-07-04 16:51:08 +02:00
Eloy Lafuente (stronk7) 50794f5278 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-07-04 16:51:03 +02:00
Víctor Déniz Falcón 6d4e4bb8ef MDL-65772 cachestore_mongodb: fix the version number of the library 2019-07-04 12:46:04 +01:00
AMOS bot e1cad3f07b Automatically generated installer lang files 2019-07-04 00:08:39 +00:00
Shamim Rezaie 2e4856a81f MDL-61114 mod_assign: Check if the teacher can access the override 2019-07-03 18:05:19 +02:00
Shamim Rezaie 211f6809b9 MDL-61114 mod_assign: assignment overrides to observe group membership 2019-07-03 18:05:19 +02:00
Shamim Rezaie ad75599c7b MDL-61115: mod_lesson: Check if the teacher can access the override 2019-07-03 17:49:58 +02:00
Shamim Rezaie ca908dd42c MDL-61115 mod_lesson: Lesson overrides to observe group membership 2019-07-03 17:49:58 +02:00
Sara Arjona 76129617e5 Merge branch 'MDL-65105-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-07-03 15:05:42 +02:00
Sara Arjona 56f92fa069 Merge branch 'MDL-65958-37-v3' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-07-03 14:53:28 +02:00
Simey Lameze d7815b0a79 MDL-65958 calendar: cover students default event type visibility 2019-07-03 20:41:04 +08:00
Simey Lameze 376a2f64f2 MDL-65958 calendar: students should not see course event type 2019-07-03 20:41:04 +08:00
Simey Lameze 634da01c65 MDL-65958 calendar: add behat to test calendar_adminseesall behaviour 2019-07-03 20:41:04 +08:00
Simey Lameze 8b0bb2389c MDL-65958 calendar: fix adminseesall logic in the event form 2019-07-03 20:41:03 +08:00
Sara Arjona 83b311dcb3 Merge branch 'MDL-64794_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-07-03 11:15:42 +02:00
Huong Nguyen 79ec71c87b MDL-64258 Group: Performance problem on the enrol group members page 2019-07-03 15:29:00 +07:00
Huong Nguyen 79a6ef4c9b MDL-64258 Group: Unit Test for find_users function 2019-07-03 15:28:52 +07:00
Eloy Lafuente (stronk7) 299cdee4bf Merge branch 'MDL-65845_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-07-03 02:25:39 +02:00
Eloy Lafuente (stronk7) 34b451dac4 Merge branch 'MDL-65656-37-2' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-07-03 02:16:54 +02:00
AMOS bot e2ac9903d9 Automatically generated installer lang files 2019-07-03 00:08:46 +00:00
AMOS bot ee22b6faba Automatically generated installer lang files 2019-07-03 00:08:46 +00:00
Eloy Lafuente (stronk7) a6c6690e79 Merge branch 'MDL-63268-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-07-03 00:13:15 +02:00
Sara Arjona acb0617d1b Merge branch 'MDL-64614_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-07-02 21:21:29 +02:00
Luca Bösch 370c8c4a06 MDL-63268 tool_uploadcourse: Keep source course section number. 2019-07-02 19:49:08 +02:00
Eloy Lafuente (stronk7) 4782bf39af Merge branch 'MDL-65707-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-07-02 16:39:49 +02:00
Sara Arjona 39f9832ce5 Merge branch 'MDL-66062_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-07-02 15:16:02 +02:00
Sara Arjona ef0d79745f Merge branch 'MDL-65101_37' of git://github.com/markn86/moodle into MOODLE_37_STABLE 2019-07-02 14:50:22 +02:00
Eloy Lafuente (stronk7) e1b1217749 MDL-66062 travis: Force PHP 7.1.30 to avoid some unit test failures
Make this sticky because current default version (7.1.11)
has a bug with redis-extension outputting information and breaking
tests.
2019-07-02 13:00:41 +02:00
Eloy Lafuente (stronk7) 57886390a6 Merge branch 'MDL-65728-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-07-02 12:14:05 +02:00
Sara Arjona 2a6ee587d3 Merge branch 'MDL-65839_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-07-02 10:42:10 +02:00
Eloy Lafuente (stronk7) 43ab5e777d Merge branch 'MDL-65853_m37' of git://github.com/gjb2048/moodle into MOODLE_37_STABLE 2019-07-02 10:25:36 +02:00
Shamim Rezaie 3f96ad977e MDL-34411 mod_quiz: Check if the teacher can access the override 2019-07-02 08:37:48 +02:00
Shamim Rezaie de068eb91a MDL-34411 groups: copy/paste error in test_groups_user_groups_visible 2019-07-02 08:37:48 +02:00
Shamim Rezaie e6539e7139 MDL-34411 mod_quiz: quiz overrides to observe group membership 2019-07-02 08:37:48 +02:00
Damyon Wiese 9a6c86b23f MDL-64623 glossary: Check the entry id
The entry must match the glossary before you can do any action on it.
2019-07-02 08:37:48 +02:00
Damyon Wiese ec2f7c0fe9 MDL-53689 xmldb: Require a sesskey to load xml
Loading and unloading xml files is not protected from XSS with a sesskey.
2019-07-02 08:37:48 +02:00
Sara Arjona 2077354356 Merge branch 'MDL-66049-37-workshopnamespace' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-07-02 08:29:00 +02:00
Sara Arjona a3bce19260 Merge branch 'MDL-65901-37' of https://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2019-07-02 08:10:27 +02:00
AMOS bot 08943d8121 Automatically generated installer lang files 2019-07-02 00:09:26 +00:00
Eloy Lafuente (stronk7) b053efae5d Merge branch 'MDL-64935-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-07-02 00:06:59 +02:00
Shamim Rezaie 8bb3a1d295 MDL-66054 behat: typo fix 2019-07-02 04:05:39 +10:00
Eloy Lafuente (stronk7) b3bd9df0fd Merge branch 'MDL-64511-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-07-01 18:52:21 +02:00
Sara Arjona 1d5341843f Merge branch 'MDL-65297-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-07-01 18:34:52 +02:00
Sara Arjona 5da74261d3 Merge branch 'MDL-65892-37-inlinereply' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-07-01 15:50:02 +02:00
David Mudrák ee3b7666f2 MDL-66049 workshop: Fix the fully qualified class name
Because of the missing slash, the class 'workshop' was not found in the
current namespace and the cron failed to work.
2019-07-01 14:49:34 +02:00
Sara Arjona 9c96a6fcf7 Merge branch 'MDL-65973-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-07-01 13:13:34 +02:00
Dan Marsden 6ab4eaf7f2 MDL-60347 core: debugsmtp should be a developer only setting. 2019-07-01 12:16:22 +02:00
Sara Arjona 46c4afbeaf Merge branch 'MDL-57884_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-07-01 09:57:48 +02:00
Eloy Lafuente (stronk7) e0e75192e8 MDL-64614 environment: mssql requirement up to 2012 (11.0) 2019-06-30 11:58:04 +02:00
Eloy Lafuente (stronk7) c0078c08df MDL-64614 environment: 3.8 base information
This is a direct copy of the 3.7 branch to have
changes under control easier for next commits.
2019-06-30 11:58:04 +02:00
AMOS bot e2c4f9d374 Automatically generated installer lang files 2019-06-30 00:09:17 +00:00
AMOS bot 1b26a3db64 Automatically generated installer lang files 2019-06-30 00:09:16 +00:00
AMOS bot fa5aa45de4 Automatically generated installer lang files 2019-06-29 00:09:17 +00:00
AMOS bot 9c9ac43919 Automatically generated installer lang files 2019-06-29 00:09:17 +00:00
David Monllaó b214024bda MDL-65845 mod_lesson: Fix wrong pointer to an object
We should be pointing to the array of timecreated values instead.
2019-06-28 21:06:22 +02:00
David Monllaó cd59d03500 MDL-65839 core_analytics: New indicator instances for each analysable 2019-06-28 21:00:25 +02:00
Paul Holden 0db181f9a9 MDL-64511 privacy: encode data URL when loading content.
Previously paths that included ? or # characters would break loading.
2019-06-28 13:16:55 +01:00
Paul Holden 868c037261 MDL-65297 atto_managefiles: improve filename decoding.
Filenames containing # character would previously be missed.
2019-06-28 13:13:49 +01:00
Sara Arjona a1714472d3 Merge branch 'MDL-65506-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-06-28 12:16:29 +02:00
Mark Nelson 7883551c72 MDL-65101 core_message: add Behat test 2019-06-28 18:14:30 +08:00
Mark Nelson bc11df440e MDL-65101 core_message: 'canmessage' should trump 'requirescontract' 2019-06-28 15:38:20 +08:00
AMOS bot 4efaec0a53 Automatically generated installer lang files 2019-06-28 00:09:47 +00:00
Gareth Barnard 0ded67ffd7 MDL-65853 format_base: Labels counted in section activity summary. 2019-06-27 23:36:06 +01:00
Luca Bösch 61923d3bdd MDL-65901 forum: Style advanced search form properly. 2019-06-27 21:58:19 +02:00
Eloy Lafuente (stronk7) 035d608c59 weekly release 3.7+ 2019-06-27 18:54:40 +02:00
Eloy Lafuente (stronk7) d49a5c7826 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-06-27 18:54:38 +02:00
Andrew Nicols 7305ed72ec Merge branch 'MDL-53778_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-06-27 08:36:55 +08:00
Eloy Lafuente (stronk7) 7ab8ebf5b1 MDL-53778 quiz: ensure completion deps are fulfilled by behat
Behat backgrounds and scenarios must observe the new
interdependencies between quiz completion settings.

This commits just applies that to the tests missing it.
2019-06-27 01:12:44 +02:00
Eloy Lafuente (stronk7) c4b9758766 MDL-53778 quiz: ensure completion deps are fulfilled by generator uses
There are some mod_quiz generator issues where the new chain
of dependencies between completion settings was not being observed.

This patch just ensures that the now 3 chained settings are
enabled together (or new quiz options logic will proceed to
disable them).
2019-06-27 01:12:44 +02:00
Eloy Lafuente (stronk7) 679d2d1129 Merge branch 'MDL-66003-37-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-06-26 23:04:27 +02:00
Nicolas Dunand 5cad3e5d46 MDL-63458 core_user: Remove send message if messaging is disabled 2019-06-26 11:30:40 -07:00
Sara Arjona 4faf9ff6c6 Merge branch 'MDL-60088-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-06-26 18:11:17 +02:00
Eloy Lafuente (stronk7) 0a77242e3c Merge branch 'MDL-53778_37' of https://github.com/anieminen/moodle into MOODLE_37_STABLE 2019-06-26 17:50:32 +02:00
Shamim Rezaie 1453ce1208 MDL-65506 forms: get the correct value for advcheckbox fields in js 2019-06-26 20:57:47 +10:00
Eloy Lafuente (stronk7) 798dc31ada Merge branch 'MDL-65249-37-fix' of https://github.com/snake/moodle into MOODLE_37_STABLE 2019-06-26 10:28:36 +02:00
Jake Dallimore 4a2a533fe1 MDL-65249 session: use redis host constant in unit tests 2019-06-26 16:11:05 +08:00
Ilya Tregubov 61373c843d MDL-65249 Session: Throw exception if number of attempts exceeded. 2019-06-26 14:49:23 +08:00
Jake Dallimore 2937760c27 Merge branch 'MDL-60978-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-06-26 13:17:04 +08:00
AMOS bot 03989cb776 Automatically generated installer lang files 2019-06-26 00:09:24 +00:00
Eloy Lafuente (stronk7) a4f78b52f6 Merge branch 'MDL-65181-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-06-26 00:43:50 +02:00
David Mudrák ecc1bd1c73 MDL-66003 lang: Use the updated strings in the tests 2019-06-25 21:30:27 +02:00
Helen Foster 694f33c2f6 MDL-66003 lang: Import fixed English strings (en_fix)
Significant string changes:

* moodleorghubname,core_admin and
  sitemustberegistered,message_airnotifier - 'Moodle.net' changed to
  'Moodle'

* registration_help,core_admin and registermoochtips,core_hub - removed
  erroneous 'access to Moodle.net our course sharing platform'

* trackingtype_help,mod_forum and formnotavailable,core_grading and
  showgrades_help,core and rolewarning_help,core_rating -
  'Administration block' changed to 'Actions menu or admin block',
  'navigation block' changed to 'navigation drawer or block'
2019-06-25 21:30:27 +02:00
David Mudrák d93cdd955b MDL-65892 forum: Fix styling of the inline reply textarea 2019-06-25 14:49:12 +02:00
Arto Nieminen d80d0b4142 MDL-53778 quiz settings: Ensure that disabled checkboxes have value 0 2019-06-25 13:26:29 +03:00
Simey Lameze b73ab4bf04 MDL-65707 calendar: behat scenario to test default event type 2019-06-25 10:23:34 +08:00
Simey Lameze a398df5381 MDL-65707 calendar: set the correct event type on site calendar 2019-06-25 10:23:34 +08:00
AMOS bot b0ff1a1600 Automatically generated installer lang files 2019-06-25 00:09:19 +00:00
Eloy Lafuente (stronk7) 98070f7020 Merge branch 'MDL-64340-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-06-25 00:54:00 +02:00
Bas Brands 40271e858d MDL-64935 theme: prevent activitynavigation link overflowing container 2019-06-24 14:48:53 +02:00
Bas Brands f839aff2b5 MDL-65105 theme_classic: use $dark variable for navbar-dark 2019-06-24 11:43:21 +02:00
Shamim Rezaie 0096c60d46 MDL-65728 tool_customlang: Escape html on the original translation field 2019-06-24 18:27:20 +10:00
Jake Dallimore 65424cea97 Merge branch 'MDL-65893-37' of https://github.com/nicoroeser/moodle into MOODLE_37_STABLE 2019-06-24 11:42:05 +08:00
AMOS bot 863b9081f5 Automatically generated installer lang files 2019-06-24 00:08:17 +00:00
Mathew May 44c178ec4f MDL-60088 travis: add dist:trusty to travis
We are doing this because travis changed its default release to xenial.
So this is a stop gap and we will add xenial support moving forward.
2019-06-23 23:58:51 +08:00
Jun Pataleta e6e99db401 MDL-65965 behat: Map grouping for activity data generator 2019-06-21 15:41:23 +08:00
Jun Pataleta 74c783924f MDL-65965 availability: Behat test for activity grouping restriction 2019-06-21 15:41:23 +08:00
Andrew Nicols 0703eeca7c MDL-60978 travis: Re-enable Redis session tests 2019-06-21 14:36:13 +08:00
Andrew Nicols 866f014372 MDL-60978 session: Run redis tests in isolation 2019-06-21 14:36:13 +08:00
Andrew Nicols 22ad84cb00 MDL-60978 testing: Support ability to run phpunit in isolated process 2019-06-21 14:36:13 +08:00
Shamim Rezaie d56311006a MDL-64340 mod_quiz: not display "add random question" when no permission 2019-06-21 08:53:47 +10:00
Eloy Lafuente (stronk7) 30d4327769 weekly release 3.7+ 2019-06-20 17:43:09 +02:00
Eloy Lafuente (stronk7) d987202dff Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-06-20 17:43:05 +02:00
Juan Leyva 25d288d297 MDL-65973 calendar: Avoid sesskey checks in WS
External function submit_create_update_form should avoid any sesskey checks.
2019-06-20 15:07:43 +02:00
Jake Dallimore aa6b0c6d03 Merge branch 'MDL-65084-m37' of https://github.com/NeillM/moodle into MOODLE_37_STABLE 2019-06-20 09:40:26 +08:00
Jake Dallimore 6f3819a805 Merge branch 'MDL-65883-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-06-20 09:13:02 +08:00
Andrew Nicols 2641b5e31e Merge branch 'MDL-61319-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2019-06-20 08:10:10 +08:00
Eloy Lafuente (stronk7) 35db491a6d Merge branch 'MDL-64975-37' of https://github.com/nicoroeser/moodle into MOODLE_37_STABLE 2019-06-20 00:17:55 +02:00
Eloy Lafuente (stronk7) 27deb31ded Merge branch 'MDL-65910-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-06-19 20:54:36 +02:00
Eloy Lafuente (stronk7) 511e5c933a Merge branch 'MDL-65665-37-2' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-06-19 20:29:38 +02:00
Eloy Lafuente (stronk7) 5574d3431b Merge branch 'MDL-65666-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-06-19 18:38:26 +02:00
Eloy Lafuente (stronk7) ee8c5098c9 Merge branch 'MDL-65806-m37' of https://github.com/sammarshallou/moodle into MOODLE_37_STABLE 2019-06-19 18:27:19 +02:00
Eloy Lafuente (stronk7) 480396103b Merge branch 'MDL-65864_37' of git://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-06-19 18:09:28 +02:00
Eloy Lafuente (stronk7) 4e5ebf89ba Merge branch 'MDL-55821-37' of git://github.com/damyon/moodle into MOODLE_37_STABLE 2019-06-19 18:05:20 +02:00
Neill Magill 015607040a MDL-65084 recent items: Handle deleted courses
The method should not cause errors when a course with activities
that the user has visited no longer exists.

Ensuring that we only get records for courses still in the database
will stop any course not found erros from get_fast_modinfo()

(cherry picked from commit f1d4c355fb25321756cfbed3b38afbe6e91ccdf9)
2019-06-19 09:04:33 +01:00
Neill Magill c58a1e9067 MDL-65084 recent items: Test handling of deleted courses 2019-06-19 09:04:31 +01:00
Simey Lameze eecc04f29c MDL-65883 mod_quiz: replace all hardcoded urls to proper params 2019-06-19 15:27:22 +08:00
Simey Lameze f237e35755 MDL-65883 mod_quiz: change attemptlib_test to use data generators 2019-06-19 15:27:22 +08:00
Simey Lameze bee606d3b1 MDL-65883 mod_quiz: fix quiz navigation buttons href 2019-06-19 15:27:22 +08:00
Jake Dallimore 38b5816722 Merge branch 'MDL-65904-37' of git://github.com/merrill-oakland/moodle into MOODLE_37_STABLE 2019-06-19 14:59:06 +08:00
Tim Hunt 6e5e4cc208 MDL-57884 quiz: autosave should not send the value of submit buttons 2019-06-18 17:47:48 +01:00
Bas Brands 4af9077f26 MDL-61319 themes: prevent using @extend rules for complex classes
* the settings and navigation blocks scss extended .fa which caused
issues with native fontawesome classes like fa-pull-left.
2019-06-18 13:49:37 +02:00
M Kassaei 0b2c17a183 MDL-65840 qtype_ddmarker: coordinates of cirle shape
The coordinates of a circle shape are not allowed to be smaller than its radius.
By default, set the coordinates to be the same as the radius.
2019-06-18 09:45:37 +08:00
Andrew Nicols 2a55bff8f6 Merge branch 'MDL-65469-37_2' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-18 09:16:53 +08:00
Eloy Lafuente (stronk7) e235ef7bd9 MDL-65469 mod_forum: Check for existence before operating 2019-06-18 08:50:32 +08:00
Peter 47dd7dd840 MDL-65469 core: Backported updates from master 2019-06-18 08:40:21 +08:00
AMOS bot 70c75a7a47 Automatically generated installer lang files 2019-06-18 00:08:37 +00:00
Eloy Lafuente (stronk7) a7367b6cf3 Merge branch 'MDL-65869-37' of git://github.com/aanabit/moodle into MOODLE_37_STABLE 2019-06-18 00:14:18 +02:00
Eloy Lafuente (stronk7) ae8dfad361 Merge branch 'MDL-64383-37' of git://github.com/damyon/moodle into MOODLE_37_STABLE 2019-06-17 23:02:53 +02:00
Andrew Nicols a0bdd53e21 Merge branch 'MDL-65469-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-17 15:19:35 +08:00
Andrew Nicols c615b3e96b Merge branch 'MDL-65888-37' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-06-17 10:52:48 +08:00
AMOS bot e3475fd088 Automatically generated installer lang files 2019-06-15 00:08:13 +00:00
Nicolas Roeser e934a351e9 MDL-64975 moodlelib: fix float formatting if decsep is ~ (tilde)
Commit 637da99edb has introduced changes
for removing trailing zeroes from the output of function format_float.
Due to a small omission, the function causes a PHP warning when the
string decsep is set to a tilde character ('~'). This is rarely the
case.

The bug lies in using PHP function preg_replace with a string that
contains external input (in this case, including decsep), but without
escaping it for PCRE processing.

This commit fixes the function to also support a tilde character in
string decsep. It also adds tests for having tilde as decimal separator.

Thanks-To:  Jake Dallimore <jake@moodle.com>
2019-06-14 13:04:37 +02:00
Paul Holden 564753102d MDL-65181 mod_data: show required field indicator for textarea fields. 2019-06-14 09:58:18 +01:00
Nicolas Roeser 91916adde5 MDL-65893 webservice: format site name (handle language tags etc.)
Allow web service clients (like the Moodle App) to benefit from a
formatted (filtered) site name. Select the filtered (localized etc.)
string on server side, before it is sent to the web service client.

For example, this translates a site name which uses language tags in
curly braces when using the filter_multilang2 plugin.

Thanks-To: Juan Leyva <juan@moodle.com>
Thanks-To: Kathrin Osswald <kathrin.osswald@uni-ulm.de>
2019-06-14 10:38:32 +02:00
Amaia Anabitarte 7af3ae4834 MDL-65869 behat: Moving @app behat tests from core to moodlemobileapp
As described in MDL-65869 we are moving @app behat tests to
https://github.com/moodlehq/moodle-local_moodlemobileapp to be easier to maintain
and be sure are working with different mobile versions.
So we are not deprecating tests from core, just removing them because will be
in a different location.
2019-06-14 10:17:17 +02:00
Jun Pataleta fdfd266454 MDL-65910 report_stats: Add stattype query condition for consistency 2019-06-14 13:01:32 +08:00
Mihail Geshoski f3e11eef99 MDL-65665 forum: WS does not respect subscribe on reply user preference 2019-06-14 08:45:59 +08:00
Mihail Geshoski 94c5e0ade7 MDL-65665 forum: Add unit test 2019-06-14 08:45:59 +08:00
Tim Hunt 55929d8a49 MDL-65864 question engine: fix re-saving a new usage
Before this fix, test_repeated_usage_saving_new_usage was failing but
test_repeated_usage_saving_existing_usage was passing. Now the
behaviour is consistent and they both pass.
2019-06-13 18:01:54 +01:00
Eloy Lafuente (stronk7) d0b1204d8e weekly release 3.7+ 2019-06-13 18:15:48 +02:00
Eloy Lafuente (stronk7) 81a3d127b1 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-06-13 18:15:46 +02:00
Shamim Rezaie 4f7eaa8b46 MDL-65666 mod_forum: Highlight unread posts count in the discussion list 2019-06-14 01:26:36 +10:00
Shamim Rezaie 9b6a5a9b24 MDL-65786 mod_forum: mark posts as read when they are read 2019-06-13 23:34:03 +10:00
Shamim Rezaie c3c8dfeb51 MDL-65786 mod_forum: re-adding the unread count to the social format 2019-06-13 23:34:03 +10:00
Shamim Rezaie 07f8abfb30 MDL-65786 mod_forum: pass parameter to str helper when loading strings
We should not concatenate strings. We should make use of the {$a}placeholder instead.
2019-06-13 23:34:03 +10:00
Andrew Nicols 54c6679153 Merge branch 'MDL-65814-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2019-06-13 11:44:15 +08:00
Jun Pataleta 089fbd15cc MDL-65814 block_timeline: Bring back item counts for action events 2019-06-13 11:32:03 +08:00
Jun Pataleta 7132749e18 Merge branch 'MDL-55997-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-13 10:28:56 +08:00
Peter 9ca2c8dc52 MDL-55997 core_reports: modify user stats query to fix duplicate rows 2019-06-13 07:46:22 +08:00
Eloy Lafuente (stronk7) f55a4c094e Merge branch 'MDL-64484-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-06-12 20:08:12 +02:00
Eric Merrill 3a3a212405 MDL-65904 theme: Compile fallback css in the correct order 2019-06-12 13:08:54 -04:00
Paul Holden 0998cf8010 MDL-64484 user: cross-DB compatible profile field ordering. 2019-06-12 17:02:32 +01:00
Jun Pataleta 3766be85b2 Merge branch 'MDL-65803-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-12 13:58:45 +08:00
Andrew Nicols 83273d25b9 Merge branch 'MDL-65703-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-06-12 12:39:05 +08:00
Peter b798b05411 MDL-65803 recentlyaccesseditems: Restrict response to valid courses.
* Additional hooks to cleanup data when a course or module is deleted
* Augmented unit tests to cover the situation when a course is deleted
* Upgrade step to cleanup existing data
2019-06-12 12:16:22 +08:00
Andrew Nicols 7eb50a3753 Merge branch 'MDL-65829_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-06-12 10:33:03 +08:00
Andrew Nicols 4a4b4e28a4 Merge branch 'MDL-64484-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2019-06-12 09:01:21 +08:00
sam marshall 42c31d53c8 MDL-65806 Search: Solr does not find words in italic 2019-06-11 16:42:20 +01:00
Paul Holden ea770fe8c8 MDL-64484 user: show full profile field name in filter element. 2019-06-11 14:25:19 +01:00
David Mudrák 434a580558 MDL-65888 forum: Do not send notifications to unconfirmed users
Under certain conditions, users marked as not confirmed yet may be
returned as forum notification recipients. Such users are considered as
inactive though and the delivery adhoc task cannot be run as these
users, throwing an exception.

The solution is to make sure that fetch_subscribed_users() does not
include unconfirmed users, similarly to what was done for suspended
users and nologin users.

The added unit test also checks for deleted users. But these should
never be returned as subscribed because we consider enrolled users only
and deleted users are filtered out implicitly.
2019-06-11 09:49:59 +02:00
Andrew Nicols 9a7a447722 Merge branch 'MDL-65779-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-11 12:07:58 +08:00
Andrew Nicols 1bf28ecb43 Merge branch 'MDL-65817_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-06-11 11:06:13 +08:00
Andrew Nicols 9c99a5da5c Merge branch 'MDL-65183-MOODLE-37' of https://github.com/kristian-94/moodle into MOODLE_37_STABLE 2019-06-11 11:02:06 +08:00
Jun Pataleta 95008df6d9 Merge branch 'MDL-65336-37' of git://github.com/aanabit/moodle into MOODLE_37_STABLE 2019-06-10 19:37:15 +08:00
Jun Pataleta f499fa90f1 Merge branch 'MDL-55592-37' of git://github.com/damyon/moodle into MOODLE_37_STABLE 2019-06-10 15:25:05 +08:00
Andrew Nicols 015b617739 Merge branch 'm37_MDL-61038_Fix_uuid_extensions_usage_v2' of https://github.com/scara/moodle into MOODLE_37_STABLE 2019-06-10 14:11:07 +08:00
Matteo Scaramuccia 423c1d6c50 MDL-61038 setuplib: Fixed PECL UUID extension support 2019-06-08 22:35:37 +02:00
Amaia Anabitarte c4bee8e510 MDL-65336 core_message: New muted conversation generator and selectors 2019-06-07 10:41:08 +02:00
Amaia Anabitarte 023ea98fc1 MDL-65336 core_message: Behat tests for mute/unmute conversations 2019-06-07 10:41:08 +02:00
Peter f1e0128a43 MDL-65469 mod_forum: Use the formchange checker initializer 2019-06-07 08:49:10 +08:00
Peter 167b85e60c MDL-65469 core: Expose formchecker to initialize current form state 2019-06-07 08:49:10 +08:00
AMOS bot 4b6e850e68 Automatically generated installer lang files 2019-06-07 00:09:47 +00:00
Kristian Ringer e48dd422f9 MDL-65183 block_timeline: escape newline characters 2019-06-07 09:36:24 +10:00
Eloy Lafuente (stronk7) dc8b92e0b2 MDL-65817 behat: switch to forked repo towards php73 compatibility
It seems that https://github.com/instaclick/php-webdriver/pull/91
is being ignored (in fact the repository itself doesn't show much
activity). So we have decided to fork it and apply any fix able
to keep our (non-marionette) runs working.

Hopefully, soon, the new W3C drivers will be supported by our
behat->mink stack... and we'll be able to move to it (from current
JSonwire drivers). So all this will be hostory.
2019-06-06 19:50:44 +02:00
David Monllaó 840d6ba543 MDL-65829 analytics: Accept enrol start time after analysis time 2019-06-06 19:05:51 +02:00
Eloy Lafuente (stronk7) 078699a1a5 weekly release 3.7+ 2019-06-06 16:46:52 +02:00
Eloy Lafuente (stronk7) c0266bdaf6 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-06-06 16:46:50 +02:00
Damyon Wiese 46f7f67db1 MDL-55821 assign: Show assign grade
When marking workflow is enabled and the grade is not released yet,
it would be helpful to show the assignment grade in the grading form.
2019-06-06 14:27:01 +08:00
Damyon Wiese e8b50bbe34 MDL-64383 user: Make username required
Username is a required field, we should indicate this even if it has a help icon.
2019-06-06 13:28:29 +08:00
AMOS bot 33113481b5 Automatically generated installer lang files 2019-06-06 00:08:17 +00:00
Jun Pataleta 8f11f7741a Merge branch 'MDL-65787-37' of git://github.com/sarjona/moodle into MOODLE_37_STABLE 2019-06-05 17:24:18 +08:00
Sara Arjona b31ec4dfbf MDL-65787 badges: fix warning count() with PHP 7.2 2019-06-05 11:03:11 +02:00
Sara Arjona 2b63da7763 Merge branch 'MDL-65777-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-06-05 09:01:00 +02:00
Mihail Geshoski 24bc58278f MDL-65777 assignment: Respect user full name in downloaded submissions 2019-06-05 11:14:51 +08:00
Adrian Greeve b59f56c259 Merge branch 'MDL-65731_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2019-06-05 10:40:41 +08:00
AMOS bot 29e40f3c13 Automatically generated installer lang files 2019-06-05 00:08:19 +00:00
Eloy Lafuente (stronk7) d2707c2d28 Merge branch 'MDL-65689-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-06-04 23:32:20 +02:00
Eloy Lafuente (stronk7) 898befb275 Merge branch 'MDL-65578-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-04 23:30:36 +02:00
Eloy Lafuente (stronk7) 938267b43a Merge branch 'MDL-65576-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-06-04 21:40:00 +02:00
Eloy Lafuente (stronk7) f9f5f5ddc8 Merge branch 'm37_MDL-65686_Fix_Incorrect_Function_Call' of https://github.com/scara/moodle into MOODLE_37_STABLE 2019-06-04 20:04:55 +02:00
Simey Lameze ca66ad24c8 MDL-65703 calendar: do not add course param for site calendar 2019-06-04 19:37:35 +08:00
Andreas Grabs e1f4756dfb MDL-65703 core_calendar: fix user event type filtering logic 2019-06-04 19:37:34 +08:00
Mathew May 12e04336a0 MDL-65658 mod_forum: Update the group image titles 2019-06-04 11:50:37 +02:00
Jun Pataleta 266aa66267 Merge branch 'MDL-65696-MOODLE-37' of https://github.com/kristian-94/moodle into MOODLE_37_STABLE 2019-06-04 16:54:52 +08:00
Peter af098adec2 MDL-65779 mod_forum: Add privatereplies to the backup process 2019-06-04 12:21:15 +08:00
Andrew Nicols 202cfa2987 MDL-65656 analytics: Stop covering memory-intensive tests 2019-06-04 11:18:49 +08:00
Andrew Nicols bafa907941 MDL-65656 core: Update composer.json for new PHPUnit version 2019-06-04 11:18:49 +08:00
AMOS bot f5131809c8 Automatically generated installer lang files 2019-06-04 00:08:14 +00:00
Eloy Lafuente (stronk7) 37c30f2249 Merge branch 'MDL-63240-37' of https://github.com/Kathrin84/moodle into MOODLE_37_STABLE 2019-06-03 17:57:49 +02:00
Eloy Lafuente (stronk7) 110a3639c3 Merge branch 'MDL-65660-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-06-03 17:51:43 +02:00
Eloy Lafuente (stronk7) 7631b43d33 Merge branch 'MDL-65675-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-06-03 17:37:21 +02:00
Sara Arjona a51f9bd003 Merge branch 'MDL-65658' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-06-03 12:33:28 +02:00
AMOS bot e998b14686 Automatically generated installer lang files 2019-06-03 00:08:17 +00:00
Kristian Ringer 5ed8d694ee MDL-65696 assign: Fix width of editpdf comments 2019-06-03 09:29:28 +10:00
Andrew Nicols f0782cc57b MDL-65578 forum: Hide action menu where no actions exist 2019-05-31 12:43:52 +08:00
Mathew May 33b74df149 MDL-65658 mod_forum: Group images links and titles groups
After a change in Moodle 3.6 some links & titles went missing.
Here I am adding them back & incresing the output image to 100x100px
2019-05-31 08:17:59 +08:00
Andrew Nicols 24e0b238d3 MDL-65576 behat: Reset Selenium driver between scorm scenarios 2019-05-31 08:09:00 +08:00
Peter dfddaa8ab6 MDL-65660 mod_forum: Allow guest users to view post buttons and links
For a self enrolment enabled course allow guest users to see the add
discussion and reply buttons
2019-05-31 07:07:13 +08:00
Eloy Lafuente (stronk7) 57b83a4f41 MDL-64794 tcpdf: Bump to tcpdf 6.2.26 2019-05-30 23:48:14 +02:00
Matteo Scaramuccia c9be953f05 MDL-65686 setuplib: Fix missing round brackets 2019-05-30 22:42:21 +02:00
Eloy Lafuente (stronk7) 794391b978 weekly release 3.7+ 2019-05-30 12:18:38 +02:00
Eloy Lafuente (stronk7) a7df733250 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2019-05-30 12:18:36 +02:00
Tim Hunt 15d5c9a276 MDL-65731 quiz manual grading: fix ambiguous order by idnumber 2019-05-29 16:55:01 +01:00
Kathrin Osswald ec60f63f59 MDL-63240 theme Boost: Removed z-indexes for border styling in navdrawer 2019-05-29 17:52:36 +02:00
Marina Glancy a024a024e8 MDL-65726 core_roles: allow to create roles in install.php 2019-05-29 10:47:36 +02:00
Damyon Wiese 09304bcbff MDL-55592 lti: Forget the key and secret
When the "Enter your consumer key and shared secret" form is displayed,
it should not contain the same values it had the last time it was opened.
2019-05-29 13:59:38 +08:00
Adrian Greeve 53ef327e54 Merge branch 'MDL-57729-37' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2019-05-29 11:40:48 +08:00
Adrian Greeve 685a71917b Merge branch 'MDL-65726-37' of git://github.com/marinaglancy/moodle into MOODLE_37_STABLE 2019-05-29 11:07:42 +08:00
Mihail Geshoski 04288af505 MDL-57729 enrol_lti: Escape the property values of the xpath elements 2019-05-29 09:56:52 +08:00
Jake Dallimore 4ac6149680 Merge branch 'MDL-65326-MOODLE_37_STABLE' of https://github.com/dmitriim/moodle into MOODLE_37_STABLE 2019-05-29 09:29:44 +08:00
AMOS bot 308046f1bc Automatically generated installer lang files 2019-05-29 00:09:19 +00:00
Marina Glancy d6c2bf620c MDL-65726 role: do not fail unittest if plugins create their roles 2019-05-28 19:08:29 +02:00
Adrian Greeve 8869cf8cd9 Merge branch 'MDL-65705-37' of git://github.com/sarjona/moodle into MOODLE_37_STABLE 2019-05-28 16:28:50 +08:00
Sara Arjona b32974f12a MDL-65705 badges: fix issued date for external badges
The preg_match('~^[1-9][0-9]*$~', x) calls have been replaced to
is_numeric(x).
2019-05-28 09:26:00 +02:00
Ryan Wyllie 48b3e4e9b2 MDL-65657 message: reduce message poll timer for behat tests 2019-05-28 14:06:05 +08:00
Jun Pataleta 4996f75a3b Merge branch 'MDL-65697-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-05-28 13:31:21 +08:00
Jake Dallimore bf2cecc440 Merge branch 'MDL-65692-37' of git://github.com/abgreeve/moodle into MOODLE_37_STABLE 2019-05-28 13:27:01 +08:00
Dmitrii Metelkin ec920f7901 MDL-65326 backup: check caps exist before assigning 2019-05-28 11:17:24 +10:00
Jun Pataleta 1131af4409 Merge branch 'MDL-65606-37' of https://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-05-27 16:27:30 +08:00
Jake Dallimore 46d8ffcefa Merge branch 'MDL-64330-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-05-27 15:22:57 +08:00
Andrew Nicols e2ea9b4c09 MDL-64330 course: Correct course test assumptions 2019-05-27 15:08:25 +08:00
Adrian Greeve 523efc4cd0 Merge branch 'MDL-65699-37' of http://github.com/dravek/moodle into MOODLE_37_STABLE 2019-05-27 14:53:36 +08:00
Andrew Nicols 3f853115e9 Merge branch 'MDL-65708-37' of git://github.com/Chocolate-lightning/moodle into MOODLE_37_STABLE 2019-05-27 14:46:09 +08:00
Mathew May 8a8a02c903 MDL-65606 mod_data: Add approvalstatusclass to template 2019-05-27 13:39:36 +08:00
Ryan Wyllie 946533c623 MDL-65657 message: revert polling timeout back to old algorithm 2019-05-27 13:29:02 +08:00
Mathew May 1f686d7fdf MDL-65708 output: Get a base config from Boost
As a part of the removal of bootstrapbase & clean
I removed some logic that got the base config of bootstrapbase,
this should of been changed to get boosts config.
See: e00f1c663c
2019-05-27 13:21:24 +08:00
Andrew Nicols 4e9e994da4 MDL-65675 forum: Remove duplicate Re in subjects 2019-05-27 12:22:16 +08:00
Adrian Greeve 3ce4575dc0 Merge branch 'MDL-64523-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-05-27 10:49:22 +08:00
David Monllaó 88dfc54de9 MDL-65680 analytics: Fix random failure on slow test environments 2019-05-27 09:42:41 +08:00
AMOS bot d855dcd29e Automatically generated installer lang files 2019-05-25 00:08:34 +00:00
AMOS bot 5d4bf77a16 Automatically generated installer lang files 2019-05-25 00:08:33 +00:00
Shamim Rezaie fc00a6641c MDL-65689 task: fix typo in help string 2019-05-25 05:19:40 +10:00
Shamim Rezaie cee73270c7 MDL-64523 core_access: replace .delegate with .on
As of jQuery 3.0, .delegate() has been deprecated. It was superseded by
the .on() method since jQuery 1.7, so its use was already discouraged.
2019-05-25 04:27:54 +10:00
Shamim Rezaie 245de290f7 MDL-64523 core_access: Fix js racing issue when overriding permissions 2019-05-25 04:27:53 +10:00
Shamim Rezaie 1a6160df3c MDL-64523 core_access: Improve the title of the delete role links 2019-05-25 04:27:53 +10:00
Sara Arjona 2a3df3d55c Merge branch 'MDL-65060-37' of git://github.com/aanabit/moodle into MOODLE_37_STABLE 2019-05-24 12:35:25 +02:00
David Matamoros c227fc61f1 MDL-65699 core_calendar: Check string exists for event types 2019-05-24 12:20:59 +02:00
Amaia Anabitarte 38a9ba9bcd MDL-65060 core_message: Delete messages behat test 2019-05-24 12:15:44 +02:00
Simey Lameze a4e309709d MDL-65697 qtype_missingtype: include missing class 2019-05-24 07:02:10 +08:00
Eloy Lafuente (stronk7) e39f3b7db2 weekly release 3.7+ 2019-05-23 20:35:31 +02:00
Amaia Anabitarte 2a64720ac8 MDL-65060 core_message: Group message data generator 2019-05-23 15:31:19 +02:00
Eloy Lafuente (stronk7) cf0307a529 Merge branch 'MDL-65695-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2019-05-23 10:50:36 +02:00
Eloy Lafuente (stronk7) c4758ab813 Merge branch 'MDL-65694-37-gradeclassnotfound' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-05-23 10:33:26 +02:00
Andrew Nicols d2c91281db MDL-65695 forum: Bump digest time to next day if in past 2019-05-23 15:06:23 +08:00
Adrian Greeve 9a88b8ec35 MDL-65692 backup: Default settings set on install and upgrade.
Asynchronous backup settings are now filled out with the defaults
on installation and upgrade.
2019-05-23 14:54:19 +08:00
David Mudrák 7a2beab44e MDL-65694 grade: Fix missing gradelib library
In the be8f453b74 the gradelib loading was removed by mistake. So
the library may not be loaded and executing the task may end with
the exception - class 'grade_grade' not found.
2019-05-23 07:48:54 +02:00
Tim Hunt a586240cc0 MDL-55197 filter_multilang: handle 'en' as parent lang better 2019-05-23 11:58:58 +08:00
Tim Hunt d2680dbb27 MDL-55197 filter_multilang: move preg_callback fn into class 2019-05-23 11:58:58 +08:00
Andrew Nicols c5b884bd51 Merge branch 'MDL-59650-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2019-05-23 10:29:00 +08:00
Adrian Greeve 5d5313537b Merge branch 'MDL-65549_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-05-23 10:10:25 +08:00
Adrian Greeve 5e6bc1b0f3 Merge branch 'MDL-65634_37' of git://github.com/dmonllao/moodle into MOODLE_37_STABLE 2019-05-23 09:54:47 +08:00
Andrew Nicols 65d4f096db Merge branch 'MDL-65654-37' of https://github.com/danielneis/moodle into MOODLE_37_STABLE 2019-05-23 09:49:20 +08:00
Adrian Greeve cb69e26b15 Merge branch 'MDL-64530_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-05-23 09:23:01 +08:00
Simey Lameze f25a7d2ac7 MDL-59650 core_calendar: remove limit from calendar UI 2019-05-23 08:40:00 +08:00
Simey Lameze de760475cf MDL-59650 core_calendar: remove limit from event exporter 2019-05-23 08:40:00 +08:00
Amaia Anabitarte a3824e559b MDL-65060 core_message: Group_message_message_content selector 2019-05-22 18:56:27 +02:00
Ryan Wyllie 67b64f85e9 MDL-65060 core_message: add render buffer to conversations
Change the conversation logic to render using a buffer so that we can
immediately save state. The render patches are based on the state so
the UI will always reach eventual consistency with the state since the
patches are processed in order.
2019-05-22 18:56:27 +02:00
Sara Arjona ac11f60853 Merge branch 'MDL-65661-37' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2019-05-22 14:57:56 +02:00
Tim Hunt 09558248e8 MDL-65636 filter_multilang: add some basic unit tests
This commit includes suggestions from Jun Pataleta on how to improve the
unit tests.
2019-05-22 19:36:55 +08:00
Peter d186ba2f81 MDL-65661 block_myoverview: Truncate category name 2019-05-22 19:34:54 +08:00
Peter 7ee550a943 MDL-65661 core_course: Truncate long course names 2019-05-22 19:34:54 +08:00
David Monllaó e260354fc9 MDL-65067 tool_analytics: Limit update_end_date to format_weeks 2019-05-22 16:31:03 +08:00
Didier 'OdyX' Raboud cd9c54c93c MDL-65067 analytics: Strengthen format_weeks detection
The public function get_section_dates($section, $startdate = false) is
only defined in format_weeks, not in format_base.

As other formats can (and format_topcoll has) declare a different
get_section_dates public method, merely checking that it exists is not
sufficient to guarantee that it can be called with just a section object.

Check that the format either is, or is a subclass of format_weeks.
2019-05-22 16:30:52 +08:00
Paul Holden 2cd4e5f8dc MDL-64784 core: update tablelib tests for explicit sort direction. 2019-05-22 14:49:41 +08:00
Paul Holden 8978731b82 MDL-64784 core: consistent column sort direction in flexible_table. 2019-05-22 14:49:28 +08:00
Andrew Nicols 5c06a1935b Merge branch 'MDL-65590-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-05-22 13:52:34 +08:00
Jun Pataleta c04e89b086 Merge branch 'MDL-65591-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-05-22 11:06:39 +08:00
Andrew Nicols 4909257b07 Merge branch 'MDL-65630-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-05-22 09:42:38 +08:00
Daniel Neis Araujo 695675483f MDL-65654 tool_uploaduser: Fix undefined variable warning 2019-05-21 14:02:03 -03:00
David Monllaó c3217a6b0d MDL-65549 tool_analytics: Reduce the context name length in models_view 2019-05-21 17:29:23 +02:00
David Monllaó 21527bf096 MDL-65634 analytics: Discard late and early student enrolments 2019-05-21 17:24:17 +02:00
Sara Arjona 8178cf1bb9 Merge branch 'MDL-65605-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2019-05-21 13:47:39 +02:00
Jun Pataleta bc4f56abc3 Merge branch 'MDL-65274-37' of git://github.com/jleyva/moodle into MOODLE_37_STABLE 2019-05-21 18:49:25 +08:00
Víctor Déniz Falcón 0864ebc14c MDL-60407 report_insights: Fix redirect when action on last prediction
When an actions is taken on the last prediction, the predictions
list page is reloaded.
2019-05-21 18:45:42 +08:00
Adrian Greeve 31354cc381 Merge branch 'MDL-65572-37' of git://github.com/damyon/moodle into MOODLE_37_STABLE 2019-05-21 15:20:30 +08:00
Andrew Nicols 422a34a6f5 Merge branch 'MDL-65644_37' of git://github.com/stronk7/moodle into MOODLE_37_STABLE 2019-05-21 12:51:49 +08:00
Shamim Rezaie d16540aa88 MDL-65590 tool_customlang: Escape html on the standard text field 2019-05-21 14:21:04 +10:00
Adrian Greeve d3a76147e0 Merge branch 'MDL-65655-37-forumcroninactiveusers' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2019-05-21 11:39:58 +08:00
Eloy Lafuente (stronk7) c48f2c90cc MDL-64530 travis: Enabble PHP 7.3 and redis cache
This commit performs a number of changes:

- Enables PHP 7.3, replacing PHP 7.2 (max/min approach).
- Enables back the redis service
- Configures redis cache store tests to be run.
- Disables redis session tests for PHP 7.2 and up (MDL-60978)
2019-05-21 01:28:23 +02:00
Eloy Lafuente (stronk7) 1f2cde345a MDL-65644 upgrade: add 3.7.0 separation line to all upgrade scripts 2019-05-20 19:36:01 +02:00
Shamim Rezaie 171a83f79b MDL-65591 tool_customlang: Re-adding the save buttons at the bottom 2019-05-21 02:21:24 +10:00
Juan Leyva a137762fec MDL-65274 mod_quiz: Do not return a translated string
We should be returning proper error codes and the translated string can be part of the debug information.
2019-05-20 15:55:18 +02:00
Shamim Rezaie b52ceb2972 MDL-65630 mod_quiz: Allow redo within an attempt with random questions 2019-05-20 23:50:21 +10:00
Shamim Rezaie 400239c7c5 MDL-65630 mod_quiz: Move logging in to the start of tests
The background is for set up, the scenario is for the test. Logging in
to start the test is the start of the test and the end of the background
itself.
2019-05-20 23:50:20 +10:00
Shamim Rezaie 159f904af5 MDL-65605 core_question: Fix the issue when get_draft_files returns nul 2019-05-20 23:49:13 +10:00
Shamim Rezaie a01edef5be MDL-65605 mod_lesson: Fix the issue when get_draft_files returns null 2019-05-20 23:49:13 +10:00
Damyon Wiese cfa7d2653c MDL-65572 messaging: Loginas upgrade check
When using login as, we also need to check if there are legacy messages that
need updating and set the user preference if required.
2019-05-20 09:15:13 +08:00
21077 changed files with 867883 additions and 1726791 deletions
+88
View File
@@ -0,0 +1,88 @@
# 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/
cache/stores/mongodb/MongoDB/
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/
lib/php-jwt/
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/
+47 -82
View File
@@ -1,38 +1,51 @@
{
'plugins': [
'@babel',
'promise',
'jsdoc'
],
'extends': [
'eslint:recommended',
'plugin:promise/recommended'
],
'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': {
'M': true,
'Y': true
},
// Warn about unused eslint-disable statements.
'reportUnusedDisableDirectives': true,
'rules': {
// See http://eslint.org/docs/rules/ for all rules and explanations of all
// rules.
// === Possible Errors ===
'comma-dangle': 'off',
'no-compare-neg-zero': 'error',
'no-cond-assign': 'error',
'no-console': 'error',
'no-constant-condition': 'error',
'no-control-regex': 'error',
'no-debugger': 'error',
'no-dupe-args': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-empty': 'warn',
'no-empty-character-class': 'error',
'no-ex-assign': 'error',
'no-extra-boolean-cast': 'error',
'no-extra-parens': 'off',
'no-extra-semi': 'error',
'no-func-assign': 'error',
'no-inner-declarations': 'error',
'no-invalid-regexp': 'error',
'no-irregular-whitespace': 'error',
'no-obj-calls': 'error',
'no-prototype-builtins': 'off',
'no-regex-spaces': 'error',
'no-sparse-arrays': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'warn',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'use-isnan': 'error',
'valid-jsdoc': ['warn', { 'requireReturn': false, 'requireParamDescription': false, 'requireReturnDescription': false }],
'valid-typeof': 'error',
// === Best Practices ===
// (these mostly match our jshint config)
@@ -44,12 +57,15 @@
'dot-notation': 'warn',
'no-alert': 'warn',
'no-caller': 'error',
'no-case-declarations': 'error',
'no-div-regex': 'error',
'no-empty-pattern': 'error',
'no-empty-function': 'warn',
'no-eq-null': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'warn',
'no-fallthrough': 'error',
'no-floating-decimal': 'warn',
'no-global-assign': 'warn',
'no-implied-eval': 'error',
@@ -61,22 +77,27 @@
'no-multi-str': 'error',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-octal': 'error',
'no-octal-escape': 'error',
'no-proto': 'error',
'no-redeclare': 'warn',
'no-restricted-globals': ['error', { 'name': 'Notification' }],
'no-return-assign': 'error',
'no-script-url': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-sequences': 'warn',
'no-throw-literal': 'warn',
'no-unmodified-loop-condition': 'error',
'no-unused-expressions': 'error',
'no-unused-labels': 'error',
'no-useless-call': 'warn',
'no-useless-escape': 'warn',
'no-with': 'error',
'wrap-iife': ['error', 'any'],
// === Variables ===
'no-delete-var': 'error',
'no-undef': 'error',
'no-undef-init': 'error',
'no-unused-vars': ['error', { 'caughtErrors': 'none' }],
@@ -109,6 +130,8 @@
'max-statements-per-line': ['warn', { max: 2 }],
'new-cap': ['warn', { 'properties': false }],
'new-parens': 'warn',
'newline-after-var': 'off',
'newline-before-return': 'off',
'newline-per-chained-call': 'off',
'no-array-constructor': 'off',
'no-bitwise': 'error',
@@ -116,6 +139,7 @@
'no-inline-comments': 'off',
'no-lonely-if': 'off',
'no-mixed-operators': 'off',
'no-mixed-spaces-and-tabs': 'error',
'no-multiple-empty-lines': 'warn',
'no-negated-condition': 'off',
'no-nested-ternary': 'warn',
@@ -137,6 +161,7 @@
'padded-blocks': 'off',
'quote-props': ['warn', 'as-needed', {'unnecessary': false, 'keywords': true, 'numbers': true}],
'quotes': 'off',
'require-jsdoc': 'warn',
'semi': 'error',
'semi-spacing': ['warn', {'before': false, 'after': true}],
'sort-vars': 'off',
@@ -149,100 +174,40 @@
'unicode-bom': 'error',
'wrap-regex': 'off',
// === Promises (override plugin:promise/recommended) ===
// === Promises ===
'promise/always-return': 'warn',
'promise/no-return-wrap': 'warn',
'promise/param-names': 'warn',
'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail']}],
'promise/no-native': 'warn',
'promise/no-promise-in-callback': 'warn',
'promise/no-callback-in-promise': 'warn',
'promise/avoid-new': 'warn',
// === Deprecations ===
"no-restricted-properties": ['warn', {
'object': 'M',
'property': 'str',
'message': 'Use "core/str" module or M.util.get_string()'
'message': 'Use AMD module "core/str" or M.util.get_string()'
}],
},
overrides: [
{
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", "Gruntfile.js"],
// Check AMD with some slightly stricter rules.
rules: {
'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',
'@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-unused-vars': 'error',
'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,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');
-124
View File
@@ -1,124 +0,0 @@
name: Core
on:
push:
branches-ignore:
- master
- MOODLE_[0-9]+_STABLE
tags-ignore:
- v[0-9]+.[0-9]+.[0-9]+*
workflow_dispatch:
inputs:
phpunit_extra_options:
description: Additional options to apply to PHPUnit
required: false
default: ''
env:
php: 8.2
jobs:
Grunt:
runs-on: ubuntu-22.04
steps:
- name: Checking out code
uses: actions/checkout@v4
- name: Configuring node & npm
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Installing node stuff
run: npm 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:
# MySQL builds always run with the lowest PHP supported version.
- os: ubuntu-22.04
php: 8.0
extensions:
db: mysqli
# PostgreSQL builds always run with the highest PHP supported version.
- os: ubuntu-22.04
php: 8.2
db: pgsql
steps:
- name: Setting up DB mysql
if: ${{ matrix.db == 'mysqli' }}
uses: moodlehq/mysql-action@v1
with:
collation server: utf8mb4_bin
mysql version: 8.0
mysql database: test
mysql user: test
mysql password: test
use tmpfs: true
tmpfs size: '1024M'
extra conf: --skip-log-bin
- name: Setting up DB pgsql
if: ${{ matrix.db == 'pgsql' }}
uses: m4nu56/postgresql-action@v1
with:
postgresql version: 13
postgresql 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@v4
- 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 ${{ inputs.phpunit_extra_options }}
-149
View File
@@ -1,149 +0,0 @@
name: Windows Testing
on:
workflow_dispatch:
inputs:
phpunit_extra_options:
description: Additional options to apply to PHPUnit
required: false
default: ''
env:
php: 8.2
jobs:
Grunt:
runs-on: windows-latest
steps:
- name: Set git to use LF
run: |
git config --global core.autocrlf false
git config --global core.eol lf
- name: Checking out code
uses: actions/checkout@v4
- name: Configuring node & npm
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Installing node stuff
run: npm ci
- name: Running grunt
run: npx grunt
- name: Looking for uncommitted changes
# Add all files to the git index and then run diff --cached to see all changes.
# This ensures that we get the status of all files, including new files.
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
run: |
git add .
git reset -- npm-shrinkwrap.json
git diff --cached --exit-code
PHPUnit:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
php: 8.2
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
# this is the place to enable them.
# db: mysqli
db: pgsql
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
- os: windows-latest
php: 8.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@v4
# Needs to be done after php is available, git configured and Moodle checkout has happened.
- name: Setting up moodle-exttests service
run: |
git clone https://github.com/moodlehq/moodle-exttests.git
nssm install php-built-in C:\tools\php\php.exe -S localhost:8080 -t D:\a\moodle\moodle\moodle-exttests
nssm start php-built-in
- name: Setting up redis service
run: |
choco install redis-64 --version 3.0.503 --no-progress
nssm install redis redis-server
nssm start redis
- name: Setting up PHPUnit
env:
dbtype: ${{ matrix.db }}
shell: bash
run: |
echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
cp .github/workflows/config-template.php config.php
mkdir ../moodledata
php admin/tool/phpunit/cli/init.php --no-composer-self-update
- name: Running PHPUnit tests
env:
dbtype: ${{ matrix.db }}
phpunit_options: ${{ secrets.phpunit_options }}
run: vendor/bin/phpunit $phpunit_options ${{ inputs.phpunit_extra_options }}
+1 -12
View File
@@ -20,12 +20,12 @@
*~
#
/config.php
/lib/editor/tinymce/extra/tools/temp/
/tags
/TAGS
/cscope.*
/.patches/
/.idea/
.phpstorm.*
/nbproject/
CVS
.DS_Store
@@ -33,7 +33,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
@@ -45,13 +44,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);
}
}
}
};
};
-394
View File
@@ -1,394 +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;
};
/**
* Get the latest tag in a remote GitHub repository.
*
* @param {string} url The remote repository.
* @returns {Array}
*/
const getRepositoryTags = async(url) => {
const gtr = require('git-tags-remote');
try {
const tags = await gtr.get(url);
if (tags !== undefined) {
return tags;
}
} catch (error) {
return [];
}
return [];
};
/**
* Get the list of thirdparty libraries that could be upgraded.
*
* @returns {Array}
*/
const getThirdPartyLibsUpgradable = async() => {
const libraries = getThirdPartyLibsData().filter((library) => !!library.repository);
const upgradableLibraries = [];
const versionCompare = (a, b) => {
if (a === b) {
return 0;
}
const aParts = a.split('.');
const bParts = b.split('.');
for (let i = 0; i < Math.min(aParts.length, bParts.length); i++) {
const aPart = parseInt(aParts[i], 10);
const bPart = parseInt(bParts[i], 10);
if (aPart > bPart) {
// 1.1.0 > 1.0.9
return 1;
} else if (aPart < bPart) {
// 1.0.9 < 1.1.0
return -1;
} else {
// Same version.
continue;
}
}
if (aParts.length > bParts.length) {
// 1.0.1 > 1.0
return 1;
}
// 1.0 < 1.0.1
return -1;
};
for (let library of libraries) {
upgradableLibraries.push(
getRepositoryTags(library.repository).then((tagMap) => {
library.version = library.version.replace(/^v/, '');
const currentVersion = library.version.replace(/moodle-/, '');
const currentMajorVersion = library.version.split('.')[0];
const tags = [...tagMap]
.map((tagData) => tagData[0])
.filter((tag) => !tag.match(/(alpha|beta|rc)/))
.map((tag) => tag.replace(/^v/, ''))
.sort((a, b) => versionCompare(b, a));
if (!tags.length) {
library.warning = "Unable to find any comparable tags.";
return library;
}
library.latestVersion = tags[0];
tags.some((tag) => {
if (!tag) {
return false;
}
// See if the version part matches.
const majorVersion = tag.split('.')[0];
if (majorVersion === currentMajorVersion) {
library.latestSameMajorVersion = tag;
return true;
}
return false;
});
if (versionCompare(currentVersion, library.latestVersion) > 0) {
// Moodle somehow has a newer version than the latest version.
library.warning = `Newer version found: ${currentVersion} > ${library.latestVersion} for ${library.name}`;
return library;
}
if (library.version !== library.latestVersion) {
// Delete version and add it again at the end of the array. That way, current and new will stay closer.
delete library.version;
library.version = currentVersion;
return library;
}
return null;
})
);
}
return (await Promise.all(upgradableLibraries)).filter((library) => !!library);
};
/**
* Get the list of thirdparty libraries.
*
* @returns {Array}
*/
const getThirdPartyLibsData = () => {
const DOMParser = require('@xmldom/xmldom').DOMParser;
const fs = require('fs');
const xpath = require('xpath');
const path = require('path');
const libraryList = [];
const libraryFields = [
'location',
'name',
'version',
'repository',
];
const thirdpartyfiles = getThirdPartyLibsList(fs.realpathSync('./'));
thirdpartyfiles.forEach(function(libraryPath) {
const xmlContent = fs.readFileSync(libraryPath, 'utf8');
const doc = new DOMParser().parseFromString(xmlContent);
const libraries = xpath.select("/libraries/library", doc);
for (const library of libraries) {
const libraryData = [];
for (const field of libraryFields) {
libraryData[field] = xpath.select(`${field}/text()`, library)?.toString();
}
libraryData.location = path.join(path.dirname(libraryPath), libraryData.location);
libraryList.push(libraryData);
}
});
return libraryList.sort((a, b) => a.location.localeCompare(b.location));
};
module.exports = {
fetchComponentData,
getAmdSrcGlobList,
getComponentFromPath,
getComponentPaths,
getOwningComponentDirectory,
getYuiSrcGlobList,
getThirdPartyLibsList,
getThirdPartyPaths,
getThirdPartyLibsUpgradable,
};
-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://moodledev.io](https://moodledev.io) 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://moodledev.io",
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;
};
-215
View File
@@ -1,215 +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 minification task
* (e.g. build/file.min.js). This function will be passed to
* the rename property of files array when building dynamically:
* http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
*
* @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-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 => {
grunt.log.debug(`Item resolved. Kicking off next one.`);
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(options) => {
return new Promise(resolve => {
queue.push(resolve);
startQueue();
return options;
});
},
// When an item in the queue completes, start the next item in the queue.
generateBundle: (options, bundle) => {
grunt.log.debug(`Finished output phase for ${Object.keys(bundle).join(', ')}`);
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')
],
presets: [
['@babel/preset-env', {
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);
};
-52
View File
@@ -1,52 +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 path = require('path');
grunt.registerTask('jsdoc', 'Generate JavaScript documentation using jsdoc', function() {
const done = this.async();
const configuration = path.resolve('.grunt/jsdoc/jsdoc.conf.js');
grunt.util.spawn({
cmd: 'jsdoc',
args: [
'--configure',
configuration,
]
}, function(error, result, code) {
if (result.stdout) {
grunt.log.write(result.stdout);
}
if (result.stderr) {
grunt.log.error(result.stderr);
}
if (error) {
grunt.fail.fatal(`JSDoc failed with error code ${code}`);
} else {
grunt.log.write('JSDoc completed successfully'.green);
}
done();
});
});
};
-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');
};
-187
View File
@@ -1,187 +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: {
quietDeprecationWarnings: true,
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: {
quietDeprecationWarnings: true,
customSyntax: 'postcss-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']
},
},
});
};
-42
View File
@@ -1,42 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/* jshint node: true, browser: false */
/* eslint-env node */
/**
* @copyright 2023 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = grunt => {
/**
* Generate upgradable third-party libraries (utilising thirdpartylibs.xml data)
*/
grunt.registerTask('upgradablelibs', 'Generate upgradable third-party libraries', async function() {
const done = this.async();
const path = require('path');
const ComponentList = require(path.join(process.cwd(), '.grunt', 'components.js'));
// An array of third party libraries that have a newer version in their repositories.
const thirdPartyLibs = await ComponentList.getThirdPartyLibsUpgradable({progress: true});
for (let library of thirdPartyLibs) {
grunt.log.ok(JSON.stringify(Object.assign({}, library), null, 4));
}
done();
});
};
-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;
};
+1 -1
View File
@@ -1 +1 @@
lts/iron
v8.16.1
+89
View File
@@ -0,0 +1,89 @@
# Generated by "grunt ignorefiles"
**/yui/build/*
theme/boost/style/moodle.css
theme/classic/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/
cache/stores/mongodb/MongoDB/
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/
lib/php-jwt/
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/
+4 -16
View File
@@ -1,14 +1,9 @@
{
"customSyntax": "postcss-scss",
"plugins": [
"stylelint-csstree-validator"
],
"rules": {
"csstree/validator": {
"syntaxExtensions": [
"sass"
]
},
"csstree/validator": true,
"at-rule-empty-line-before": [ "always",
{"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
],
@@ -50,7 +45,7 @@
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
"function-url-scheme-disallowed-list": ["data"],
"function-url-scheme-blacklist": ["data"],
"function-whitespace-after": "always",
"indentation": 4,
"keyframe-declaration-no-important": true,
@@ -89,19 +84,12 @@
"selector-type-no-unknown": true,
"string-no-newline": true,
"time-min-milliseconds": 100,
"unit-disallowed-list": ["pt"],
"unit-blacklist": ["pt"],
"unit-case": "lower",
"unit-no-unknown": true,
"value-keyword-case": ["lower", {"ignoreKeywords": ["/(@|$)/"]}],
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
},
"overrides": [
{
"files": ["**/yui/**/*.css"],
"rules": {
}
}
]
}
}
+286
View File
@@ -0,0 +1,286 @@
# PLEASE NOTE: Travis is not currently utilised by the Moodle core integration
# process (which uses our internal CI system) this file is here for the benefit
# of community developers git clones - see MDL-51458.
sudo: required
# We currently disable Travis notifications entirely until https://github.com/travis-ci/travis-ci/issues/4976
# is fixed.
notifications:
email: false
language: php
dist: xenial
services:
- mysql
php:
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
- 7.3
- 7.1.30 # Make this sticky because current default version (7.1.11) has a bug with redis-extension output (MDL-66062)
addons:
postgresql: "9.6"
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 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:
# Run mysql only on 7.3 - it's just too slow
- php: 7.3
env: DB=mysqli TASK=PHPUNIT
# 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'
cache:
directories:
- $HOME/.composer/cache
- $HOME/.npm
before_install:
# Avoid IPv6 default binding as service (causes redis not to start).
sudo service redis-server start --bind 127.0.0.1
install:
- >
if [ "$DB" = 'mysqli' ];
then
sudo mkdir /mnt/ramdisk
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
sudo service mysql stop
sudo mv /var/lib/mysql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
sudo service mysql restart
fi
- >
if [ "$DB" = 'pgsql' ];
then
sudo mkdir /mnt/ramdisk
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
sudo service postgresql stop
sudo mv /var/lib/postgresql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
sudo service postgresql start 9.6
fi
- >
if [ "$TASK" = 'PHPUNIT' ];
then
if [ -n "$GITHUB_APITOKEN" ]; then
composer config github-oauth.github.com $GITHUB_APITOKEN;
echo 'auth.json' >> .git/info/exclude
fi
echo 'extension="redis.so"' > /tmp/redis.ini
phpenv config-add /tmp/redis.ini
# Install composer dependencies.
# We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
# Typically it should be able to use the Composer cache if any other job has already completed before we started here.
travis_retry composer install --prefer-dist --no-interaction;
fi
- >
if [ "$TASK" = 'GRUNT' ];
then
nvm install $NVM_VERSION ;
nvm use $NVM_VERSION ;
fi
before_script:
- phpenv config-rm xdebug.ini
- >
if [ "$TASK" = 'PHPUNIT' -o "$TASK" = 'UPGRADE' ];
then
# Copy generic configuration in place.
cp config-dist.php config.php ;
# Create the moodledata directory.
mkdir -p "$HOME"/roots/base
# The database name and password.
sed -i \
-e "s%= 'moodle'%= 'travis_ci_test'%" \
-e "s%= 'password'%= ''%" \
config.php ;
# The wwwroot and dataroot.
sed -i \
-e "s%http://example.com/moodle%https://localhost%" \
-e "s%/home/example/moodledata%/home/travis/roots/base%" \
config.php ;
if [ "$DB" = 'pgsql' ];
then
# Postgres-specific setup.
sed -i \
-e "s%= 'username'%= 'postgres'%" \
config.php ;
psql -c 'CREATE DATABASE travis_ci_test;' -U postgres;
fi
if [ "$DB" = 'mysqli' ];
then
# MySQL-specific setup.
sed -i \
-e "s%= 'pgsql'%= 'mysqli'%" \
-e "s%= 'username'%= 'travis'%" \
-e "s%=> 'utf8mb4_unicode_ci'%=> 'utf8mb4_bin'%" \
config.php;
mysql -u root -e 'SET GLOBAL innodb_file_format=barracuda;' ;
mysql -u root -e 'SET GLOBAL innodb_file_per_table=ON;' ;
mysql -u root -e 'SET GLOBAL innodb_large_prefix=ON;' ;
mysql -e 'CREATE DATABASE travis_ci_test DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_bin;' ;
fi
fi
- >
if [ "$TASK" = 'PHPUNIT' ];
then
# Create a directory for the phpunit dataroot.
mkdir -p "$HOME"/roots/phpunit
# The phpunit dataroot and prefix..
sed -i \
-e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
-e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
config.php ;
# Redis cache store tests
sed -i \
-e "/require_once/i \\define('TEST_CACHESTORE_REDIS_TESTSERVERS', '127.0.0.1');" \
config.php ;
# Redis session tests, but not for PHP 7.2 and up. See MDL-60978 for more info.
redissession="define('TEST_SESSION_REDIS_HOST', '127.0.0.1');"
sed -i \
-e "/require_once/i \\${redissession}" \
config.php ;
# Initialise PHPUnit for Moodle.
php admin/tool/phpunit/cli/init.php
fi
- >
if [ "$TASK" = 'GRUNT' ];
then
npm install --no-spin;
npm install --no-spin -g grunt ;
fi
########################################################################
# CI Tests
########################################################################
- >
if [ "$TASK" = 'CITEST' ];
then
# Note - this is deliberately placed in the script section as we
# should not add any code until after phpunit has run.
# The following repositories are required.
# The local_ci repository does the actual checking.
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci
# We need the official upstream for comparison
git remote add upstream https://github.com/moodle/moodle.git;
git fetch upstream MOODLE_37_STABLE;
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
export GIT_COMMIT="$TRAVIS_COMMIT";
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
# Variables required by our linter.
export gitcmd=`which git`;
export gitdir="$TRAVIS_BUILD_DIR";
export phpcmd=`which php`;
fi
########################################################################
# 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' ];
then
vendor/bin/phpunit --fail-on-risky --disallow-test-output --verbose;
fi
- >
if [ "$TASK" = 'CITEST' ];
then
bash local/ci/php_lint/php_lint.sh;
fi
- >
if [ "$TASK" = 'GRUNT' ];
then
grunt ;
# Add all files to the git index and then run diff --cached to see all changes.
# This ensures that we get the status of all files, including new files.
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
git add . ;
git reset -- npm-shrinkwrap.json ;
git diff --cached --exit-code ;
fi
########################################################################
# Upgrade test
########################################################################
- >
if [ "$TASK" = 'UPGRADE' ];
then
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
+3 -3
View File
@@ -6,7 +6,7 @@ of developers, designers, teachers, testers, translators and other users. We
work in universities, schools, companies and other places. You are very welcome
to join us and contribute to the project.
See <https://moodledev.io/general/community/contribute> for the many ways you
See <https://docs.moodle.org/dev/Contributing_to_Moodle> for the many ways you
can help, not only with coding.
Moodle is open to community contributions to core, though all code must go
@@ -35,7 +35,7 @@ submitted patches has evolved.
* New features are developed on the master branch. Bug fixes are also
backported to currently supported maintenance (stable) branches.
For further details, see <https://moodledev.io/general/development/process>.
For further details, see <https://docs.moodle.org/dev/Process>.
Moodle plugins
--------------
@@ -53,4 +53,4 @@ be easily installed and updated via the Moodle administration interface.
the plugins directory. We do not pull from your code repository; you must do
it explicitly.
For further details, see <https://moodledev.io/general/community/plugincontribution>.
For further details, see <https://docs.moodle.org/dev/Plugin_contribution>.
+320 -219
View File
@@ -16,200 +16,23 @@
/* 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');
/* eslint-env node */
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,50 +40,328 @@ 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(/\/?$/, '/');
}
addTask('upgradablelibs', grunt);
// 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'}
}
},
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: {
includePaths: ["theme/boost/scss/", "theme/classic/scss/"]
}
},
watch: {
options: {
nospawn: true // We need not to spawn so config can be changed dynamically.
},
amd: {
files: ['**/amd/src/**/*.js'],
tasks: ['amd']
},
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: {
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/boost/style/moodle.css',
'theme/classic/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('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-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: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']);
+1 -1
View File
@@ -20,7 +20,7 @@ Moodle is widely used around the world by universities, schools, companies and
all manner of organisations and individuals.
Moodle is provided freely as open source software, under the GNU General Public
License <https://moodledev.io/general/license>.
License <https://docs.moodle.org/dev/License>.
Moodle is written in PHP and JavaScript and uses an SQL database for storing
the data.
+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));
}
}
-3
View File
@@ -1,3 +0,0 @@
define("core_admin/block_management_table",["exports","./plugin_management_table","core_table/dynamic","core/ajax","core/pending","core/notification"],(function(_exports,_plugin_management_table,_dynamic,_ajax,_pending,_notification){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_plugin_management_table=_interopRequireDefault(_plugin_management_table),_pending=_interopRequireDefault(_pending);class _default extends _plugin_management_table.default{constructor(){super(),this.addClickHandler(this.handleBlockProtectToggle)}setBlockProtectState(plugin,state){return(0,_ajax.call)([{methodname:"core_admin_set_block_protection",args:{plugin:plugin,state:state}}])[0]}async handleBlockProtectToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="toggleprotectstate"]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:processAction");await this.setBlockProtectState(stateToggle.dataset.plugin,"1"===stateToggle.dataset.targetState?1:0);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="toggleprotectstate"][data-plugin="'.concat(stateToggle.dataset.plugin,'"]')).focus(),pendingPromise.resolve()}}}return _exports.default=_default,_exports.default}));
//# sourceMappingURL=block_management_table.min.js.map
@@ -1 +0,0 @@
{"version":3,"file":"block_management_table.min.js","sources":["../src/block_management_table.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport PluginManagementTable from './plugin_management_table';\nimport {refreshTableContent} from 'core_table/dynamic';\nimport {call as fetchMany} from 'core/ajax';\nimport Pending from 'core/pending';\nimport {fetchNotifications} from 'core/notification';\n\nexport default class extends PluginManagementTable {\n constructor() {\n super();\n this.addClickHandler(this.handleBlockProtectToggle);\n }\n\n /**\n * Set the block protection state.\n *\n * @param {string} plugin\n * @param {number} state\n * @returns {Promise}\n */\n setBlockProtectState(plugin, state) {\n return fetchMany([{\n methodname: 'core_admin_set_block_protection',\n args: {\n plugin,\n state,\n },\n }])[0];\n }\n\n /**\n * Handle toggling of block protection.\n *\n * @param {HTMLElement} tableRoot\n * @param {Event} e\n */\n async handleBlockProtectToggle(tableRoot, e) {\n const stateToggle = e.target.closest('[data-action=\"toggleprotectstate\"]');\n if (stateToggle) {\n e.preventDefault();\n const pendingPromise = new Pending('core_table/dynamic:processAction');\n\n await this.setBlockProtectState(\n stateToggle.dataset.plugin,\n stateToggle.dataset.targetState === '1' ? 1 : 0\n );\n\n const [updatedRoot] = await Promise.all([\n refreshTableContent(tableRoot),\n fetchNotifications(),\n ]);\n\n // Refocus on the link that as pressed in the first place.\n updatedRoot.querySelector(`[data-action=\"toggleprotectstate\"][data-plugin=\"${stateToggle.dataset.plugin}\"]`).focus();\n pendingPromise.resolve();\n }\n }\n}\n"],"names":["PluginManagementTable","constructor","addClickHandler","this","handleBlockProtectToggle","setBlockProtectState","plugin","state","methodname","args","tableRoot","e","stateToggle","target","closest","preventDefault","pendingPromise","Pending","dataset","targetState","updatedRoot","Promise","all","querySelector","focus","resolve"],"mappings":"uhBAqB6BA,iCACzBC,2BAESC,gBAAgBC,KAAKC,0BAU9BC,qBAAqBC,OAAQC,cAClB,cAAU,CAAC,CACdC,WAAY,kCACZC,KAAM,CACFH,OAAAA,OACAC,MAAAA,UAEJ,kCASuBG,UAAWC,SAChCC,YAAcD,EAAEE,OAAOC,QAAQ,yCACjCF,YAAa,CACbD,EAAEI,uBACIC,eAAiB,IAAIC,iBAAQ,0CAE7Bd,KAAKE,qBACPO,YAAYM,QAAQZ,OACgB,MAApCM,YAAYM,QAAQC,YAAsB,EAAI,SAG3CC,mBAAqBC,QAAQC,IAAI,EACpC,gCAAoBZ,YACpB,wCAIJU,YAAYG,wEAAiEX,YAAYM,QAAQZ,cAAYkB,QAC7GR,eAAeS"}
-3
View File
@@ -1,3 +0,0 @@
define("core_admin/plugin_management_table",["exports","core_table/dynamic","core_table/local/dynamic/selectors","core/ajax","core/pending","core/notification"],(function(_exports,_dynamic,Selectors,_ajax,_pending,_notification){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,Selectors=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj}(Selectors),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};let watching=!1;return _exports.default=class{constructor(){!function(obj,key,value){key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}(this,"clickHandlers",[]),this.addClickHandler(this.handleStateToggle),this.addClickHandler(this.handleMoveUpDown),this.registerEventListeners()}static init(){watching||(watching=!0,new this)}addClickHandler(handler){this.clickHandlers.push(handler.bind(this))}registerEventListeners(){document.addEventListener("click",function(e){const tableRoot=this.getTableRoot(e);tableRoot&&this.clickHandlers.forEach((handler=>handler(tableRoot,e)))}.bind(this))}getTableRoot(e){const tableRoot=e.target.closest(Selectors.main.region);return tableRoot||!1}setPluginState(methodname,plugin,state){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,state:state}}])[0]}setPluginOrder(methodname,plugin,direction){return(0,_ajax.call)([{methodname:methodname,args:{plugin:plugin,direction:direction}}])[0]}async handleStateToggle(tableRoot,e){const stateToggle=e.target.closest('[data-action="togglestate"][data-toggle-method]');if(stateToggle){e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:togglestate");await this.setPluginState(stateToggle.dataset.toggleMethod,stateToggle.dataset.plugin,"1"===stateToggle.dataset.state?0:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]);updatedRoot.querySelector('[data-action="togglestate"][data-plugin="'.concat(stateToggle.dataset.plugin,'"]')).focus(),pendingPromise.resolve()}}async handleMoveUpDown(tableRoot,e){const actionLink=e.target.closest('[data-action="move"][data-method][data-direction]');if(!actionLink)return;e.preventDefault();const pendingPromise=new _pending.default("core_table/dynamic:processAction");await this.setPluginOrder(actionLink.dataset.method,actionLink.dataset.plugin,"up"===actionLink.dataset.direction?-1:1);const[updatedRoot]=await Promise.all([(0,_dynamic.refreshTableContent)(tableRoot),(0,_notification.fetchNotifications)()]),exactMatch=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"][data-direction="').concat(actionLink.dataset.direction,'"]'));var _updatedRoot$querySel;exactMatch?exactMatch.focus():null===(_updatedRoot$querySel=updatedRoot.querySelector('[data-action="move"][data-plugin="'.concat(actionLink.dataset.plugin,'"]')))||void 0===_updatedRoot$querySel||_updatedRoot$querySel.focus();pendingPromise.resolve()}},_exports.default}));
//# sourceMappingURL=plugin_management_table.min.js.map
File diff suppressed because one or more lines are too long
-72
View File
@@ -1,72 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
import PluginManagementTable from './plugin_management_table';
import {refreshTableContent} from 'core_table/dynamic';
import {call as fetchMany} from 'core/ajax';
import Pending from 'core/pending';
import {fetchNotifications} from 'core/notification';
export default class extends PluginManagementTable {
constructor() {
super();
this.addClickHandler(this.handleBlockProtectToggle);
}
/**
* Set the block protection state.
*
* @param {string} plugin
* @param {number} state
* @returns {Promise}
*/
setBlockProtectState(plugin, state) {
return fetchMany([{
methodname: 'core_admin_set_block_protection',
args: {
plugin,
state,
},
}])[0];
}
/**
* Handle toggling of block protection.
*
* @param {HTMLElement} tableRoot
* @param {Event} e
*/
async handleBlockProtectToggle(tableRoot, e) {
const stateToggle = e.target.closest('[data-action="toggleprotectstate"]');
if (stateToggle) {
e.preventDefault();
const pendingPromise = new Pending('core_table/dynamic:processAction');
await this.setBlockProtectState(
stateToggle.dataset.plugin,
stateToggle.dataset.targetState === '1' ? 1 : 0
);
const [updatedRoot] = await Promise.all([
refreshTableContent(tableRoot),
fetchNotifications(),
]);
// Refocus on the link that as pressed in the first place.
updatedRoot.querySelector(`[data-action="toggleprotectstate"][data-plugin="${stateToggle.dataset.plugin}"]`).focus();
pendingPromise.resolve();
}
}
}
-179
View File
@@ -1,179 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
import {refreshTableContent} from 'core_table/dynamic';
import * as Selectors from 'core_table/local/dynamic/selectors';
import {call as fetchMany} from 'core/ajax';
import Pending from 'core/pending';
import {fetchNotifications} from 'core/notification';
let watching = false;
export default class {
/**
* @property {function[]} clickHandlers a list of handlers to call on click.
*/
clickHandlers = [];
constructor() {
this.addClickHandler(this.handleStateToggle);
this.addClickHandler(this.handleMoveUpDown);
this.registerEventListeners();
}
/**
* Initialise an instance of the class.
*
* This is just a way of making it easier to initialise an instance of the class from PHP.
*/
static init() {
if (watching) {
return;
}
watching = true;
new this();
}
/**
* Add a click handler to the list of handlers.
*
* @param {Function} handler A handler to call on a click event
*/
addClickHandler(handler) {
this.clickHandlers.push(handler.bind(this));
}
/**
* Register the event listeners for this instance.
*/
registerEventListeners() {
document.addEventListener('click', function(e) {
const tableRoot = this.getTableRoot(e);
if (!tableRoot) {
return;
}
this.clickHandlers.forEach((handler) => handler(tableRoot, e));
}.bind(this));
}
/**
* Get the table root from an event.
*
* @param {Event} e
* @returns {HTMLElement|bool}
*/
getTableRoot(e) {
const tableRoot = e.target.closest(Selectors.main.region);
if (!tableRoot) {
return false;
}
return tableRoot;
}
/**
* Set the plugin state (enabled or disabled)
*
* @param {string} methodname The web service to call
* @param {string} plugin The name of the plugin to set the state for
* @param {number} state The state to set
* @returns {Promise}
*/
setPluginState(methodname, plugin, state) {
return fetchMany([{
methodname,
args: {
plugin,
state,
},
}])[0];
}
setPluginOrder(methodname, plugin, direction) {
return fetchMany([{
methodname,
args: {
plugin,
direction,
},
}])[0];
}
/**
* Handle state toggling.
*
* @param {HTMLElement} tableRoot
* @param {Event} e
*/
async handleStateToggle(tableRoot, e) {
const stateToggle = e.target.closest('[data-action="togglestate"][data-toggle-method]');
if (stateToggle) {
e.preventDefault();
const pendingPromise = new Pending('core_table/dynamic:togglestate');
await this.setPluginState(
stateToggle.dataset.toggleMethod,
stateToggle.dataset.plugin,
stateToggle.dataset.state === '1' ? 0 : 1
);
const [updatedRoot] = await Promise.all([
refreshTableContent(tableRoot),
fetchNotifications(),
]);
// Refocus on the link that as pressed in the first place.
updatedRoot.querySelector(`[data-action="togglestate"][data-plugin="${stateToggle.dataset.plugin}"]`).focus();
pendingPromise.resolve();
}
}
async handleMoveUpDown(tableRoot, e) {
const actionLink = e.target.closest('[data-action="move"][data-method][data-direction]');
if (!actionLink) {
return;
}
e.preventDefault();
const pendingPromise = new Pending('core_table/dynamic:processAction');
await this.setPluginOrder(
actionLink.dataset.method,
actionLink.dataset.plugin,
actionLink.dataset.direction === 'up' ? -1 : 1,
);
const [updatedRoot] = await Promise.all([
refreshTableContent(tableRoot),
fetchNotifications(),
]);
// Refocus on the link that as pressed in the first place.
const exactMatch = updatedRoot.querySelector(
`[data-action="move"][data-plugin="${actionLink.dataset.plugin}"][data-direction="${actionLink.dataset.direction}"]`
);
if (exactMatch) {
exactMatch.focus();
} else {
// The move link is not present anymore, so we need to focus on the other one.
updatedRoot.querySelector(`[data-action="move"][data-plugin="${actionLink.dataset.plugin}"]`)?.focus();
}
pendingPromise.resolve();
}
}
+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);
+212
View File
@@ -0,0 +1,212 @@
<?php
/**
* Edit configuration for an individual auth plugin
*/
require_once '../config.php';
require_once $CFG->libdir.'/adminlib.php';
$auth = required_param('auth', PARAM_PLUGIN);
$PAGE->set_pagetype('admin-auth-' . $auth);
admin_externalpage_setup('authsetting'.$auth);
$authplugin = get_auth_plugin($auth);
$err = array();
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageauths";
debugging("Use of config.html files in authentication plugins have been deprecated. " .
" Please migrate your plugin to use the admin settings API", DEBUG_DEVELOPER);
// save configuration changes
if ($frm = data_submitted() and confirm_sesskey()) {
$authplugin->validate_form($frm, $err);
if (count($err) == 0) {
// save plugin config
if ($authplugin->process_config($frm)) {
// save field lock configuration
foreach ($frm as $name => $value) {
if (preg_match('/^lockconfig_(.+?)$/', $name, $matches)) {
$plugin = "auth/$auth";
$name = $matches[1];
set_config($name, $value, $plugin);
}
}
redirect($returnurl);
exit;
}
} else {
foreach ($err as $key => $value) {
$focus = "form.$key";
}
}
} else {
$frmlegacystyle = get_config('auth/'.$auth);
$frmnewstyle = get_config('auth_'.$auth);
$frm = (object)array_merge((array)$frmlegacystyle, (array)$frmnewstyle);
}
$user_fields = $authplugin->userfields;
//$user_fields = array("firstname", "lastname", "email", "phone1", "phone2", "institution", "department", "address", "city", "country", "description", "idnumber", "lang");
/// Get the auth title (from core or own auth lang files)
$authtitle = $authplugin->get_title();
/// Get the auth descriptions (from core or own auth lang files)
$authdescription = $authplugin->get_description();
// output configuration form
echo $OUTPUT->header();
// choose an authentication method
echo "<form id=\"authmenu\" method=\"post\" action=\"auth_config.php\">\n";
echo "<div>\n";
echo "<input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n";
echo "<input type=\"hidden\" name=\"auth\" value=\"".$auth."\" />\n";
// auth plugin description
echo $OUTPUT->box_start();
echo $OUTPUT->heading($authtitle);
echo $OUTPUT->box_start('informationbox');
echo $authdescription;
echo $OUTPUT->box_end();
echo "<hr />\n";
$authplugin->config_form($frm, $err, $user_fields);
echo $OUTPUT->box_end();
echo '<p style="text-align: center"><input type="submit" value="' . get_string("savechanges") . "\" /></p>\n";
echo "</div>\n";
echo "</form>\n";
$PAGE->requires->string_for_js('unmaskpassword', 'core_form');
$PAGE->requires->yui_module('moodle-auth-passwordunmask', 'M.auth.passwordunmask');
echo $OUTPUT->footer();
exit;
/// Functions /////////////////////////////////////////////////////////////////
/**
* auth field locking
* Good enough for most auth plugins
* but some may want a custom one if they are offering
* other options
* Note: lockconfig_ fields have special handling.
*
* @param string $auth authentication plugin shortname
* @param array $user_fields user profile fields
* @param string $helptext help text to be displayed at top of form
* @param boolean $retrieveopts Map fields or lock only.
* @param boolean $updateopts Allow remote updates
* @param array $customfields list of custom profile fields
* @deprecated since Moodle 3.3
*/
function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts, $updateopts, $customfields = array()) {
global $DB, $OUTPUT;
debugging("The function 'print_auth_lock_options' has been deprecated, " .
"Please migrate your code to use the admin settings API and use the function 'display_auth_lock_options' instead. ",
DEBUG_DEVELOPER);
echo '<tr><td colspan="3">';
if ($retrieveopts) {
echo $OUTPUT->heading(get_string('auth_data_mapping', 'auth'));
} else {
echo $OUTPUT->heading(get_string('auth_fieldlocks', 'auth'));
}
echo '</td></tr>';
$lockoptions = array ('unlocked' => get_string('unlocked', 'auth'),
'unlockedifempty' => get_string('unlockedifempty', 'auth'),
'locked' => get_string('locked', 'auth'));
$updatelocaloptions = array('oncreate' => get_string('update_oncreate', 'auth'),
'onlogin' => get_string('update_onlogin', 'auth'));
$updateextoptions = array('0' => get_string('update_never', 'auth'),
'1' => get_string('update_onupdate', 'auth'));
$pluginconfig = get_config("auth/$auth");
// Helptext is on a field with rowspan.
if (empty($helptext)) {
$helptext = '&nbsp;';
}
// If we have custom fields then merge them with user fields.
if (!empty($customfields)) {
$user_fields = array_merge($user_fields, $customfields);
}
if (!empty($customfields)) {
$customfieldname = $DB->get_records('user_info_field', null, '', 'shortname, name');
}
foreach ($user_fields as $field) {
// Define some vars we'll work with.
if (!isset($pluginconfig->{"field_map_$field"})) {
$pluginconfig->{"field_map_$field"} = '';
}
if (!isset($pluginconfig->{"field_updatelocal_$field"})) {
$pluginconfig->{"field_updatelocal_$field"} = '';
}
if (!isset($pluginconfig->{"field_updateremote_$field"})) {
$pluginconfig->{"field_updateremote_$field"} = '';
}
if (!isset($pluginconfig->{"field_lock_$field"})) {
$pluginconfig->{"field_lock_$field"} = '';
}
// Define the fieldname we display to the user.
$fieldname = $field;
if ($fieldname === 'lang') {
$fieldname = get_string('language');
} elseif (!empty($customfields) && in_array($field, $customfields)) {
// If custom field then pick name from database.
$fieldshortname = str_replace('profile_field_', '', $fieldname);
$fieldname = $customfieldname[$fieldshortname]->name;
if (core_text::strlen($fieldshortname) > 67) {
// If custom profile field name is longer than 67 characters we will not be able to store the setting
// such as 'field_updateremote_profile_field_NOTSOSHORTSHORTNAME' in the database because the character
// limit for the setting name is 100.
continue;
}
} elseif ($fieldname == 'url') {
$fieldname = get_string('webpage');
} else {
$fieldname = get_string($fieldname);
}
if ($retrieveopts) {
$varname = 'field_map_' . $field;
echo '<tr valign="top"><td align="right">';
echo '<label for="lockconfig_'.$varname.'">'.$fieldname.'</label>';
echo '</td><td>';
echo "<input id=\"lockconfig_{$varname}\" name=\"lockconfig_{$varname}\" type=\"text\" size=\"30\" value=\"{$pluginconfig->$varname}\" />";
echo '<div style="text-align: right">';
echo '<label for="menulockconfig_field_updatelocal_'.$field.'">'.get_string('auth_updatelocal', 'auth') . '</label>&nbsp;';
echo html_writer::select($updatelocaloptions, "lockconfig_field_updatelocal_{$field}", $pluginconfig->{"field_updatelocal_$field"}, false);
echo '<br />';
if ($updateopts) {
echo '<label for="menulockconfig_field_updateremote_'.$field.'">'.get_string('auth_updateremote', 'auth') . '</label>&nbsp;';
echo html_writer::select($updateextoptions, "lockconfig_field_updateremote_{$field}", $pluginconfig->{"field_updateremote_$field"}, false);
echo '<br />';
}
echo '<label for="menulockconfig_field_lock_'.$field.'">'.get_string('auth_fieldlock', 'auth') . '</label>&nbsp;';
echo html_writer::select($lockoptions, "lockconfig_field_lock_{$field}", $pluginconfig->{"field_lock_$field"}, false);
echo '</div>';
} else {
echo '<tr valign="top"><td align="right">';
echo '<label for="menulockconfig_field_lock_'.$field.'">'.$fieldname.'</label>';
echo '</td><td>';
echo html_writer::select($lockoptions, "lockconfig_field_lock_{$field}", $pluginconfig->{"field_lock_$field"}, false);
}
echo '</td>';
if (!empty($helptext)) {
echo '<td rowspan="' . count($user_fields) . '">' . $helptext . '</td>';
$helptext = '';
}
echo '</tr>';
}
}
+223 -79
View File
@@ -1,94 +1,238 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Allows the admin to configure blocks (hide/show, uninstall and configure)
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Allows the admin to configure blocks (hide/show, uninstall and configure)
require_once('../config.php');
require_once("{$CFG->libdir}/adminlib.php");
require_once("{$CFG->libdir}/blocklib.php");
require_once("{$CFG->libdir}/tablelib.php");
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/blocklib.php');
require_once($CFG->libdir.'/tablelib.php');
admin_externalpage_setup('manageblocks');
admin_externalpage_setup('manageblocks');
$plugin = optional_param('plugin', '', PARAM_PLUGIN);
$action = optional_param('action', '', PARAM_ALPHA);
$unprotect = optional_param('unprotect', 0, PARAM_PLUGIN);
$protect = optional_param('protect', 0, PARAM_PLUGIN);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$hide = optional_param('hide', 0, PARAM_INT);
$show = optional_param('show', 0, PARAM_INT);
$unprotect = optional_param('unprotect', 0, PARAM_INT);
$protect = optional_param('protect', 0, PARAM_INT);
$strmanageblocks = get_string('manageblocks');
/// Print headings
// If data submitted, then process and store.
if (!empty($plugin) && !empty($action) && confirm_sesskey()) {
$manager = \core_plugin_manager::resolve_plugininfo_class('block');
$pluginname = get_string('pluginname', "block_{$plugin}");
$strmanageblocks = get_string('manageblocks');
$struninstall = get_string('uninstallplugin', 'core_admin');
$strversion = get_string('version');
$strhide = get_string('hide');
$strshow = get_string('show');
$strsettings = get_string('settings');
$strcourses = get_string('blockinstances', 'admin');
$strname = get_string('name');
$strshowblockcourse = get_string('showblockcourse');
$strprotecthdr = get_string('blockprotect', 'admin'). $OUTPUT->help_icon('blockprotect','admin');
$strprotect = get_string('blockprotect', 'admin');
$strunprotect = get_string('blockunprotect', 'admin');
if ($action === 'disable' && $manager::enable_plugin($plugin, 0)) {
\core\notification::add(
get_string('plugin_disabled', 'core_admin', $pluginname),
\core\notification::SUCCESS
);
// Settings not required - only pages.
admin_get_root(true, false);
} else if ($action === 'enable' && $manager::enable_plugin($plugin, 1)) {
\core\notification::add(
get_string('plugin_enabled', 'core_admin', $pluginname),
\core\notification::SUCCESS
);
/// If data submitted, then process and store.
// Settings not required - only pages.
admin_get_root(true, false);
if (!empty($hide) && confirm_sesskey()) {
if (!$block = $DB->get_record('block', array('id'=>$hide))) {
print_error('blockdoesnotexist', 'error');
}
$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
}
// Redirect back to the page with out any params.
redirect(new moodle_url('/admin/blocks.php'));
}
if (!empty($show) && confirm_sesskey() ) {
if (!$block = $DB->get_record('block', array('id'=>$show))) {
print_error('blockdoesnotexist', 'error');
}
$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()) {
block_manager::protect_block($protect);
$pluginname = get_string('pluginname', "block_{$protect}");
\core\notification::add(
get_string('blockprotected', 'core_admin', $pluginname),
\core\notification::SUCCESS
);
// Settings not required - only pages.
admin_get_root(true, false);
}
if (!empty($protect) && confirm_sesskey()) {
block_manager::protect_block((int)$protect);
admin_get_root(true, false); // settings not required - only pages
}
if (!empty($unprotect) && confirm_sesskey()) {
block_manager::unprotect_block($unprotect);
$pluginname = get_string('pluginname', "block_{$unprotect}");
\core\notification::add(
get_string('blockunprotected', 'core_admin', $pluginname),
\core\notification::SUCCESS
);
// Settings not required - only pages.
admin_get_root(true, false);
}
if (!empty($unprotect) && confirm_sesskey()) {
block_manager::unprotect_block((int)$unprotect);
admin_get_root(true, false); // settings not required - only pages
}
$undeletableblocktypes = block_manager::get_undeletable_block_types();
echo $OUTPUT->header();
echo $OUTPUT->heading($strmanageblocks);
/// Main display starts here
/// Get and sort the existing blocks
if (!$blocks = $DB->get_records('block', array(), 'name ASC')) {
print_error('noblocks', 'error'); // Should never happen
}
$incompatible = array();
/// Print the table of all blocks
$table = new flexible_table('admin-blocks-compatible');
$table->define_columns(array('name', 'instances', 'version', 'hideshow', 'undeletable', 'settings', 'uninstall'));
$table->define_headers(array($strname, $strcourses, $strversion, $strhide.'/'.$strshow, $strprotecthdr, $strsettings, $struninstall));
$table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/blocks.php');
$table->set_attribute('class', 'admintable blockstable generaltable');
$table->set_attribute('id', 'compatibleblockstable');
$table->setup();
$tablerows = array();
// Sort blocks using current locale.
$blocknames = array();
foreach ($blocks as $blockid=>$block) {
$blockname = $block->name;
if (file_exists("$CFG->dirroot/blocks/$blockname/block_$blockname.php")) {
$blocknames[$blockid] = get_string('pluginname', 'block_'.$blockname);
} else {
$blocknames[$blockid] = $blockname;
}
}
core_collator::asort($blocknames);
foreach ($blocknames as $blockid=>$strblockname) {
$block = $blocks[$blockid];
$blockname = $block->name;
$dbversion = get_config('block_'.$block->name, 'version');
if (!file_exists("$CFG->dirroot/blocks/$blockname/block_$blockname.php")) {
$blockobject = false;
$strblockname = '<span class="notifyproblem">'.$strblockname.' ('.get_string('missingfromdisk').')</span>';
$plugin = new stdClass();
$plugin->version = $dbversion;
} else {
$plugin = new stdClass();
$plugin->version = '???';
if (file_exists("$CFG->dirroot/blocks/$blockname/version.php")) {
include("$CFG->dirroot/blocks/$blockname/version.php");
}
if (!$blockobject = block_instance($block->name)) {
$incompatible[] = $block;
continue;
}
}
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('block_'.$blockname, 'manage')) {
$uninstall = html_writer::link($uninstallurl, $struninstall);
} else {
$uninstall = '';
}
$settings = ''; // By default, no configuration
if ($blockobject and $blockobject->has_config()) {
$blocksettings = admin_get_root()->locate('blocksetting' . $block->name);
if ($blocksettings instanceof admin_externalpage) {
$settings = '<a href="' . $blocksettings->url . '">' . get_string('settings') . '</a>';
} else if ($blocksettings instanceof admin_settingpage) {
$settings = '<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksetting'.$block->name.'">'.$strsettings.'</a>';
} else if (!file_exists($CFG->dirroot.'/blocks/'.$block->name.'/settings.php')) {
// If the block's settings node was not found, we check that the block really provides the settings.php file.
// Note that blocks can inject their settings to other nodes in the admin tree without using the default locations.
// This can be done by assigning null to $setting in settings.php and it is a valid case.
debugging('Warning: block_'.$block->name.' returns true in has_config() but does not provide a settings.php file',
DEBUG_DEVELOPER);
}
}
// MDL-11167, blocks can be placed on mymoodle, or the blogs page
// and it should not show up on course search page
$totalcount = $DB->count_records('block_instances', array('blockname'=>$blockname));
$count = $DB->count_records('block_instances', array('blockname'=>$blockname, 'pagetypepattern'=>'course-view-*'));
if ($count>0) {
$blocklist = "<a href=\"{$CFG->wwwroot}/course/search.php?blocklist=$blockid&amp;sesskey=".sesskey()."\" ";
$blocklist .= "title=\"$strshowblockcourse\" >$totalcount</a>";
}
else {
$blocklist = "$totalcount";
}
$class = ''; // Nothing fancy, by default
if (!$blockobject) {
// ignore
$visible = '';
} else if ($blocks[$blockid]->visible) {
$visible = '<a href="blocks.php?hide='.$blockid.'&amp;sesskey='.sesskey().'" title="'.$strhide.'">'.
$OUTPUT->pix_icon('t/hide', $strhide) . '</a>';
} else {
$visible = '<a href="blocks.php?show='.$blockid.'&amp;sesskey='.sesskey().'" title="'.$strshow.'">'.
$OUTPUT->pix_icon('t/show', $strshow) . '</a>';
$class = 'dimmed_text';
}
if ($dbversion == $plugin->version) {
$version = $dbversion;
} else {
$version = "$dbversion ($plugin->version)";
}
if (!$blockobject) {
// ignore
$undeletable = '';
} else if (in_array($blockname, $undeletableblocktypes)) {
$undeletable = '<a href="blocks.php?unprotect='.$blockid.'&amp;sesskey='.sesskey().'" title="'.$strunprotect.'">'.
$OUTPUT->pix_icon('t/unlock', $strunprotect) . '</a>';
} else {
$undeletable = '<a href="blocks.php?protect='.$blockid.'&amp;sesskey='.sesskey().'" title="'.$strprotect.'">'.
$OUTPUT->pix_icon('t/lock', $strprotect) . '</a>';
}
$row = array(
$strblockname,
$blocklist,
$version,
$visible,
$undeletable,
$settings,
$uninstall,
);
$table->add_data($row, $class);
}
$table->print_html();
if (!empty($incompatible)) {
echo $OUTPUT->heading(get_string('incompatibleblocks', 'blockstable', 'admin'));
$table = new flexible_table('admin-blocks-incompatible');
$table->define_columns(array('block', 'uninstall'));
$table->define_headers(array($strname, $struninstall));
$table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/blocks.php');
$table->set_attribute('class', 'incompatibleblockstable generaltable');
$table->setup();
foreach ($incompatible as $block) {
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('block_'.$block->name, 'manage')) {
$uninstall = html_writer::link($uninstallurl, $struninstall);
} else {
$uninstall = '';
}
$table->add_data(array(
$block->name,
$uninstall,
));
}
$table->print_html();
}
echo $OUTPUT->footer();
echo $OUTPUT->header();
echo $OUTPUT->heading($strmanageblocks);
echo $OUTPUT->notification(get_string('noteunneededblocks', 'admin'), 'info', false);
// Print the table of all blocks.
$table = new \core_admin\table\block_management_table();
$table->out();
echo $OUTPUT->footer();
+13 -14
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');
@@ -131,7 +126,8 @@ if ($savebutton) {
$outputhtml .= html_writer::end_tag('div');
}
$PAGE->set_title(implode(moodle_page::TITLE_SEPARATOR, $settingspage->visiblepath));
$visiblepathtosection = array_reverse($settingspage->visiblepath);
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
$PAGE->set_heading($SITE->fullname);
if ($buttons) {
$PAGE->set_button($buttons);
@@ -145,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');
@@ -157,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,127 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\admin;
use admin_setting;
use core_plugin_manager;
use core_text;
/**
* Admin setting plugin manager.
*
* @package core_admin
* @subpackage admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class admin_setting_plugin_manager extends admin_setting {
/** @var core_plugin_manager The plugin manager instance */
protected core_plugin_manager $pluginmanager;
/** @var string The plugintype that this manager covers */
protected string $plugintype;
/** @var string The class of the management table to use */
protected string $tableclass;
public function __construct(
string $plugintype,
string $tableclass,
string $name,
string $visiblename,
string $description = '',
string $defaultsetting = '',
) {
$this->nosave = true;
$this->pluginmanager = core_plugin_manager::instance();
$this->plugintype = $plugintype;
$this->tableclass = $tableclass;
parent::__construct($name, $visiblename, $description, $defaultsetting);
}
/**
* Always returns true, does nothing
*
* @return true
*/
public function get_setting(): bool {
return true;
}
/**
* Always returns true, does nothing
*
* @return true
*/
public function get_defaultsetting(): bool {
return true;
}
/**
* Always returns '', does not write anything
*
* @return string Always returns ''
*/
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
public function write_setting($data): string {
// Do not write any setting.
return '';
}
/**
* Checks if $query is one of the available editors
*
* @param string $query The string to search for
* @return bool Returns true if found, false if not
*/
public function is_related($query) {
if (parent::is_related($query)) {
return true;
}
$plugins = $this->pluginmanager->get_installed_plugins($this->plugintype);
foreach (array_keys($plugins) as $plugin) {
$plugin = "{$this->plugintype}_{$plugin}";
if (str_contains($plugin, $query)) {
return true;
}
$pluginname = get_string('pluginname', $plugin);
if (strpos(core_text::strtolower($pluginname), $query) !== false) {
return true;
}
}
return false;
}
/**
* Builds the XHTML to display the control
*
* @param string $data Unused
* @param string $query
* @return string
*/
public function output_html($data, $query = ''): string {
$table = new $this->tableclass();
if (!($table instanceof \core_admin\table\plugin_management_table)) {
throw new \coding_exception("{$this->tableclass} must be an instance of \\core_admin\\table\\plugin_management_table");
}
return highlight($query, $table->get_content());
}
}
-97
View File
@@ -1,97 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\external;
use block_manager;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
/**
* Web Service to control the state of a plugin.
*
* @package core_admin
* @category external
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_block_protection extends external_api {
/**
* Returns description of method parameters
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'plugin' => new external_value(PARAM_PLUGIN, 'The name of the plugin', VALUE_REQUIRED),
'state' => new external_value(PARAM_INT, 'The target state', VALUE_REQUIRED),
]);
}
/**
* Set the block protection state.
*
* @param string $plugin The name of the plugin
* @param int $state The target state
* @return null
*/
public static function execute(
string $plugin,
int $state,
): array {
[
'plugin' => $plugin,
'state' => $state,
] = self::validate_parameters(self::execute_parameters(), [
'plugin' => $plugin,
'state' => $state,
]);
$context = \context_system::instance();
self::validate_context($context);
require_capability('moodle/site:config', $context);
[, $pluginname] = explode('_', \core_component::normalize_componentname($plugin), 2);
$displayname = get_string('pluginname', $plugin);
if ($state) {
block_manager::protect_block($pluginname);
\core\notification::add(
get_string('blockprotected', 'core_admin', $displayname),
\core\notification::SUCCESS
);
} else {
block_manager::unprotect_block($pluginname);
\core\notification::add(
get_string('blockunprotected', 'core_admin', $displayname),
\core\notification::SUCCESS
);
}
return [];
}
/**
* Describe the return structure of the external service.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([]);
}
}
-84
View File
@@ -1,84 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\external;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
/**
* Web Service to control the order of a plugin.
*
* @package core_admin
* @category external
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_plugin_order extends external_api {
/**
* Returns description of method parameters
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'plugin' => new external_value(PARAM_PLUGIN, 'The name of the plugin', VALUE_REQUIRED),
'direction' => new external_value(PARAM_INT, 'The direction to move', VALUE_REQUIRED),
]);
}
/**
* Set the plugin state.
*
* @param string $plugin The name of the plugin
* @param int $direction The direction to move the plugin
* @return array
*/
public static function execute(
string $plugin,
int $direction,
): array {
[
'plugin' => $plugin,
'direction' => $direction,
] = self::validate_parameters(self::execute_parameters(), [
'plugin' => $plugin,
'direction' => $direction,
]);
$context = \context_system::instance();
self::validate_context($context);
require_capability('moodle/site:config', $context);
[$plugintype, $pluginname] = explode('_', \core_component::normalize_componentname($plugin), 2);
$manager = \core_plugin_manager::resolve_plugininfo_class($plugintype);
$manager::change_plugin_order($pluginname, $direction);
return [];
}
/**
* Describe the return structure of the external service.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([]);
}
}
-98
View File
@@ -1,98 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\external;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
/**
* Web Service to control the state of a plugin.
*
* @package core_admin
* @category external
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class set_plugin_state extends external_api {
/**
* Returns description of method parameters
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'plugin' => new external_value(PARAM_PLUGIN, 'The name of the plugin', VALUE_REQUIRED),
'state' => new external_value(PARAM_INT, 'The target state', VALUE_REQUIRED),
]);
}
/**
* Set the plugin state.
*
* @param string $plugin The name of the plugin
* @param int $state The target state
* @return null
*/
public static function execute(
string $plugin,
int $state,
): array {
[
'plugin' => $plugin,
'state' => $state,
] = self::validate_parameters(self::execute_parameters(), [
'plugin' => $plugin,
'state' => $state,
]);
$context = \context_system::instance();
self::validate_context($context);
require_capability('moodle/site:config', $context);
[$plugintype, $pluginname] = explode('_', \core_component::normalize_componentname($plugin), 2);
$manager = \core_plugin_manager::resolve_plugininfo_class($plugintype);
$displayname = get_string('pluginname', $plugin);
if ($manager::enable_plugin($pluginname, $state)) {
if (!empty($state)) {
\core\notification::add(
get_string('plugin_enabled', 'core_admin', $displayname),
\core\notification::SUCCESS
);
} else {
\core\notification::add(
get_string('plugin_disabled', 'core_admin', $displayname),
\core\notification::SUCCESS
);
}
}
return [];
}
/**
* Describe the return structure of the external service.
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([]);
}
}
-1
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'))
@@ -43,22 +43,11 @@ class testoutgoingmailconf_form extends \moodleform {
$mform = $this->_form;
// Recipient.
$options = ['maxlength' => '100', 'size' => '25', 'autocomplete' => 'email'];
$options = ['maxlength' => '100', 'size' => '25'];
$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');
@@ -67,26 +56,4 @@ class testoutgoingmailconf_form extends \moodleform {
$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'),
)));
}
}
@@ -1,118 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
use core_plugin_manager;
use dml_exception;
use html_writer;
use moodle_url;
use stdClass;
/**
* Activity Module admin settings.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class activity_management_table extends plugin_management_table {
public function setup() {
$this->set_attribute('id', 'modules');
$this->set_attribute('class', 'admintable generaltable');
parent::setup();
}
protected function get_table_id(): string {
return 'module-administration-table';
}
protected function get_plugintype(): string {
return 'mod';
}
public function guess_base_url(): void {
$this->define_baseurl(
new moodle_url('/admin/modules.php')
);
}
protected function get_action_url(array $params = []): moodle_url {
return new moodle_url('/admin/modules.php', $params);
}
protected function get_column_list(): array {
$columns = parent::get_column_list();
return array_merge(
array_slice($columns, 0, 1, true),
['activities' => get_string('activities')],
array_slice($columns, 1, null, true),
);
}
protected function col_name(stdClass $row): string {
global $OUTPUT;
$status = $row->plugininfo->get_status();
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
return html_writer::span(
get_string('pluginmissingfromdisk', 'core', $row->plugininfo),
'notifyproblem'
);
}
return html_writer::span(
html_writer::img(
$OUTPUT->image_url('monologo', $row->plugininfo->name),
'',
[
'class' => 'icon',
],
) . get_string('modulename', $row->plugininfo->name)
);
}
/**
* Show the number of activities present, with a link to courses containing activity if relevant.
*
* @param mixed $row
* @return string
*/
protected function col_activities(stdClass $row): string {
global $DB, $OUTPUT;
try {
$count = $DB->count_records_select($row->plugininfo->name, "course <> 0");
} catch (dml_exception $e) {
$count = -1;
}
if ($count > 0) {
return $OUTPUT->action_link(
new moodle_url('/course/search.php', [
'modulelist' => $row->plugininfo->name,
]),
$count,
null,
['title' => get_string('showmodulecourse')]
);
} else if ($count < 0) {
return get_string('error');
} else {
return $count;
}
}
}
@@ -1,153 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
use html_writer;
use moodle_url;
use stdClass;
/**
* Tiny admin settings.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class block_management_table extends \core_admin\table\plugin_management_table {
/** @var plugininfo[] A list of blocks which cannot be deleted */
protected array $undeletableblocktypes;
/** @var stdClass[] A list of basic block data */
protected array $blockdata;
/** @var array<string,int> A list of course counts */
protected array $courseblocks;
public function __construct() {
global $DB;
parent::__construct();
$this->undeletableblocktypes = \block_manager::get_undeletable_block_types();
$sql = 'SELECT b.name,
b.id,
COUNT(DISTINCT binst.id) as totalcount
FROM {block} b
LEFT JOIN {block_instances} binst ON binst.blockname = b.name
GROUP BY b.id,
b.name
ORDER BY b.name ASC';
$this->blockdata = $DB->get_records_sql($sql);
$sql = "SELECT blockname
FROM {block_instances}
WHERE pagetypepattern = 'course-view-*'
GROUP BY blockname";
$this->courseblocks = $DB->get_records_sql($sql);
}
protected function get_plugintype(): string {
return 'block';
}
public function guess_base_url(): void {
$this->define_baseurl(
new moodle_url('/admin/blocks.php')
);
}
protected function get_action_url(array $params = []): moodle_url {
return new moodle_url('/admin/blocks.php', $params);
}
protected function get_table_js_module(): string {
return 'core_admin/block_management_table';
}
protected function get_column_list(): array {
$columns = parent::get_column_list();
return array_merge(
array_slice($columns, 0, 1, true),
['instances' => get_string('blockinstances', 'admin')],
array_slice($columns, 1, 2, true),
['protect' => get_string('blockprotect', 'admin')],
array_slice($columns, 3, null, true),
);
}
protected function get_columns_with_help(): array {
return [
'protect' => new \help_icon('blockprotect', 'admin'),
];
}
/**
* Render the instances column
* @param stdClass $row
* @return string
*/
protected function col_instances(stdClass $row): string {
$blockdata = $this->blockdata[$row->plugininfo->name];
if (array_key_exists($blockdata->name, $this->courseblocks)) {
return html_writer::link(
new moodle_url('/course/search.php', [
'blocklist' => $blockdata->id,
]),
$blockdata->totalcount,
);
}
return $blockdata->totalcount;
}
/**
* Render the protect column.
*
* @param stdClass $row
* @return string
*/
protected function col_protect(stdClass $row): string {
global $OUTPUT;
$params = [
'sesskey' => sesskey(),
];
$protected = in_array($row->plugininfo->name, $this->undeletableblocktypes);
$pluginname = $row->plugininfo->displayname;
if ($protected) {
$params['unprotect'] = $row->plugininfo->name;
$icon = $OUTPUT->pix_icon('t/unlock', get_string('blockunprotectblock', 'admin', $pluginname));
} else {
$params['protect'] = $row->plugininfo->name;
$icon = $OUTPUT->pix_icon('t/lock', get_string('blockprotectblock', 'admin', $pluginname));
}
return html_writer::link(
$this->get_action_url($params),
$icon,
[
'data-action' => 'toggleprotectstate',
'data-plugin' => $row->plugin,
'data-target-state' => $protected ? 0 : 1,
],
);
return '';
}
}
@@ -1,63 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
use moodle_url;
/**
* Tiny admin settings.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class editor_management_table extends \core_admin\table\plugin_management_table {
protected function get_plugintype(): string {
return 'editor';
}
public function guess_base_url(): void {
$this->define_baseurl(
new moodle_url('/admin/settings.php', ['section' => 'manageeditors'])
);
}
protected function get_action_url(array $params = []): moodle_url {
return new moodle_url('/admin/editors.php', $params);
}
protected function order_plugins(array $plugins): array {
global $CFG;
// The Editor list is stored in an ordered string.
$activeeditors = explode(',', $CFG->texteditors);
$sortedplugins = [];
foreach ($activeeditors as $editor) {
if (isset($plugins[$editor])) {
$sortedplugins[$editor] = $plugins[$editor];
unset($plugins[$editor]);
}
}
$otherplugins = parent::order_plugins($plugins);
return array_merge(
$sortedplugins,
$otherplugins
);
}
}
@@ -1,71 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
use moodle_url;
use stdClass;
/**
* Media plugin admin settings.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class media_management_table extends \core_admin\table\plugin_management_table {
/** @var array The list of used extensions */
protected array $usedextensions = [];
protected function get_plugintype(): string {
return 'media';
}
protected function get_action_url(array $params = []): moodle_url {
return new moodle_url('/admin/media.php', $params);
}
protected function get_column_list(): array {
$columns = parent::get_column_list();
return array_merge(
array_slice($columns, 0, 1, true),
['supports' => get_string('supports', 'core_media')],
array_slice($columns, 1, null, true),
);
}
protected function col_name(stdClass $row): string {
global $OUTPUT, $PAGE;
$name = $row->plugininfo->name;
if ($PAGE->theme->resolve_image_location('icon', 'media_' . $name, false)) {
$icon = $OUTPUT->pix_icon('icon', '', "media_{$name}", ['class' => 'icon pluginicon']);
} else {
$icon = $OUTPUT->pix_icon('spacer', '', 'moodle', ['class' => 'icon pluginicon noicon']);
}
$help = '';
if (get_string_manager()->string_exists('pluginname_help', 'media_' . $name)) {
$help = '&nbsp;' . $OUTPUT->help_icon('pluginname', 'media_' . $name);
}
return $icon . $row->plugininfo->displayname . $help;
}
protected function col_supports(stdClass $row): string {
return $row->plugininfo->supports($this->usedextensions);
}
}
@@ -1,503 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
use context_system;
use core_plugin_manager;
use core_table\dynamic as dynamic_table;
use flexible_table;
use html_writer;
use moodle_url;
use stdClass;
defined('MOODLE_INTERNAL') || die();
require_once("{$CFG->libdir}/tablelib.php");
/**
* Plugin Management table.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class plugin_management_table extends flexible_table implements dynamic_table {
/** @var \core\plugininfo\base[] The plugin list */
protected array $plugins = [];
/** @var int The number of enabled plugins of this type */
protected int $enabledplugincount = 0;
/** @var core_plugin_manager */
protected core_plugin_manager $pluginmanager;
/** @var string The plugininfo class for this plugintype */
protected string $plugininfoclass;
public function __construct() {
global $CFG;
parent::__construct($this->get_table_id());
require_once($CFG->libdir . '/adminlib.php');
// Fetch the plugininfo class.
$this->pluginmanager = core_plugin_manager::instance();
$this->plugininfoclass = $this->pluginmanager::resolve_plugininfo_class($this->get_plugintype());
$this->guess_base_url();
$this->plugins = $this->get_sorted_plugins();
$this->enabledplugincount = count(array_filter($this->plugins, function ($plugin) {
return $plugin->is_enabled();
}));
$this->setup_column_configuration();
$this->set_filterset(new plugin_management_table_filterset());
$this->setup();
}
/**
* Get the list of sorted plugins.
*
* @return \core\plugininfo\base[]
*/
protected function get_sorted_plugins(): array {
if ($this->plugininfoclass::plugintype_supports_ordering()) {
return $this->plugininfoclass::get_sorted_plugins();
} else {
$plugins = $this->pluginmanager->get_plugins_of_type($this->get_plugintype());
return self::sort_plugins($plugins);
}
}
/**
* Sort the plugins list.
*
* Note: This only applies to plugins which do not support ordering.
*
* @param \core\plugininfo\base[] $plugins
* @return \core\plugininfo\base[]
*/
protected function sort_plugins(array $plugins): array {
// The asort functions work by reference.
\core_collator::asort_objects_by_property($plugins, 'displayname');
return $plugins;
}
/**
* Set up the column configuration for this table.
*/
protected function setup_column_configuration(): void {
$columnlist = $this->get_column_list();
$this->define_columns(array_keys($columnlist));
$this->define_headers(array_values($columnlist));
$columnswithhelp = $this->get_columns_with_help();
$columnhelp = array_map(function (string $column) use ($columnswithhelp): ?\renderable {
if (array_key_exists($column, $columnswithhelp)) {
return $columnswithhelp[$column];
}
return null;
}, array_keys($columnlist));
$this->define_help_for_headers($columnhelp);
}
/**
* Set the standard order of the plugins.
*
* @param array $plugins
* @return array
*/
protected function order_plugins(array $plugins): array {
uasort($plugins, function ($a, $b) {
if ($a->is_enabled() && !$b->is_enabled()) {
return -1;
} else if (!$a->is_enabled() && $b->is_enabled()) {
return 1;
}
return strnatcasecmp($a->name, $b->name);
});
return $plugins;
}
/**
* Get the plugintype for this table.
*
* @return string
*/
abstract protected function get_plugintype(): string;
/**
* Get the action URL for this table.
*
* The action URL is used to perform all actions when JS is not available.
*
* @param array $params
* @return moodle_url
*/
abstract protected function get_action_url(array $params = []): moodle_url;
/**
* Provide a default implementation for guessing the base URL from the action URL.
*/
public function guess_base_url(): void {
$this->define_baseurl($this->get_action_url());
}
/**
* Get the web service method used to toggle state.
*
* @return null|string
*/
protected function get_toggle_service(): ?string {
return 'core_admin_set_plugin_state';
}
/**
* Get the web service method used to order plugins.
*
* @return null|string
*/
protected function get_sortorder_service(): ?string {
return 'core_admin_set_plugin_order';
}
/**
* Get the ID of the table.
*
* @return string
*/
protected function get_table_id(): string {
return 'plugin_management_table-' . $this->get_plugintype();
}
/**
* Get a list of the column titles
* @return string[]
*/
protected function get_column_list(): array {
$columns = [
'name' => get_string('name', 'core'),
'version' => get_string('version', 'core'),
];
if ($this->supports_disabling()) {
$columns['enabled'] = get_string('pluginenabled', 'core_plugin');
}
if ($this->supports_ordering()) {
$columns['order'] = get_string('order', 'core');
}
$columns['settings'] = get_string('settings', 'core');
$columns['uninstall'] = get_string('uninstallplugin', 'core_admin');
return $columns;
}
protected function get_columns_with_help(): array {
return [];
}
/**
* Get the context for this table.
*
* @return context_system
*/
public function get_context(): context_system {
return context_system::instance();
}
/**
* Get the table content.
*/
public function get_content(): string {
ob_start();
$this->out();
$content = ob_get_contents();
ob_end_clean();
return $content;
}
/**
* Print the table.
*/
public function out(): void {
$plugintype = $this->get_plugintype();
foreach ($this->plugins as $plugininfo) {
$plugin = "{$plugintype}_{$plugininfo->name}";
$rowdata = (object) [
'plugin' => $plugin,
'plugininfo' => $plugininfo,
'name' => $plugininfo->displayname,
'version' => $plugininfo->versiondb,
];
$this->add_data_keyed(
$this->format_row($rowdata),
$this->get_row_class($rowdata)
);
}
$this->finish_output(false);
}
/**
* This table is not downloadable.
* @param bool $downloadable
* @return bool
*/
// phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
public function is_downloadable($downloadable = null): bool {
return false;
}
/**
* Show the name column content.
*
* @param stdClass $row
* @return string
*/
protected function col_name(stdClass $row): string {
$status = $row->plugininfo->get_status();
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
return html_writer::span(
get_string('pluginmissingfromdisk', 'core', $row->plugininfo),
'notifyproblem'
);
}
if ($row->plugininfo->is_installed_and_upgraded()) {
return $row->plugininfo->displayname;
}
return html_writer::span(
$row->plugininfo->displayname,
'notifyproblem'
);
}
/**
* Show the enable/disable column content.
*
* @param stdClass $row
* @return string
*/
protected function col_enabled(stdClass $row): string {
global $OUTPUT;
$enabled = $row->plugininfo->is_enabled();
$params = [
'sesskey' => sesskey(),
'plugin' => $row->plugininfo->name,
'action' => $enabled ? 'disable' : 'enable',
];
if ($enabled) {
$icon = $OUTPUT->pix_icon('t/hide', get_string('disableplugin', 'core_admin', $row->plugininfo->displayname));
} else {
$icon = $OUTPUT->pix_icon('t/show', get_string('enableplugin', 'core_admin', $row->plugininfo->displayname));
}
return html_writer::link(
$this->get_action_url($params),
$icon,
[
'data-toggle-method' => $this->get_toggle_service(),
'data-action' => 'togglestate',
'data-plugin' => $row->plugin,
'data-state' => $enabled ? 1 : 0,
],
);
}
protected function col_order(stdClass $row): string {
global $OUTPUT;
if (!$this->supports_ordering()) {
return '';
}
if (!$row->plugininfo->is_enabled()) {
return '';
}
if ($this->enabledplugincount <= 1) {
// There is only one row.
return '';
}
$hasup = true;
$hasdown = true;
if (empty($this->currentrow)) {
// This is the top row.
$hasup = false;
}
if ($this->currentrow === ($this->enabledplugincount - 1)) {
// This is the last row.
$hasdown = false;
}
if ($this->supports_ordering()) {
$dataattributes = [
'data-method' => $this->get_sortorder_service(),
'data-action' => 'move',
'data-plugin' => $row->plugin,
];
} else {
$dataattributes = [];
}
if ($hasup) {
$upicon = html_writer::link(
$this->get_action_url([
'sesskey' => sesskey(),
'action' => 'up',
'plugin' => $row->plugininfo->name,
]),
$OUTPUT->pix_icon('t/up', get_string('moveup')),
array_merge($dataattributes, ['data-direction' => 'up']),
);
} else {
$upicon = $OUTPUT->spacer();
}
if ($hasdown) {
$downicon = html_writer::link(
$this->get_action_url([
'sesskey' => sesskey(),
'action' => 'down',
'plugin' => $row->plugininfo->name,
]),
$OUTPUT->pix_icon('t/down', get_string('movedown')),
array_merge($dataattributes, ['data-direction' => 'down']),
);
} else {
$downicon = $OUTPUT->spacer();
}
// For now just add the up/down icons.
return html_writer::span($upicon . $downicon);
}
/**
* Show the settings column content.
*
* @param stdClass $row
* @return string
*/
protected function col_settings(stdClass $row): string {
if ($settingsurl = $row->plugininfo->get_settings_url()) {
return html_writer::link($settingsurl, get_string('settings'));
}
return '';
}
/**
* Show the Uninstall column content.
*
* @param stdClass $row
* @return string
*/
protected function col_uninstall(stdClass $row): string {
$status = $row->plugininfo->get_status();
if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
return get_string('status_new', 'core_plugin');
}
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
$uninstall = get_string('status_missing', 'core_plugin') . '<br/>';
} else {
$uninstall = '';
}
if ($uninstallurl = $this->pluginmanager->get_uninstall_url($row->plugin)) {
$uninstall .= html_writer::link($uninstallurl, get_string('uninstallplugin', 'core_admin'));
}
return $uninstall;
}
/**
* Get the JS module used to manage this table.
*
* This should be a class which extends 'core_admin/plugin_management_table'.
*
* @return string
*/
protected function get_table_js_module(): string {
return 'core_admin/plugin_management_table';
}
/**
* Add JS specific to this implementation.
*
* @return string
*/
protected function get_dynamic_table_html_end(): string {
global $PAGE;
$PAGE->requires->js_call_amd($this->get_table_js_module(), 'init');
return parent::get_dynamic_table_html_end();
}
/**
* Get any class to add to the row.
*
* @param mixed $row
* @return string
*/
protected function get_row_class($row): string {
$plugininfo = $row->plugininfo;
if ($plugininfo->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
return '';
}
if (!$plugininfo->is_enabled()) {
return 'dimmed_text';
}
return '';
}
public static function get_filterset_class(): string {
return self::class . '_filterset';
}
/**
* Whether this plugin type supports the disabling of plugins.
*
* @return bool
*/
protected function supports_disabling(): bool {
return $this->plugininfoclass::plugintype_supports_disabling();
}
/**
* Whether this table should show ordering fields.
*
* @return bool
*/
protected function supports_ordering(): bool {
return $this->plugininfoclass::plugintype_supports_ordering();
}
}
@@ -1,27 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
/**
* This file contains the dynamic interface.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class plugin_management_table_filterset extends \core_table\local\filter\filterset {
}
@@ -1,44 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\table;
use moodle_url;
/**
* Admin tool settings.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_plugin_management_table extends \core_admin\table\plugin_management_table {
protected function get_plugintype(): string {
return 'tool';
}
protected function get_column_list(): array {
$columns = parent::get_column_list();
unset($columns['settings']);
return $columns;
}
protected function get_action_url(array $params = []): moodle_url {
return new moodle_url('/admin/settings.php', array_merge(['section' => 'toolsmanagement'], $params));
}
}
+288
View File
@@ -0,0 +1,288 @@
<?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 log table.
*
* @package core_admin
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/tablelib.php');
/**
* Table to display list of task logs.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class task_log_table extends \table_sql {
/**
* Constructor for the task_log table.
*
* @param string $filter
* @param int $resultfilter
*/
public function __construct(string $filter = '', int $resultfilter = null) {
global $DB;
if (-1 === $resultfilter) {
$resultfilter = null;
}
parent::__construct('tasklogs');
$columnheaders = [
'classname' => get_string('name'),
'type' => get_string('tasktype', 'admin'),
'userid' => get_string('user', 'admin'),
'timestart' => get_string('task_starttime', 'admin'),
'duration' => get_string('task_duration', 'admin'),
'db' => get_string('task_dbstats', 'admin'),
'result' => get_string('task_result', 'admin'),
'actions' => '',
];
$this->define_columns(array_keys($columnheaders));
$this->define_headers(array_values($columnheaders));
// The name column is a header.
$this->define_header_column('classname');
// This table is not collapsible.
$this->collapsible(false);
// The actions class should not wrap. Use the BS text utility class.
$this->column_class('actions', 'text-nowrap');
// Allow pagination.
$this->pageable(true);
// Allow sorting. Default to sort by timestarted DESC.
$this->sortable(true, 'timestart', SORT_DESC);
// Add filtering.
$where = [];
$params = [];
if (!empty($filter)) {
$orwhere = [];
$filter = str_replace('\\', '\\\\', $filter);
// Check the class name.
$orwhere[] = $DB->sql_like('classname', ':classfilter', false, false);
$params['classfilter'] = '%' . $DB->sql_like_escape($filter) . '%';
$orwhere[] = $DB->sql_like('output', ':outputfilter', false, false);
$params['outputfilter'] = '%' . $DB->sql_like_escape($filter) . '%';
$where[] = "(" . implode(' OR ', $orwhere) . ")";
}
if (null !== $resultfilter) {
$where[] = 'tl.result = :result';
$params['result'] = $resultfilter;
}
$where = implode(' AND ', $where);
$this->set_sql('', '', $where, $params);
}
/**
* Query the db. Store results in the table object for use by build_table.
*
* @param int $pagesize size of page for paginated displayed table.
* @param bool $useinitialsbar do you want to use the initials bar. Bar
* will only be used if there is a fullname column defined for the table.
*/
public function query_db($pagesize, $useinitialsbar = true) {
global $DB;
// Fetch the attempts.
$sort = $this->get_sql_sort();
if ($sort) {
$sort = "ORDER BY $sort";
}
$extrafields = get_extra_user_fields(\context_system::instance());
$userfields = \user_picture::fields('u', $extrafields, 'userid2', 'user');
$where = '';
if (!empty($this->sql->where)) {
$where = "WHERE {$this->sql->where}";
}
$sql = "SELECT
tl.*,
tl.dbreads + tl.dbwrites AS db,
tl.timeend - tl.timestart AS duration,
{$userfields}
FROM {task_log} tl
LEFT JOIN {user} u ON u.id = tl.userid
{$where}
{$sort}";
$this->pagesize($pagesize, $DB->count_records_sql("SELECT COUNT('x') FROM {task_log} tl {$where}", $this->sql->params));
if (!$this->is_downloading()) {
$this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
} else {
$this->rawdata = $DB->get_records_sql($sql, $this->sql->params);
}
}
/**
* Format the name cell.
*
* @param \stdClass $row
* @return string
*/
public function col_classname($row) : string {
$output = '';
if (class_exists($row->classname)) {
$task = new $row->classname;
if ($task instanceof \core\task\scheduled_task) {
$output = $task->get_name();
}
}
$output .= \html_writer::tag('div', "\\{$row->classname}", [
'class' => 'task-class',
]);
return $output;
}
/**
* Format the type cell.
*
* @param \stdClass $row
* @return string
*/
public function col_type($row) : string {
if (\core\task\database_logger::TYPE_SCHEDULED == $row->type) {
return get_string('task_type:scheduled', 'admin');
} else {
return get_string('task_type:adhoc', 'admin');
}
}
/**
* Format the timestart cell.
*
* @param \stdClass $row
* @return string
*/
public function col_result($row) : string {
if ($row->result) {
return get_string('task_result:failed', 'admin');
} else {
return get_string('success');
}
}
/**
* Format the timestart cell.
*
* @param \stdClass $row
* @return string
*/
public function col_timestart($row) : string {
return userdate($row->timestart, get_string('strftimedatetimeshort', 'langconfig'));
}
/**
* Format the duration cell.
*
* @param \stdClass $row
* @return string
*/
public function col_duration($row) : string {
$duration = round($row->timeend - $row->timestart, 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);
}
/**
* Format the DB details cell.
*
* @param \stdClass $row
* @return string
*/
public function col_db($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;
}
/**
* Format the actions cell.
*
* @param \stdClass $row
* @return string
*/
public function col_actions($row) : string {
global $OUTPUT;
$actions = [];
$url = new \moodle_url('/admin/tasklogs.php', ['logid' => $row->id]);
// Quick view.
$actions[] = $OUTPUT->action_icon(
$url,
new \pix_icon('e/search', get_string('view')),
new \popup_action('click', $url)
);
// Download.
$actions[] = $OUTPUT->action_icon(
new \moodle_url($url, ['download' => true]),
new \pix_icon('t/download', get_string('download'))
);
return implode('&nbsp;', $actions);
}
/**
* Format the user cell.
*
* @param \stdClass $row
* @return string
*/
public function col_userid($row) : string {
if (empty($row->userid)) {
return '';
}
$user = (object) [];
username_load_fields_from_object($user, $row, 'user');
return fullname($user);
}
}
-174
View File
@@ -1,174 +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");
list($options, $unrecognized) = cli_get_params(
[
'help' => false,
'showsql' => false,
'showdebugging' => false,
'execute' => false,
'keep-alive' => 0,
'ignorelimits' => false,
'force' => false,
'id' => null,
'classname' => null,
'taskslimit' => null,
'failed' => false,
], [
'h' => 'help',
'e' => 'execute',
'k' => 'keep-alive',
'i' => 'ignorelimits',
'f' => 'force',
'c' => 'classname',
'l' => 'taskslimit',
]
);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
$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
--id Run (failed) task with id
-c, --classname Run tasks with a certain classname (FQN)
-l, --taskslimit=N Run at most N tasks
--failed Run only tasks that failed, ie those with a fail delay
Run all queued tasks:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --execute
Run all queued tasks of specific class:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --classname=\\\\core_course\\\\task\\\\course_delete_modules
Double backslash for the shell escape reasons.
Run a specific task:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --id=123456
Run a specific task with debugging:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --id=123456 --showsql --showdebugging
To profile a long running task:
\$sudo -u www-data /usr/bin/php admin/cli/adhoc_task.php --taskslimit=1 --classname='\\some\\class\\name' --ignorelimits
EOT;
if ($options['help']) {
echo $help;
exit(0);
}
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 (!get_config('core', 'cron_enabled') && !$options['force']) {
mtrace('Cron is disabled. Use --force to override.');
exit(1);
}
// Common debugging options.
if ($options['showdebugging']) {
set_debugging(DEBUG_DEVELOPER, true);
}
if ($options['showsql']) {
$DB->set_debug(true);
}
if (!empty($CFG->showcronsql)) {
$DB->set_debug(true);
}
if (!empty($CFG->showcrondebugging)) {
set_debugging(DEBUG_DEVELOPER, true);
}
// Process params.
core_php_time_limit::raise();
// Increase memory limit.
raise_memory_limit(MEMORY_EXTRA);
// Emulate normal session - we use admin account by default.
\core\cron::setup_user();
\core\local\cli\shutdown::script_supports_graceful_exit();
$humantimenow = date('r', time());
mtrace("Server Time: {$humantimenow}\n");
$classname = $options['classname'];
// Run a single adhoc task only, if requested.
if (!empty($options['id'])) {
$taskid = (int) $options['id'];
\core\cron::run_adhoc_task($taskid);
exit(0);
}
// Run all failed tasks.
if (!empty($options['failed'])) {
\core\cron::run_failed_adhoc_tasks($classname);
exit(0);
}
// Examine params and determine if we should run.
$execute = (bool) $options['execute'];
$keepalive = empty($options['keep-alive']) ? 0 : (int) $options['keep-alive'];
$taskslimit = empty($options['taskslimit']) ? null : (int) $options['taskslimit'];
$checklimits = empty($options['ignorelimits']);
if ($classname || $keepalive || $taskslimit) {
$execute = true;
}
// Output the help text if no criteria for running the adhoc tasks are given.
if (!$execute) {
echo $help;
exit(0);
}
\core\cron::run_adhoc_tasks(time(), $keepalive, $checklimits, null, $taskslimit, $classname);
+5 -4
View File
@@ -30,6 +30,7 @@ define('CLI_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once($CFG->libdir.'/clilib.php'); // cli only functions
require_once($CFG->libdir.'/cronlib.php');
// now get cli options
list($options, $unrecognized) = cli_get_params(array('help'=>false),
@@ -79,10 +80,10 @@ if (!empty($CFG->showcrondebugging)) {
$starttime = microtime();
// Emulate normal session.
\core\cron::setup_user();
/// emulate normal session
cron_setup_user();
// Start output log.
/// Start output log
$timenow = time();
mtrace("Server Time: ".date('r',$timenow)."\n\n");
@@ -95,4 +96,4 @@ backup_cron_automated_helper::run_automated_backup(backup_cron_automated_helper:
mtrace("Automated cron backups completed correctly");
$difftime = microtime_diff($starttime, microtime());
mtrace("Execution took ".$difftime." seconds");
mtrace("Execution took ".$difftime." seconds");
+2 -14
View File
@@ -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);
+10 -135
View File
@@ -1,4 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@@ -29,32 +30,13 @@
define('CLI_SCRIPT', true);
require(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/clilib.php');
require(__DIR__.'/../../config.php');
require_once($CFG->libdir.'/clilib.php'); // cli only functions
require_once($CFG->libdir.'/cronlib.php');
// Now get cli option.
[$options, $unrecognized] = cli_get_params(
[
'help' => false,
'stop' => false,
'list' => false,
'force' => false,
'enable' => false,
'disable' => false,
'disable-wait' => false,
'keep-alive' => null,
],
[
'h' => 'help',
's' => 'stop',
'l' => 'list',
'f' => 'force',
'e' => 'enable',
'd' => 'disable',
'w' => 'disable-wait',
'k' => 'keep-alive',
]
);
// now get cli options
list($options, $unrecognized) = cli_get_params(array('help'=>false),
array('h'=>'help'));
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
@@ -63,19 +45,10 @@ if ($unrecognized) {
if ($options['help']) {
$help =
"Execute periodic cron actions.
"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)
-k, --keep-alive=N Keep this script alive for N seconds and poll for new tasks
The default value can be set by administrators in:
Site administration > Server > Tasks > Task processing > Keep alive time
-h, --help Print out this help
Example:
\$sudo -u www-data /usr/bin/php admin/cli/cron.php
@@ -85,102 +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();
$keepalive = $options['keep-alive'];
\core\cron::run_main_process($keepalive);
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);
-123
View File
@@ -1,123 +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');
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!');
-209
View File
@@ -1,209 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This script allows you to view and change the emailstop flag of any user.
*
* @package core
* @subpackage cli
* @copyright 2023 Stephan Robotta (stephan.robotta@bfh.ch)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once($CFG->libdir.'/clilib.php');
// Define the input options.
$longparams = [
'email' => '',
'help' => false,
'id' => '',
'quiet' => false,
'stop' => '',
'username' => '',
];
$shortparams = [
'e' => 'email',
'h' => 'help',
'i' => 'id',
'q' => 'quiet',
's' => 'stop',
'u' => 'username',
];
// Define exit codes.
$exitsuccess = 0;
$exitunknownoption = 1;
$exitmissinguserarg = 2;
$exittoomanyuserarg = 3;
$exitnosearchargs = 4;
$exitnousersfound = 5;
$exitinvalidstopflag = 6;
$exiterrordb = 7;
// Now get cli options that are set by the caller.
list($options, $unrecognized) = cli_get_params($longparams, $shortparams);
$verbose = empty($options['quiet']);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
if ($verbose) {
cli_error(get_string('cliunknowoption', 'admin', $unrecognized), $exitunknownoption);
}
exit($exitunknownoption);
}
if ($options['help']) {
$help =
"Set/unset or show status of emailstop flag for a user, identified by username or email.
There are no security checks here because anybody who is able to
execute this file may execute any PHP too.
Options:
-h, --help Print out this help
-e, --email=email Specify user by email, separate many users by comma
-i, --id=id Specify user by id, separate many users by comma
-q, --quiet No output to stdout
-s, --stop=0|1|off|on Set new value for emailstop flag
-u, --username=username Specify user by username, separate many users by comma
Example:
\$sudo -u www-data /usr/bin/php admin/cli/emailstop.php --email=student1@example.com --stop=1
\$sudo -u www-data /usr/bin/php admin/cli/emailstop.php --email=student1@example.com,student2@example.com
\$sudo -u www-data /usr/bin/php admin/cli/emailstop.php --u=student1,student2 -s=on
";
echo $help;
exit($exitsuccess);
}
$cntempty = 0;
$cntfilled = 0;
$searchargs = [];
// Try to find out which option is used to fetch the users from. Also do sanitize etc.
foreach (['email', 'username', 'id'] as $option) {
if (empty($options[$option])) {
$cntempty++;
} else {
$cntfilled++;
$argname = $option;
// The search args must be: split by the comma, trimmed, and empty elements filtered out.
$searchargs = array_flip(array_filter(
array_map(
function ($item) {
return trim($item);
},
explode(',', $options[$option])
),
function ($item) {
return $item !== '';
}
));
}
}
if ($cntempty === 3) {
if ($verbose) {
cli_error('One of username, email, or id must be set.', $exitmissinguserarg);
}
exit($exitmissinguserarg);
}
if ($cntfilled > 1) {
if ($verbose) {
cli_error('Only one of email, username, or id can be set to identify a user.', $exittoomanyuserarg);
}
exit($exittoomanyuserarg);
}
if (empty($searchargs)) {
if ($verbose) {
cli_error('No values are provided for users.', $exitnosearchargs);
}
exit($exitnosearchargs);
}
try {
$users = $DB->get_records_list('user', $argname, array_keys($searchargs));
} catch (Exception $e) {
if ($verbose) {
cli_error("Could not fetch data from db by {$argname}: '{$options[$argname]}'.", $exiterrordb);
}
exit($exiterrordb);
}
if (empty($users)) {
if ($verbose) {
cli_error("Can not find any user by {$argname}: '{$options[$argname]}'.", $exitnousersfound);
}
exit($exitnousersfound);
}
// No stop flag set, then just print the user and the current emailstop flag state.
if ($options['stop'] === '') {
foreach ($users as $user) {
if ($verbose) {
echo 'user=' . $user->{$argname} . ' - emailstop=' . (int)$user->emailstop . PHP_EOL;
unset($searchargs[$user->{$argname}]);
}
}
if ($verbose) {
foreach (array_keys($searchargs) as $arg) {
echo 'user=' . $arg . ' - not found' . PHP_EOL;
}
}
exit($exitsuccess);
}
// Allowed values for the stop flag enabled are 1 and on, for disabled are 0 and off.
$validvalues = ['0', '1', 'off', 'on'];
$stopflag = strtolower($options['stop']);
if (!in_array($stopflag, $validvalues)) {
if ($verbose) {
cli_error('Value for the emailstop flag must be one of: ' . implode(', ', $validvalues) . '.', $exitinvalidstopflag);
}
exit($exitinvalidstopflag);
}
foreach ($validvalues as $value) {
if ($value === $stopflag) {
$stopflag = ($value === '1' || $value === 'on') ? 1 : 0;
break;
}
}
// Update each user with the stop flag to be set if it is necessary.
foreach ($users as $user) {
$line = 'Update user ' . $user->{$argname} . ($argname !== 'id' ? ' (' . $user->id . ')' : '') . ' - ';
if ((int)$user->emailstop !== $stopflag) {
$DB->set_field('user', 'emailstop', $stopflag, ['id' => $user->id]);
$line .= 'ok';
} else {
$line .= 'already done';
}
if ($verbose) {
echo $line . PHP_EOL;
unset($searchargs[$user->{$argname}]);
}
}
if ($verbose) {
foreach (array_keys($searchargs) as $arg) {
echo 'user=' . $arg . ' - not found' . PHP_EOL;
}
}
exit($exitsuccess);
-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";
+93 -126
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) {
@@ -649,114 +638,96 @@ do {
}
} 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, $options['adminemail']);
}
// 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 +746,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 +810,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.
-18
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:
@@ -98,8 +96,6 @@ list($options, $unrecognized) = cli_get_params(
'adminemail' => '',
'fullname' => '',
'shortname' => '',
'summary' => '',
'supportemail' => '',
'agree-license' => false,
'help' => false
),
@@ -108,11 +104,6 @@ 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;
@@ -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_controller::get_tempdir_name(SITEID, $USER->id);
$path = make_backup_temp_directory($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);
-167
View File
@@ -1,167 +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");
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.
\core\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);
}
\core\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);
+2 -22
View File
@@ -34,22 +34,16 @@ $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.
@@ -69,13 +63,10 @@ Examples:
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'
]);
@@ -90,26 +81,15 @@ if ($options['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']) {
if ($options['show-all'] || $options['show-missing']) {
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']) {
if ($options['show-all']) {
cli_writeln($pluginstring);
} else {
if ($plugin->get_status() === core_plugin_manager::PLUGIN_STATUS_MISSING) {
+24 -126
View File
@@ -48,16 +48,11 @@ require_once($CFG->libdir.'/environmentlib.php');
$lang = isset($SESSION->lang) ? $SESSION->lang : $CFG->lang;
list($options, $unrecognized) = cli_get_params(
array(
'allow-unstable' => false,
'help' => false,
'is-maintenance-required' => false,
'is-pending' => false,
'lang' => $lang,
'maintenance' => true,
'non-interactive' => false,
'set-ui-upgrade-lock' => false,
'unset-ui-upgrade-lock' => false,
'verbose-settings' => false,
'non-interactive' => false,
'allow-unstable' => false,
'help' => false,
'lang' => $lang,
'verbose-settings' => false
),
array(
'h' => 'help'
@@ -83,35 +78,17 @@ Please note you must execute this script with the same uid as apache!
Site defaults may be changed via local/defaults.php.
Options:
--allow-unstable Upgrade even if the version is not marked as stable yet,
required in non-interactive mode.
-h, --help Print out this help.
--is-maintenance-required Returns exit code 2 if the upgrade requires maintenance mode.
Returns exit code 3 if no maintenance is required for the upgrade.
--is-pending Exit with error code 2 if an upgrade is required.
--lang=CODE Set preferred language for CLI output. Defaults to the
site language if not set. Defaults to 'en' if the lang
parameter is invalid or if the language pack is not
installed.
--maintenance Sets whether this upgrade will use maintenance mode.
If not possible, the upgrade will not happen and the script will exit.
WARNING: Caches (except theme) will be STALE and MUST be purged after upgrading.
DO NOT USE if the upgrade contains known breaking changes to the way data
and the database interact.
RECOMMENDED for lightweight deployments, to allow for a graceful purge and
rebuild of the cache.
--non-interactive No interactive questions or confirmations.
--set-ui-upgrade-lock Sets the upgrade to CLI only and unable to be triggered from the frontend.
If called with --maintenance=false, the lock WILL NOT be released when the
upgrade finishes, and MUST be manually removed.
If called with --is-maintenance-required before an upgrade,
The lock WILL be released when the upgrade finishes.
--unset-ui-upgrade-lock Removes the frontend upgrade lock, if the lock exists.
Useful when an error during the upgrade leaves the upgrade locked,
or there is need to control the time where the unlock happens.
--verbose-settings Show new settings values. By default only the name of
new core or plugin settings are displayed. This option
outputs the new values as well as the setting name.
--non-interactive No interactive questions or confirmations
--allow-unstable Upgrade even if the version is not marked as stable yet,
required in non-interactive mode.
--lang=CODE Set preferred language for CLI output. Defaults to the
site language if not set. Defaults to 'en' if the lang
parameter is invalid or if the language pack is not
installed.
--verbose-settings Show new settings values. By default only the name of
new core or plugin settings are displayed. This option
outputs the new values as well as the setting name.
-h, --help Print out this help
Example:
\$sudo -u www-data /usr/bin/php admin/cli/upgrade.php
@@ -135,60 +112,10 @@ if ($version < $CFG->version) {
$oldversion = "$CFG->release ($CFG->version)";
$newversion = "$release ($version)";
if ($options['unset-ui-upgrade-lock']) {
// Unconditionally unset this config if requested.
set_config('outagelessupgrade', false);
cli_writeln(get_string('cliupgradeunsetlock', 'admin'));
}
$allhash = core_component::get_all_component_hash();
// Initialise allcomponent hash if not set. It will be correctly set after upgrade.
$CFG->allcomponenthash = $CFG->allcomponenthash ?? '';
if (!$options['maintenance']) {
if ($allhash !== $CFG->allcomponenthash) {
// Throw an error here, we can't proceed, this needs to set maintenance.
cli_error(get_string('cliupgrademaintenancerequired', 'core_admin'), 2);
}
// Set a constant to stop any upgrade var from being set during processing.
// This protects against the upgrade setting timeouts and maintenance during the upgrade.
define('CLI_UPGRADE_RUNNING', true);
// This database control is the control to block the GUI from doing upgrade related actions.
set_config('outagelessupgrade', true);
}
// We should ignore all upgrade locks here.
if (!moodle_needs_upgrading(false)) {
if (!moodle_needs_upgrading()) {
cli_error(get_string('cliupgradenoneed', 'core_admin', $newversion), 0);
}
// Handle exit based options for outputting upgrade state.
if ($options['is-pending'] || $options['is-maintenance-required']) {
// If we aren't doing a maintenance check, plain pending check.
if (!$options['is-maintenance-required']) {
cli_error(get_string('cliupgradepending', 'core_admin'), 2);
}
// Can we do this safely with no maintenance/outage? Detect if there is a schema or other application state change.
if ($allhash !== $CFG->allcomponenthash) {
// State change here, we need to do this in maintenance.
cli_writeln(get_string('cliupgradepending', 'core_admin'));
cli_error(get_string('cliupgrademaintenancerequired', 'core_admin'), 2);
}
// If requested, we should always set the upgrade lock here, so this cannot be run from frontend.
if ($options['set-ui-upgrade-lock']) {
set_config('outagelessupgrade', true);
cli_writeln(get_string('cliupgradesetlock', 'admin'));
}
// We can do an upgrade without maintenance!
cli_writeln(get_string('cliupgradepending', 'core_admin'));
cli_error(get_string('cliupgrademaintenancenotrequired', 'core_admin'), 3);
}
// Test environment first.
list($envstatus, $environment_results) = check_moodle_environment(normalize_version($release), ENV_SELECT_RELEASE);
if (!$envstatus) {
@@ -201,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'));
}
@@ -253,18 +171,12 @@ if ($interactive) {
}
if ($version > $CFG->version) {
// Only purge caches if this is a plain upgrade.
// In the case of a no-outage upgrade, we will gracefully roll caches after upgrade.
if ($options['maintenance']) {
// We purge all of MUC's caches here.
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
// This ensures a real config object is loaded and the stores will be purged.
// This is the only way we can purge custom caches such as memcache or APC.
// Note: all other calls to caches will still used the disabled API.
cache_helper::purge_all(true);
}
// We purge all of MUC's caches here.
// Caches are disabled for upgrade by CACHE_DISABLE_ALL so we must set the first arg to true.
// This ensures a real config object is loaded and the stores will be purged.
// This is the only way we can purge custom caches such as memcache or APC.
// Note: all other calls to caches will still used the disabled API.
cache_helper::purge_all(true);
upgrade_core($version, true);
}
set_config('release', $release);
@@ -302,18 +214,4 @@ foreach ($settingsoutput as $setting => $value) {
upgrade_themes();
echo get_string('cliupgradefinished', 'admin', $a)."\n";
if (!$options['maintenance']) {
cli_writeln(get_string('cliupgradecompletenomaintenanceupgrade', 'admin'));
// Here we check if upgrade lock has not been specifically set during this upgrade run.
// This supports wider server orchestration actions happening, which should call with no-maintenance AND set-ui-upgrade-lock,
// such as a new docker container deployment, of which the moodle upgrade is only a component.
if (!$options['set-ui-upgrade-lock']) {
// In this case we should release the lock now, as the upgrade is finished.
// We weren't told to keep the lock with set-ui-upgrade-lock, so release.
set_config('outagelessupgrade', false);
}
}
exit(0); // 0 means success
-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);
-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/>.
/**
* Reset course indentation
*
* @copyright 2023 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once('../../config.php');
require_admin();
$format = required_param('format', PARAM_PLUGIN);
$confirm = optional_param('confirm', false, PARAM_BOOL);
$backurl = new moodle_url('/admin/settings.php', ['section' => 'formatsetting'.$format]);
$PAGE->set_url('/admin/course/resetindentation.php', ['format' => $format]);
$PAGE->set_context(context_system::instance());
if ($confirm) {
require_sesskey();
$courses = $DB->get_records('course', ['format' => $format], 'id', 'id');
if (!empty($courses)) {
$courseids = array_keys($courses);
list($courseinsql, $courseparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED, 'course');
$DB->set_field_select('course_modules', 'indent', '0', "course $courseinsql AND indent <> 0", $courseparams);
rebuild_course_cache(0, true);
}
redirect(
$backurl,
get_string('resetindentationsuccess', 'admin'),
null,
\core\output\notification::NOTIFY_SUCCESS
);
}
$strtitle = get_string('resetindentation', 'admin');
$PAGE->set_title($strtitle);
$PAGE->set_heading($strtitle);
navigation_node::override_active_url(new moodle_url(
'/admin/course/resetindentation.php',
['action' => 'confirm', 'format' => $format]
));
echo $OUTPUT->header();
$displayoptions = ['confirmtitle' => get_string('resetindentation_title', 'admin')];
$confirmbutton = new single_button(
new moodle_url('/admin/course/resetindentation.php', ['confirm' => 1, 'format' => $format, 'sesskey' => sesskey()]),
get_string('resetindentation', 'admin'),
'post',
single_button::BUTTON_DANGER
);
$cancelbutton = new single_button($backurl, get_string('cancel'));
echo $OUTPUT->confirm(
get_string('resetindentation_help', 'admin', ['format' => get_string('pluginname', 'format_'.$format)]),
$confirmbutton,
$cancelbutton,
$displayoptions
);
echo $OUTPUT->footer();
+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':
+9 -8
View File
@@ -1,4 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@@ -35,7 +36,6 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// phpcs:ignoreFile moodle.Files.MoodleInternal.MoodleInternalGlobalState
if (defined('STDIN')) {
fwrite(STDERR, "ERROR: This script no longer supports CLI, please use admin/cli/cron.php instead\n");
@@ -49,7 +49,8 @@ define('WEB_CRON_EMULATED_CLI', 'defined'); // ugly ugly hack, do not use elsewh
define('NO_OUTPUT_BUFFERING', true);
require('../config.php');
require_once($CFG->libdir . '/clilib.php');
require_once($CFG->libdir.'/clilib.php');
require_once($CFG->libdir.'/cronlib.php');
// extra safety
\core\session\manager::write_close();
@@ -57,7 +58,7 @@ require_once($CFG->libdir . '/clilib.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.
@@ -65,16 +66,16 @@ 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;
}
}
// Send mime type and encoding.
// send mime type and encoding
@header('Content-Type: text/plain; charset=utf-8');
// We do not want html markup in emulated CLI.
// we do not want html markup in emulated CLI
@ini_set('html_errors', 'off');
// Execute the cron, disabling keepalive.
\core\cron::run_main_process(0);
// execute the cron
cron_run();
+7 -6
View File
@@ -32,7 +32,8 @@ $syscontext = context_system::instance();
$PAGE->set_url('/admin/customfields.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' => 'managecustomfields'));
@@ -41,20 +42,20 @@ $customfieldplugins = core_plugin_manager::instance()->get_plugins_of_type('cust
$sortorder = array_flip(array_keys($customfieldplugins));
if (!isset($customfieldplugins[$customfieldname])) {
throw new \moodle_exception('customfieldnotfound', 'error', $return, $customfieldname);
print_error('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);
set_config('disabled', 1, 'customfield_'. $customfieldname);
core_plugin_manager::reset_caches();
}
break;
case 'enable':
if (!$customfieldplugins[$customfieldname]->is_enabled()) {
$class = \core_plugin_manager::resolve_plugininfo_class('customfield');
$class::enable_plugin($customfieldname, true);
unset_config('disabled', 'customfield_'. $customfieldname);
core_plugin_manager::reset_caches();
}
break;
}
+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);
+62 -60
View File
@@ -1,96 +1,88 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A page to manage editor plugins.
*
* @package core_admin
* @copyright 2023 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* Allows admin to configure editors.
*/
require_once('../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->libdir . '/tablelib.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/tablelib.php');
$action = required_param('action', PARAM_ALPHANUMEXT);
$plugin = required_param('plugin', PARAM_PLUGIN);
$action = required_param('action', PARAM_ALPHANUMEXT);
$editor = required_param('editor', PARAM_PLUGIN);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$PAGE->set_url('/admin/editors.php', ['action' => $action, 'editor' => $plugin]);
$PAGE->set_url('/admin/editors.php', array('action'=>$action, 'editor'=>$editor));
$PAGE->set_context(context_system::instance());
require_admin();
require_sesskey();
require_login();
require_capability('moodle/site:config', context_system::instance());
$returnurl = new moodle_url('/admin/settings.php', ['section' => 'manageeditors']);
$returnurl = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageeditors";
// Get currently installed and enabled auth plugins.
$availableeditors = editors_get_available();
if (!empty($plugin) && empty($availableeditors[$plugin])) {
redirect($returnurl);
// get currently installed and enabled auth plugins
$available_editors = editors_get_available();
if (!empty($editor) and empty($available_editors[$editor])) {
redirect ($returnurl);
}
$activeeditors = explode(',', $CFG->texteditors);
foreach ($activeeditors as $key => $active) {
if (empty($availableeditors[$active])) {
unset($activeeditors[$key]);
$active_editors = explode(',', $CFG->texteditors);
foreach ($active_editors as $key=>$active) {
if (empty($available_editors[$active])) {
unset($active_editors[$key]);
}
}
////////////////////////////////////////////////////////////////////////////////
// process actions
if (!confirm_sesskey()) {
redirect($returnurl);
}
$return = true;
switch ($action) {
case 'disable':
// Remove from enabled list.
$class = \core_plugin_manager::resolve_plugininfo_class('editor');
$class::enable_plugin($plugin, false);
// 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.
if (!in_array($plugin, $activeeditors)) {
$class = \core_plugin_manager::resolve_plugininfo_class('editor');
$class::enable_plugin($plugin, true);
// add to enabled list
if (!in_array($editor, $active_editors)) {
$active_editors[] = $editor;
$active_editors = array_unique($active_editors);
add_to_config_log('editor_visibility', '0', '1', $editor);
}
break;
case 'down':
$key = array_search($plugin, $activeeditors);
$key = array_search($editor, $active_editors);
// check auth plugin is valid
if ($key !== false) {
// Move down the list.
if ($key < (count($activeeditors) - 1)) {
$fsave = $activeeditors[$key];
$activeeditors[$key] = $activeeditors[$key + 1];
$activeeditors[$key + 1] = $fsave;
add_to_config_log('editor_position', $key, $key + 1, $plugin);
set_config('texteditors', implode(',', $activeeditors));
core_plugin_manager::reset_caches();
// move down the list
if ($key < (count($active_editors) - 1)) {
$fsave = $active_editors[$key];
$active_editors[$key] = $active_editors[$key + 1];
$active_editors[$key + 1] = $fsave;
add_to_config_log('editor_position', $key, $key + 1, $editor);
}
}
break;
case 'up':
$key = array_search($plugin, $activeeditors);
$key = array_search($editor, $active_editors);
// check auth is valid
if ($key !== false) {
// Move up the list.
// move up the list
if ($key >= 1) {
$fsave = $activeeditors[$key];
$activeeditors[$key] = $activeeditors[$key - 1];
$activeeditors[$key - 1] = $fsave;
add_to_config_log('editor_position', $key, $key - 1, $plugin);
set_config('texteditors', implode(',', $activeeditors));
core_plugin_manager::reset_caches();
$fsave = $active_editors[$key];
$active_editors[$key] = $active_editors[$key - 1];
$active_editors[$key - 1] = $fsave;
add_to_config_log('editor_position', $key, $key - 1, $editor);
}
}
break;
@@ -99,4 +91,14 @@ switch ($action) {
break;
}
redirect($returnurl);
// 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

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