Compare commits

...

259 Commits

Author SHA1 Message Date
Huong Nguyen 4bd3217ce8 Moodle release 4.5.1 2024-12-06 13:13:03 +07:00
Huong Nguyen 3a71764572 NOBUG: Add upgrade notes 2024-12-06 13:13:03 +07:00
Huong Nguyen 15d05e6d76 weekly release 4.5+ 2024-12-05 22:32:49 +07:00
Huong Nguyen 96579b1904 NOBUG: Add upgrade notes 2024-12-05 22:32:48 +07:00
Huong Nguyen b5600c2b56 MDL-83921 competency: Update unit tests with latest changes 2024-12-05 18:36:58 +08:00
Huong Nguyen 5b374f607a MDL-82379 core_user: Move email change token to user private access key 2024-12-05 13:38:11 +08:00
Huong Nguyen f0f81cbddf Merge branch 'MDL-83606-405' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_405_STABLE 2024-12-05 12:09:52 +07:00
Huong Nguyen 9141121f01 Merge branch 'MDL-83836-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2024-12-05 11:44:12 +07:00
Jun Pataleta 588f9efe8c Merge branch 'MDL-83727-405' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_405_STABLE 2024-12-05 12:35:56 +08:00
Huong Nguyen 6e9de0d56b Merge branch 'MDL-83641-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-12-05 11:29:17 +07:00
Huong Nguyen 5f96398a90 MDL-83921 competency: Bump version 2024-12-05 11:20:51 +07:00
Michael Hawkins ea3bba0ac8 MDL-83921 competency: Match web service capability check with page check 2024-12-05 11:20:29 +07:00
Jun Pataleta fd1b952e3e Merge branch 'MDL-83823-405-enfix' of https://github.com/mudrd8mz/moodle into MOODLE_405_STABLE 2024-12-05 11:48:36 +08:00
Huong Nguyen 00253d140c Merge branch 'MDL-83584-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2024-12-05 10:12:46 +07:00
Huong Nguyen ade9ea1b64 Merge branch 'MDL-83223-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2024-12-05 10:08:45 +07:00
Huong Nguyen 175e553143 MDL-82963 Tag: Improve validation for users tagged with sepecified tag 2024-12-05 11:03:03 +08:00
Jun Pataleta ccaa6daf95 Merge branch 'MDL-83844-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-12-05 10:35:31 +08:00
Jun Pataleta f3a96eb019 Merge branch 'MDL-83710-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-12-05 09:55:07 +08:00
meirzamoodle f68fc730f4 MDL-83223 core: Use capture with addEventListener to intercept events
The issue is that Bootstrap’s dropdown component likely stops
event propagation after the first click to manage its own
dropdown behavior. This prevents your click event handler from
running on subsequent clicks.

To fix this, we can handle the event before Bootstrap’s code stops
the propagation by using capture option with addEventListener.
2024-12-04 10:36:54 +07:00
Laurent David c44cd5ce91 MDL-82757 mod_data: Improve group access handling
* Improved handling of group access to ensure correct visibility of records.
2024-12-04 02:50:20 +00:00
Jun Pataleta 65acecced1 MDL-61316 core: Fix session gc unit tests 2024-12-04 02:50:19 +00:00
meirzamoodle 3f8502225e MDL-61316 core: Removed 5x multiplier from guest session expiration 2024-12-04 02:50:19 +00:00
Mark Johnson a7f0516ae9 MDL-83357 question: Fix filter cleaning in page links 2024-12-04 02:50:19 +00:00
Mark Johnson 10fef0df99 MDL-83357 question: Additional cleaning of filter params 2024-12-04 02:50:19 +00:00
Huong Nguyen f6f8ec2291 Merge branch 'MDL-82946-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-12-04 09:39:30 +07:00
David Mudrák 065fdf4b2d MDL-83823 lang: Use the fixed strings in tests, too. 2024-12-03 20:14:25 +01:00
Helen Foster 1ab447455b MDL-83823 lang: Import fixed English strings (en_fix) 2024-12-03 20:13:50 +01:00
Angelia Dela Cruz bf301a5e81 MDL-82946 qbank: Behat coverage for questions bulk actions 2024-12-03 10:32:24 +08:00
Huong Nguyen bbd8a07f68 Merge branch 'MDL-83128-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-12-03 09:32:13 +07:00
Sara Arjona 8b2638fd56 Merge branch 'MDL-83686-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-12-02 13:52:27 +01:00
Sara Arjona 97414ca1cb Merge branch 'MDL-82949-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2024-12-02 12:01:27 +01:00
Paul Holden a11e396945 MDL-83641 cohort: allow 'includes' option be specified in form element. 2024-12-02 10:58:47 +00:00
Paul Holden c13aac05cc MDL-83844 mod_scorm: avoid SQL reserved words retrieving SCO timing. 2024-12-02 10:47:39 +00:00
Jun Pataleta a4e26132e0 Merge branch 'MDL-83648_405' of https://github.com/timhunt/moodle into MOODLE_405_STABLE 2024-12-02 17:24:28 +08:00
Huong Nguyen 1b6873b44a Merge branch 'MDL-82947-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2024-12-02 14:32:17 +07:00
Huong Nguyen 9b0645fc15 Merge branch 'MDL-83711-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2024-12-02 14:19:33 +07:00
Shamim Rezaie 2db344ac25 Merge branch 'MDL-75610_405_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_405_STABLE 2024-12-02 15:24:18 +11:00
Huong Nguyen 3be068cc72 Merge branch 'MDL-83778-405' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_405_STABLE 2024-12-02 10:44:22 +07:00
Huong Nguyen e33213647c Merge branch 'MDL-83670-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2024-12-02 10:30:51 +07:00
Huong Nguyen 289056c576 Merge branch 'MDL-82657_405_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_405_STABLE 2024-12-02 10:17:36 +07:00
Tim Hunt 1e6e11d8d3 MDL-83648 javascript dialogues: fix responsive behaviour
visibilityChanged in the dialogue base class does important things.
Therefore if ajaxException and exception also want to do something
else in response to the visibleChange event, it should use a
different method name, rather than a name that collides with the
base class method.
2024-11-29 17:05:29 +00:00
Luca Bösch 94a7dbf7f4 MDL-82949 qbank_managecategories: better vertical distinction of title. 2024-11-29 15:53:05 +01:00
Luca Bösch 70d07c5947 MDL-82947 qbank_managecategories: Hover color for category management. 2024-11-29 15:51:08 +01:00
Luca Bösch 8a31a02cce MDL-83711 quiz: Quiz navigation profile pic not linking in secure mode 2024-11-29 14:25:46 +01:00
Sara Arjona a8b2acd35c weekly release 4.5+ 2024-11-29 12:36:57 +01:00
Khoa Nguyen cd2a074cc2 MDL-83727 question: Core question privacy provider misuses lazy-loading 2024-11-29 10:54:51 +07:00
Khoa Nguyen 660d38be15 MDL-83778 quiz: prevent page caching for quiz view page 2024-11-28 16:41:29 +07:00
Jun Pataleta a87bb9848f MDL-83470 environment: Put back Oracle support for now
Even though Oracle support is planned to be dropped for 5.0, the
actual issue that drops it (MDL-83172) has not yet landed. So, it's
better to keep this in environment.xml for now and defer its removal
from environment.xml in MDL-83172.
2024-11-28 16:05:19 +07:00
Jun Pataleta 376411566a Merge branch 'MDL-82475-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-11-28 13:19:02 +08:00
David Woloszyn 85f4603014 MDL-83836 aiplacement_courseassist: Fixed JS selectors 2024-11-28 16:03:02 +11:00
Huong Nguyen 1ae32381c5 Merge branch 'MDL-83776-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-11-28 12:00:17 +07:00
Jun Pataleta 966ac4af8f Merge branch 'MDL-83614-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-11-28 12:55:30 +08:00
Jun Pataleta 9a20fcd261 Merge branch 'MDL-83759-405' of https://github.com/roland04/moodle into MOODLE_405_STABLE 2024-11-28 12:28:49 +08:00
Huong Nguyen d0931fd7d4 Merge branch 'MDL-83811-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2024-11-28 11:15:22 +07:00
Jun Pataleta d3f2f141a5 Merge branch 'MDL-83412-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2024-11-28 12:12:02 +08:00
Huong Nguyen 6f59fe694b Merge branch 'MDL-83470-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2024-11-28 11:03:42 +07:00
Jun Pataleta 2cc40431cb MDL-83412 core: Coding style fixes 2024-11-28 11:55:15 +08:00
Andrew Nicols cdbc789fd8 MDL-83412 calendartype_gregorian: Use core_date
Update timestamp_to_date_string to use core_date.
2024-11-28 11:55:15 +08:00
Andrew Nicols 3e45d0801e MDL-83412 core: Use LLL/LLLL for standalone Month names
We currently use MMM and MMMM which mean 'month in year', however in
some locales this is context-specific and should only be used in
conjunction with a day, for example "10 October 2024".

LLL and LLLL are for "stand-alone on the in year" and should be used
when a month is used without a day.
2024-11-28 11:55:15 +08:00
Huong Nguyen 348c37c98d Merge branch 'MDL-63264-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-11-28 10:46:17 +07:00
Huong Nguyen 57b5c36320 Merge branch 'MDL-83653_405' of https://github.com/timhunt/moodle into MOODLE_405_STABLE 2024-11-28 10:21:20 +07:00
Huong Nguyen cd0b2c6624 Merge branch 'MDL-82931-MOODLE_405_STABLE' of https://github.com/PhMemmel/moodle into MOODLE_405_STABLE 2024-11-28 09:44:11 +07:00
Huong Nguyen 2ba08bbda2 Merge branch 'MDL-83661-405' of https://github.com/ferranrecio/moodle into MOODLE_405_STABLE 2024-11-28 09:39:02 +07:00
Huong Nguyen e7e806e5f9 Merge branch 'MDL-82932-MOODLE_405_STABLE' of https://github.com/PhMemmel/moodle into MOODLE_405_STABLE 2024-11-28 09:28:14 +07:00
Huong Nguyen 9aa4e03b03 Merge branch 'MDL-83643-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-11-28 09:20:39 +07:00
Jun Pataleta e8e20f996d Merge branch 'MDL-83211-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2024-11-27 23:28:41 +08:00
Jun Pataleta 46861f51b7 Merge branch 'MDL-83788-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2024-11-27 16:19:25 +08:00
Huong Nguyen 6e98de58b4 Merge branch 'MDL-83658-MOODLE_405_STABLE' of https://github.com/praxisdigital/moodle into MOODLE_405_STABLE 2024-11-27 09:51:09 +07:00
Andrew Nicols 445f79f464 MDL-83788 mod_glossary: Correct assertions for assertArrayHasKey 2024-11-27 13:26:01 +11:00
Mark Johnson 491356530e MDL-82657 qbank_managecategories: Check "includesubcategories" on reload
The "includesubcategories" parameter is passed in the URL as lowercase,
but the Javascript was looking for "includeSubcategories" in camel case.
This meant it was always being set as false (unchecked) even when the
URL said it was true.

This fixes the casing in the Javascript, and adds a behat test to
confirm the fix.
2024-11-26 13:27:12 +00:00
Shamim Rezaie 943ad5a1fc Merge branch 'MDL-77957-405-test2' of https://github.com/rezaies/moodle into MOODLE_405_STABLE 2024-11-26 20:59:15 +11:00
Bastian Schmidt-Kuhl 88763543f8 MDL-77957 theme_boost: Fix drawer not closing on mobile if it has focus 2024-11-26 20:52:06 +11:00
Huong Nguyen 47e3c9ad06 Merge branch 'mdl-82762_405_wip' of https://github.com/james-cnz/moodle into MOODLE_405_STABLE 2024-11-26 12:10:36 +07:00
Khoa Nguyen 5ac62e7763 MDL-83606 Question bank: Delete questions to fit one page causes errors. 2024-11-26 11:16:50 +07:00
Jun Pataleta 7eba1d5996 MDL-83811 gha: Replace redis-64 with redis 5.0 2024-11-26 10:24:30 +08:00
Mikel Martín 5c1dd89dd3 MDL-83759 theme_boost: Fix user navigation items height 2024-11-25 12:07:39 +01:00
Huong Nguyen fa5a4b9612 Merge branch 'MDL-83704-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2024-11-25 10:15:37 +07:00
Paul Holden 2da1a26439 MDL-83128 blocks: consistently style/align block list icons. 2024-11-22 16:20:20 +00:00
Paul Holden 88ef13a747 MDL-63264 enrol: retrieve additional welcome message contact data.
The `maildisplay` field is required to determine from whom to send
the welcome message.

Co-authored-by: Zak Risha <zjrisha@gmail.com>
2024-11-22 16:17:44 +00:00
Paul Holden ab60333d45 MDL-83614 javascript: apply icon class to legacy lightbox spinner. 2024-11-22 16:13:29 +00:00
Jun Pataleta 485130d7c5 weekly release 4.5+ 2024-11-22 22:26:45 +08:00
Jun Pataleta f83ab42515 NOBUG: Add upgrade notes 2024-11-22 22:26:45 +08:00
Paul Holden eb19752b9a MDL-83776 customfield_text: correct link field URL encoding. 2024-11-21 09:53:41 +00:00
Jun Pataleta 3bb4b79a15 MDL-83470 core: Define environment requirements for Moodle 5.0 2024-11-21 17:35:11 +08:00
Andrew Nicols 671514c6c2 Merge branch 'MDL-83551-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-11-21 12:25:52 +08:00
Huong Nguyen 1113c4c5b1 Merge branch 'MDL-83529-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2024-11-21 11:21:45 +07:00
Huong Nguyen 2b50abb97b Merge branch 'MDL-83747-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2024-11-21 11:08:40 +07:00
Huong Nguyen 4a844708e6 Merge branch 'MDL-83048_405' of https://github.com/timhunt/moodle into MOODLE_405_STABLE 2024-11-21 11:01:32 +07:00
Andrew Nicols 36f946b5db Merge branch 'MDL-83501-url-encode-nginx-paths-MOODLE_405_STABLE' of https://github.com/rajandangi/moodle into MOODLE_405_STABLE 2024-11-21 11:48:15 +08:00
Jun Pataleta 39def1c571 Merge branch 'MDL-83290-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2024-11-21 11:46:10 +08:00
Andrew Nicols df4c1d94f0 Merge branch 'MDL-83226-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-11-21 11:44:49 +08:00
Philipp Memmel 1f60d5198d MDL-82931 mod_data: Harden parsing of content format 2024-11-20 21:23:02 +01:00
Paul Holden a93ceeef99 Merge branch 'MDL-83570-405-fix' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2024-11-20 12:25:05 +00:00
Jun Pataleta 1be54667d6 MDL-83570 tiny_recordrtc: Use the correct upgrade_plugin_savepoint()
And move the release upgrade line comment before the upgrade step.
2024-11-20 18:12:18 +08:00
Huong Nguyen 5ae0bf0a12 Merge branch 'MDL-83570-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2024-11-20 16:11:22 +07:00
Frederik Milling Pytlick 8dd0ea96e5 MDL-83658 core: Fix reactive debug tool logging
Fixed issue where the reactive debug panel does not log a transaction,
if the events fired are exactly the same as the previous ones.
2024-11-20 08:15:18 +01:00
meirzamoodle 42b0a371bf MDL-83570 tiny_recordrtc: Turn the audio bitrate input to Select field
The current code may have a bug. If users set the audio bit rate to
a non-supported value, such as 1000,
Firefox will display an error in the console,
while Chrome will create the recorded audio file successfully,
but it will have no sound. I tested this on Ubuntu 24.04.

The minimum bit rate threshold varies depending on the audio format.
During my tests with Firefox version 131.0.3, which uses
the audio/Ogg format, I found that the minimum supported value
is 24000. In Chrome 129.0.6668.70, which uses the audio/MP4 format,
the minimum supported value is 2400.

Due to these differences, I decided to change the input from
a text field to a select field, offering options that support both
Ogg and MP4 audio formats.

The database conversion for the old value has been provided in
the lib/db/upgrade.php. The script will find the closest match to
the current data and update it accordingly.
2024-11-20 10:02:53 +07:00
Jun Pataleta 796dd551f7 Merge branch 'MDL-81521-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2024-11-19 15:15:20 +08:00
Huong Nguyen 8d8b9b7268 Merge branch 'MDL-83610-405' of https://github.com/marinaglancy/moodle into MOODLE_405_STABLE 2024-11-19 09:28:22 +07:00
Jun Pataleta cb041849a3 MDL-83747 mod_data: Add accessible name for delcheck checkboxes 2024-11-18 19:39:04 +08:00
Marina Glancy e764df0dbb MDL-83610 behat: allow to set date fields in groups 2024-11-18 10:37:03 +00:00
meirzamoodle a817a54e90 MDL-83290 dml: Remove "ORDER BY" from the $sort 2024-11-18 16:08:26 +07:00
Jun Pataleta 176558d2ce Merge branch 'MDL-83502-405' of https://github.com/ferranrecio/moodle into MOODLE_405_STABLE 2024-11-18 14:37:01 +08:00
sam marshall f7931a5580 MDL-83529 Analytics: Upgrade can break if core module is deleted 2024-11-15 09:34:05 +00:00
sam marshall d12989b797 MDL-83211 core_search: Indexing can miss items due to race condition
Changes search indexing so that (except for test scripts) each indexing
run indexes only items up to 5 seconds ago, and the following indexing
will start from the same point. This ensures all items are indexed,
even if an item is written to the database one or two seconds after its
timecreated value.
2024-11-15 09:33:43 +00:00
Mark Johnson 1262e4539e MDL-75610 theme: Allow the activity title in Boost theme's secure layout 2024-11-15 08:32:28 +00:00
Mark Johnson eb7e4a9b65 MDL-75610 output: Fix title display logic in activity header
The display logic for including the title in the activity header was
such that the title would only display if both the theme default and the
layout option for 'notitle' were undefined or false. It was not possible
to a theme to have 'notitle' default to true, but have a layout override
that as false to display the title.

This change re-writes the is_title_allowed method to encapsulte the new
logic, first checking if the current layout has the option set and using
that, and if not falling back to the theme default if that is set. If
neither is set, the title is displayed.

This also tweaks moodle_page::magic_get_layout_options to ensure the
theme is initialised before trying to return the layout options.
2024-11-15 08:32:27 +00:00
Jun Pataleta 26e68178a8 Merge branch 'MDL-82877-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-11-15 13:31:26 +08:00
Andrew Nicols b1d7ea12cd MDL-81521 mod_quiz: Fix attempt walkthrough tests 2024-11-15 12:50:44 +08:00
Andrew Nicols c370c0cc5e MDL-81521 core: Update all possibly data providers to be static
Note: Some data providers could not be automatically be converted to
being static. These will be handled in a separate issue.
2024-11-15 12:50:44 +08:00
Huong Nguyen e1d05182a6 weekly release 4.5+ 2024-11-15 09:21:27 +07:00
Huong Nguyen 2b6424c59d NOBUG: Add upgrade notes 2024-11-15 09:21:27 +07:00
Jun Pataleta 8270af1bf0 Merge branch 'MDL-80926-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-11-14 12:05:12 +08:00
Jun Pataleta 88e82bb634 Merge branch 'MDL-74836_405_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_405_STABLE 2024-11-14 10:46:03 +08:00
Paul Holden 5a189106ad MDL-83710 report_questioninstances: fix missing type query params. 2024-11-13 21:16:00 +00:00
James C 6a107256e3 MDL-82762 course: Prevent "undefined" being added to course index 2024-11-14 10:14:43 +13:00
Wiktor Wandachowicz 521a83352d MDL-83048 mod_quiz: Fixed use of grade_out_of and plugin renderer 2024-11-13 17:12:52 +00:00
Huong Nguyen 66183e5320 Merge branch 'MDL-83185-405' of https://github.com/laurentdavid/moodle into MOODLE_405_STABLE 2024-11-13 14:26:02 +07:00
Huong Nguyen 5ebabad505 Merge branch 'MDL-80689_405' of https://github.com/timhunt/moodle into MOODLE_405_STABLE 2024-11-13 14:00:47 +07:00
Andrew Nicols 9fe9652c16 MDL-83704 core: Stop loading subplugins files to uninstall
The list of subplugin types was loaded from the json/php subplugins
file, but then the actual list of subplugins was loaded from the cache
in the component, rendering any benefit of using the source json/php as
pointless.
2024-11-13 10:25:06 +08:00
Andrew Nicols e5b715291d MDL-83704 core: Stop loading subplugins files to fetch caps
This information is heavily cached in the component class. This should
be used wherever possible rather than checking on disk.
2024-11-13 10:25:06 +08:00
Simey Lameze 50a7bad23e MDL-83643 behat: make manual completion scenario names unique 2024-11-13 07:17:51 +08:00
Simey Lameze cfcfa4b1cd MDL-83551 behat: make duplicated scenario names unique 2024-11-13 06:50:47 +08:00
Paul Holden 5ec8651d54 MDL-83686 task: restore behaviour for custom report task name column.
The linked task name column was only required for the system report
and broke aggregation/grouping when used within a custom report, so
fix that.
2024-11-11 16:10:06 +00:00
Nexterday ff08b12ce1 MDL-74836 theme: Display activity header on secure layouts 2024-11-11 15:17:28 +00:00
Philipp Memmel 762681f5c4 MDL-82932 mod_data: Fix export with userdata of deleted users 2024-11-11 13:00:14 +01:00
Tim Hunt 4d40958181 MDL-83653 file manager: report ajax errors
This is for things like when you click on a file, and then click on
the delete button, and an error happens then. Previously that was
ignored.
2024-11-08 17:13:55 +00:00
sam marshall 7f3f962c3f MDL-83670 availability_group: With hidden groups, can throw warning 2024-11-08 11:57:48 +00:00
ferran aab9e18b6d MDL-83661 core_courseformat: fix drop file modal
When the user drags and drops a file into a course section that can
create more than one type of activity (for example a zip file) the modal
had repeated form elements ids. Now every radio option has its own id.
2024-11-08 11:46:05 +01:00
Huong Nguyen cd5c991ede weekly release 4.5+ 2024-11-08 13:56:33 +07:00
Huong Nguyen 1c70185782 MDL-82335 qbank_columnsortorder: Fix upgrade code coding style 2024-11-08 09:03:21 +07:00
sam marshall cf431667e9 MDL-83584 report_log: Group filter can get list of all users in system 2024-11-07 09:39:15 +00:00
Huong Nguyen 598b4743cc MDL-82335 qbank_columnsortorder: Cleanup upgrade code 2024-11-07 13:37:37 +07:00
Huong Nguyen a35b341ce7 Merge branch 'MDL-83619-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-11-07 11:05:27 +07:00
Huong Nguyen 66f4852bff Merge branch 'MDL-83611-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-11-07 11:02:21 +07:00
Huong Nguyen aeace8ee75 Merge branch 'MDL-82335_405' of https://github.com/AnupamaSarjoshi/moodle into MOODLE_405_STABLE 2024-11-07 09:31:45 +07:00
Huong Nguyen 38f99a1e60 Merge branch 'MDL-83316-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-11-07 09:26:50 +07:00
Simey Lameze 7547dec095 MDL-83316 behat: remove duplicated Then from new test 2024-11-07 07:46:02 +08:00
sam marshall d4564b876e MDL-83316 Behat: New step allows system clock change 2024-11-07 07:46:02 +08:00
Jun Pataleta 0f5cb9dbd5 Merge branch 'mdl-83497_405' of https://github.com/james-cnz/moodle into MOODLE_405_STABLE 2024-11-06 22:38:40 +08:00
Anupama Sarjoshi 1ecc215b3a MDL-82335 qbank_columnsortorder: Fix upgrading issue
When upgraded to Moodle 4.4 or higher, for qbank_columnsortorder
the colsize values in the config_plugins were getting incorrectly set,
resulting in errors accessing the question bank. Changes done to fix
this code and to remove the corrupted colsize value from
config_plugins table.
2024-11-06 13:17:58 +00:00
Jun Pataleta ecc8edd917 Merge branch 'MDL-76563-405' of https://github.com/roland04/moodle into MOODLE_405_STABLE 2024-11-06 17:29:29 +08:00
Simey Lameze 8bcec8ba5f MDL-80926 behat: fix random and improve h5p completion test 2024-11-06 13:36:58 +08:00
Jun Pataleta b26192f62f Merge branch 'MDL-83602-405' of https://github.com/ilyatregubov/moodle into MOODLE_405_STABLE 2024-11-06 13:30:44 +08:00
Simey Lameze 82c915dbc3 MDL-83611 behat: increase window size to avoid randoms 2024-11-05 13:21:23 +08:00
Simey Lameze 50ab3f94d5 MDL-83619 behat: enable bbb module early in the test 2024-11-05 10:23:24 +08:00
Paul Holden 5b282947d7 MDL-82877 customfield: pass correct instanceid for restore structure. 2024-11-04 15:32:09 +00:00
Paul Holden 24dc478086 MDL-83226 customfield: set backup/restore configuration defaults. 2024-11-04 15:29:11 +00:00
Laurent David 2562bbfd1b MDL-83185 core_courseformat: Refresh cache on group change
* When we add users to a group (or remove them), we should refresh
the course index cache so it stays in sync with what the user
can actually see.
2024-11-04 06:14:06 +01:00
ferran 1716e2f2cd MDL-83185 core_courseformat: Allow global state cache invalidation 2024-11-04 06:14:06 +01:00
Huong Nguyen acff633e39 weekly release 4.5+ 2024-11-01 14:29:15 +07:00
Huong Nguyen 65ceca6092 NOBUG: Add upgrade notes 2024-11-01 14:29:15 +07:00
Huong Nguyen c21b1143a4 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2024-11-01 14:29:01 +07:00
Tim Hunt 0cd7aaebcd MDL-80689 filepicker: better reporting of incorrect file type
Before this change, file type errors were reported like system errors. Now,
they are reported in a plain dialoue, which is more like how it works for
drag-drop upload.

Also, before this, after an upload errors, you were left with a blank
filepicker dialogue. Now, the upload form is redisplayed.
2024-10-31 11:38:28 +00:00
Tim Hunt 2e8b980985 MDL-80689 behat: add a transformation to get dirroot 2024-10-31 11:38:27 +00:00
Tim Hunt 01aa6fa7d2 MDL-80689 form behat: move fixture file to the expected place 2024-10-31 11:38:27 +00:00
Ilya Tregubov 6290196cde MDL-83602 customfield_number: Add help text for fieldtype. 2024-10-31 16:17:49 +08:00
Huong Nguyen ffa8c930f0 Merge branch 'MDL-82911-405-fix' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-10-31 14:14:28 +07:00
Simey Lameze 8679f4afdf MDL-82911 behat: change future times example to minutes 2024-10-31 14:15:41 +08:00
Huong Nguyen 1afeadb4f4 Merge branch 'MDL-82911-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2024-10-31 11:22:27 +07:00
Huong Nguyen 3fc2111a4b Merge branch 'MDL-83414-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2024-10-31 11:22:27 +07:00
Huong Nguyen d731f7e01e Merge branch 'MDL-83514-405' of https://github.com/marinaglancy/moodle into MOODLE_405_STABLE 2024-10-31 11:22:27 +07:00
Huong Nguyen 49fbe6d614 Merge branch 'MDL-82989-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2024-10-31 11:22:26 +07:00
Jun Pataleta 9ece615f6c Merge branch 'MDL-82809-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-31 11:22:26 +07:00
Huong Nguyen 42052386d1 Merge branch 'MDL-82988-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2024-10-31 11:22:26 +07:00
Angelia Dela Cruz 0d02ded10f MDL-83414 core_grades: Behat to test custom scale display 2024-10-31 09:46:29 +08:00
Marina Glancy aaf5c3f8b7 MDL-83514 customfield_number: add missing event observers 2024-10-29 19:44:12 +00:00
Angelia Dela Cruz 11c941f404 MDL-82911 mod_bigbluebuttonbn: Behat for BBB open and close date time 2024-10-29 11:45:51 +08:00
AMOS bot 87d0aae1fb Automatically generated installer lang files 2024-10-29 00:07:54 +00:00
meirzamoodle 3e0c2a45fb MDL-82989 communication_matrix: Apply helper to mock http_client 2024-10-27 15:56:39 +07:00
meirzamoodle a3b84f77c7 MDL-82988 general: Apply helper to get path to fixture 2024-10-27 15:38:50 +07:00
Huong Nguyen 149a477903 weekly release 4.5+ 2024-10-25 08:35:54 +07:00
Huong Nguyen 47cd445f67 NOBUG: Add upgrade notes 2024-10-25 08:35:53 +07:00
Huong Nguyen 5524686f71 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2024-10-25 08:35:39 +07:00
Mikel Martín 20d4962c33 MDL-76563 theme: Change SCSS variable value
Change the value of the $pink SCSS colour variable so it is
colour contrast accessible on white backgrounds.
2024-10-24 13:27:49 +02:00
Jun Pataleta 1b93c2781e Merge branch 'MDL-82548-main' of https://github.com/roland04/moodle into MOODLE_405_STABLE 2024-10-24 12:18:34 +08:00
Jun Pataleta 39658c5b3a Merge branch 'MDL-83423-405' of https://github.com/snake/moodle into MOODLE_405_STABLE 2024-10-24 12:13:23 +08:00
Huong Nguyen e271f67942 Merge branch 'MDL-83432-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-24 10:13:12 +07:00
Huong Nguyen 1aef5337bd Merge branch 'MDL-83504-405' of https://github.com/marinaglancy/moodle into MOODLE_405_STABLE 2024-10-24 09:44:51 +07:00
AMOS bot 3ef3a9b1bc Automatically generated installer lang files 2024-10-24 00:08:18 +00:00
Jun Pataleta 80c7a3a847 Merge branch 'MDL-81308-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2024-10-23 18:15:24 +08:00
Jun Pataleta c5b16d9afb Merge branch 'MDL-83430-405' of https://github.com/marinaglancy/moodle into MOODLE_405_STABLE 2024-10-23 16:09:37 +08:00
Jun Pataleta 4fb2a4dd60 Merge branch 'MDL-83463-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-23 14:35:35 +08:00
Andrew Nicols 5ab2997d89 MDL-81308 core: Use a helper for consecutive invocation counts 2024-10-23 14:19:26 +08:00
Andrew Nicols 16efbcaa01 MDL-81308 core: Update tests to not use withConsecutive 2024-10-23 14:19:25 +08:00
Jun Pataleta 3f020e662d Merge branch 'MDL-83376-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2024-10-22 17:18:31 +08:00
Jun Pataleta ef01def984 Merge branch 'MDL-83472-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-22 15:55:54 +08:00
Marina Glancy ce1ef8bda0 MDL-83504 user: reset preference cache in unittests 2024-10-21 17:59:08 +01:00
ferran 8adf0918ce MDL-83502 course: fix chrome file dropping in course page 2024-10-21 11:48:36 +02:00
rajandangi 86e830eac4 MDL-83501 core: URL encode paths for Nginx X-Accel-Redirect 2024-10-21 19:37:45 +10:30
meirzamoodle 60fb2c1232 MDL-83376 AI: Add is_request_allowed() to the base provider 2024-10-21 13:32:12 +07:00
James C 605a610702 MDL-83497 course: Preserve move section dialogue info HTML 2024-10-19 16:21:46 +13:00
Paul Holden 55e6c1b588 MDL-83432 enrol: fix arguments to enrolment test generator. 2024-10-18 15:12:44 +01:00
Paul Holden e792dbbe0b MDL-83432 enrol_manual: reference correct role in welcome message. 2024-10-18 15:12:44 +01:00
Shamim Rezaie 09880d7d78 weekly release 4.5+ 2024-10-18 23:28:49 +11:00
Shamim Rezaie 426e34af13 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2024-10-18 23:28:37 +11:00
Jun Pataleta 161d14cd92 Merge branch 'MDL-83457-405' of https://github.com/roland04/moodle into MOODLE_405_STABLE 2024-10-17 12:23:19 +08:00
Jun Pataleta 204da574bd Merge branch 'MDL-83443-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-17 12:17:33 +08:00
Jun Pataleta a7f0f4af47 Merge branch 'MDL-83442-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2024-10-17 12:13:29 +08:00
Jun Pataleta cec04e64a1 Merge branch 'MDL-83367-405' of https://github.com/dravek/moodle into MOODLE_405_STABLE 2024-10-17 12:08:48 +08:00
Jun Pataleta 371c836be1 Merge branch 'MDL-81450-MOODLE_405_STABLE' of https://github.com/PhMemmel/moodle into MOODLE_405_STABLE 2024-10-17 12:05:06 +08:00
Huong Nguyen 97f35300f7 Merge branch 'MDL-82580-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-17 10:49:15 +07:00
Jun Pataleta 2870ea8556 Merge branch 'MDL-83143-405' of https://github.com/safatshahin/moodle into MOODLE_405_STABLE 2024-10-17 11:47:11 +08:00
Jun Pataleta 1c2e8c3abb Merge branch 'MDL-82838-main' of https://github.com/justusdieckmann/moodle into MOODLE_405_STABLE 2024-10-17 10:55:17 +08:00
Huong Nguyen 125ff0d462 Merge branch 'MDL-75724-405_toolbrickfield_tableheadercheck' of https://github.com/brickfield/moodle into MOODLE_405_STABLE 2024-10-17 09:44:24 +07:00
Jun Pataleta 23bde28300 Merge branch 'MDL-83002' of https://github.com/marinaglancy/moodle into MOODLE_405_STABLE 2024-10-16 20:33:38 +08:00
Paul Holden f5aa88ec02 MDL-83472 phpunit: add void return type to test methods.
See also 01148a0816 from MDL-81522.
2024-10-16 13:03:50 +01:00
Paul Holden 9f9fa01a91 MDL-83472 phpunit: call parent setUp unit test method.
See also 674497a12c from MDL-81523.
2024-10-16 13:03:21 +01:00
Paul Holden 5bf6da6331 MDL-82809 reportbuilder: always apply conditions to custom report.
Including those that are otherwise unavailable to the current user,
ensuring that they are always applied when viewing report output.
2024-10-16 10:51:42 +01:00
Philipp Memmel 69751fcd69 MDL-81450 mod_forum: Reduce size of file icon in HTML mails
@Co-authored-by: Mateusz Walczak
2024-10-16 11:32:45 +02:00
Paul Holden 5c969d2370 MDL-82475 reportbuilder: account for duplicate profile field names.
Long-term, it would be better to not allow this scenario to happen
at all but until then we'll have to work around it (see MDL-73461).
2024-10-16 09:33:16 +01:00
Paul Holden 7c959f479b MDL-82809 reportbuilder: load custom/profile fields consistently.
Ensure that provided columns and filters for each use appropriate
checks to determine their availability (based on user permissions,
etc), rather than conditionally adding them to the entity.
2024-10-16 08:51:00 +01:00
David Woloszyn d43cec5bb3 MDL-83442 aiprovider_azureai: Correct help string URL 2024-10-16 17:55:09 +11:00
Huong Nguyen a47729dc17 Merge branch 'MDL-83390-405' of https://github.com/roland04/moodle into MOODLE_405_STABLE 2024-10-16 11:09:57 +07:00
Huong Nguyen 8ffd4c4bb1 Merge branch 'MDL-82793-MOODLE_405_STABLE' of https://github.com/phmemmel/moodle into MOODLE_405_STABLE 2024-10-16 09:26:36 +07:00
Philipp Memmel a3ab626df1 MDL-82793 core: Make modal execute JS from template
Co-authored-by: Huong Nguyen <huongnv13@gmail.com>
2024-10-15 20:52:23 +02:00
Paul Holden fd103caa83 MDL-83463 backup: ensure defaults for course file inclusion are read. 2024-10-15 12:27:07 +01:00
Jun Pataleta 12d87a9b65 Merge branch 'MDL-83070_405' of https://github.com/timhunt/moodle into MOODLE_405_STABLE 2024-10-15 19:09:10 +08:00
david adamson cd54f46df1 MDL-82429 tool_brickfield: Process calculated fontsizes 2024-10-15 16:25:54 +07:00
Mikel Martín 49e66dfc5d MDL-83457 mod_feedback: Fix get_incomplete_users early return type
Fix 'feedback_get_incomplete_users' early return when there are no users with
the 'mod/feedback:complete' capability from 'false' to an empty array. That
will follow the function signature.
2024-10-15 09:51:23 +02:00
Mikel Martín c36c98448d MDL-83390 message: Fix category collapse icon
- Replace incorrect 't/collapsedcaret' with 't/collapsed' icon
- Add RTL icon for accessibility
2024-10-15 09:24:11 +02:00
Jun Pataleta 5e7d431426 Merge branch 'MDL-83253-main' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2024-10-15 11:45:43 +08:00
Andrew Nicols 3b4b95d431 MDL-83257 editor_tiny: Disable Alt+F12 keyboard shortcut
This was introduced in Tiny 7.1 to focus notifications, but it conflicts
with the German keyboard layout which uses Alt+F12 to access the open
curly brace.

This is an upstream problem with TinyMCE and should be fixed in a future
release.

The recommended workaround is to disable the shortcut.
2024-10-15 10:33:23 +08:00
Jake Dallimore 42079bb48d MDL-83423 mod_lti: fix JWK decoding when multiple keys missing alg
Related to MDL-77077, but was a case missed there. Now, any unusable
keys (i.e. can't be used during the JWT decode), are dropped from the
keyset if they don't have the 'alg' prop, preventing a 'missing alg'
exception during keyset parsing. Since these cannot be used during
decode, these aren't needed anyway.
2024-10-15 09:11:21 +08:00
AMOS bot c294a22dae Automatically generated installer lang files 2024-10-15 00:09:36 +00:00
Michael Pound bde5487a56 MDL-75724 tool_brickfield: Ensuring correct table headers pass checks. 2024-10-14 16:55:07 +00:00
Marina Glancy c0b2343245 MDL-83430 customfield_number: call display method from provider earlier 2024-10-14 11:39:56 +01:00
Marina Glancy ae500b5728 MDL-83430 customfield_number: fix storing activities number when 0 2024-10-14 11:39:51 +01:00
Huong Nguyen b311baf0bd Merge branch 'MDL-83381-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2024-10-14 11:08:59 +07:00
AMOS bot d1c223071a Automatically generated installer lang files 2024-10-13 00:07:55 +00:00
Paul Holden 14f9c08355 MDL-83443 enrol: use defined role name in welcome message. 2024-10-11 14:35:22 +01:00
Jake Dallimore 9ec7e01527 weekly release 4.5+ 2024-10-11 10:55:02 +08:00
Jake Dallimore ce20b2f255 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2024-10-11 10:54:54 +08:00
Safat 85bd222b2f MDL-83143 core_communication: Behat coverage for default to course name 2024-10-11 11:02:19 +11:00
Safat cf3d932d74 MDL-83143 core_course: Add course name as default for empty room name 2024-10-11 11:02:19 +11:00
Safat 0b47dfec7c MDL-83143: core_communication: Fix variable name typos 2024-10-11 11:02:19 +11:00
Jun Pataleta 8036733091 Merge branch 'MDL-82813-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2024-10-10 12:04:10 +08:00
vietlx426 a74e15c66b MDL-82570 themes: Help boxes not accessible if selected consecutively 2024-10-10 10:52:33 +07:00
Tobias Garske b7e1d77184 MDL-83255 core_course: Fix activitychooser recommended tab navigation 2024-10-10 10:12:28 +07:00
Jun Pataleta 5379d34827 Merge branch 'MDL-82912-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2024-10-10 10:35:02 +08:00
Jun Pataleta 50e813478a Merge branch 'MDL-82812_405_toolbrickfieldfaicons' of https://github.com/brickfield/moodle into MOODLE_405_STABLE 2024-10-10 10:13:40 +08:00
Mikel Martín 4f699801b9 MDL-83283 mod_subsection: Fix subsection completion button margin 2024-10-10 09:08:16 +07:00
David Woloszyn 7beb6d7e82 MDL-83381 AI: Fix OpenAI provider config 2024-10-10 11:53:55 +11:00
Angelia Dela Cruz 1f1406d68c MDL-82912 mod_workshop: Behat to view assessment after workshop close 2024-10-09 16:26:56 +08:00
Huong Nguyen 17924add45 Merge branch 'MDL-83331_405' of https://github.com/timhunt/moodle into MOODLE_405_STABLE 2024-10-09 14:47:00 +07:00
AMOS bot 56293e0de4 Automatically generated installer lang files 2024-10-09 00:09:26 +00:00
Max Larkin 653c0937c6 MDL-82812 tool_brickfield: Ignore fa icons 2024-10-08 13:04:26 +01:00
Bas Brands 9fcb0eca01 MDL-70180 theme_boost: Allow form autoselect modal overflow
Co-authored-by: Mikel Martín <mikel@moodle.com>
2024-10-08 09:36:11 +07:00
AMOS bot ff87bb5101 Automatically generated installer lang files 2024-10-08 00:07:49 +00:00
Paul Holden a271d9efc9 MDL-82580 report_log: preserve filter by individual user. 2024-10-07 20:15:35 +01:00
Paul Holden 3e18e85dce MDL-82813 group: correctly format group description property. 2024-10-07 17:58:34 +01:00
Tim Hunt 92fdfe834f MDL-83331 behat: enable navigation direct to mod/.../index.php 2024-10-07 12:05:09 +01:00
Tim Hunt f7c18e4e4b MDL-83070 question restore: recode links in hints 2024-10-07 11:54:20 +01:00
David Carrillo 2698647bcd MDL-83367 tasks: Apply trim() to pathtophp setting
- It fixes the problem that when "pathtophp" setting is stored with
whitespaces, the "Run now" button will still show up in the tasks list,
but the task will never run
2024-10-07 08:18:13 +02:00
Jun Pataleta 803c3d8977 MDL-83374 upgrade: add the 4.5.0 separation line to all upgrade scripts 2024-10-07 09:34:51 +07:00
Marina Glancy 62e776673a MDL-83002 theme_boost: tell behat to wait when initialising drawers 2024-10-03 15:50:28 +01:00
Mikel Martín 89c30cecd8 MDL-82548 courseformat: Fix courseindex cm anchors
In the course index the course modules links had incorrenct "href" (only the anchor) when
being displayed in a page different than course page. This patch regenerates the href for
cms in the course index when needed.
2024-10-01 11:53:52 +02:00
Andrew Nicols a5ac414521 MDL-83253 core: Ignore invalid components for deprecated cap info
When checking for deprecated capabilty info, if a component is invalid,
skip loading of that component.
2024-09-26 12:34:45 +08:00
Justus Dieckmann 1d848a78cf MDL-82838 tool_mfa: Prevent accidental resubmission of token 2024-08-20 16:46:01 +02:00
876 changed files with 7596 additions and 3106 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ jobs:
- name: Setting up redis service
run: |
choco install redis-64 --version 3.0.503 --no-progress
choco install redis --version 5.0.7 --no-progress
nssm install redis redis-server
nssm start redis
+76
View File
@@ -6,6 +6,82 @@ More detailed information on key changes can be found in the [Developer update n
The format of this change log follows the advice given at [Keep a CHANGELOG](https://keepachangelog.com).
## 4.5.1
### core
#### Added
- `\core\output\activity_header` now uses the `is_title_allowed()` method when setting the title in the constructor.
This method has been improved to give priority to the 'notitle' option in the theme config for the current page layout, over the top-level option in the theme.
For example, the Boost theme sets `$THEME->activityheaderconfig['notitle'] = true;` by default, but in its `secure` pagelayout, it has `'notitle' = false`.
This prevents display of the title in all layouts except `secure`.
For more information see [MDL-75610](https://tracker.moodle.org/browse/MDL-75610)
#### Changed
- All uses of the following PHPUnit methods have been removed as these methods are
deprecated upstream without direct replacement:
- `withConsecutive`
- `willReturnConsecutive`
- `onConsecutive`
Any plugin using these methods must update their uses.
For more information see [MDL-81308](https://tracker.moodle.org/browse/MDL-81308)
### core_courseformat
#### Added
- Add core_courseformat\base::invalidate_all_session_caches to reset course editor cache for all users when course is changed. This method can be used as an alternative to core_courseformat\base::session_cache_reset for resetting the cache for the current user in case the change in the course should be reflected for all users.
For more information see [MDL-83185](https://tracker.moodle.org/browse/MDL-83185)
### core_enrol
#### Changed
- The `after_user_enrolled` hook now contains a `roleid` property to allow for listeners to determine which role was assigned during user enrolment (if any)
The base enrolment `enrol_plugin::send_course_welcome_message_to_user` method also now accepts a `$roleid` parameter in order to correctly populate the `courserole` placeholder
For more information see [MDL-83432](https://tracker.moodle.org/browse/MDL-83432)
### core_form
#### Changed
- The `cohort` form element now accepts new `includes` option, which is passed to the corresponding external service to determine which cohorts to return (self, parents, all)
For more information see [MDL-83641](https://tracker.moodle.org/browse/MDL-83641)
### core_reportbuilder
#### Changed
- The `get_active_conditions` method of the base report class has a new `$checkavailable` parameter to determine whether to check the returned conditions availability
For more information see [MDL-82809](https://tracker.moodle.org/browse/MDL-82809)
### mod_quiz
#### Changed
- The `\mod_quiz\attempt_walkthrough_from_csv_test` unit test has been marked as final and should not be extended by other tests.
All shared functionality has been moved to a new autoloadable test-case:
`\mod_quiz\tests\attempt_walkthrough_testcase`.
To support this testcase the existing `$files` instance property should be replaced with a new static method, `::get_test_files`.
Both the existing instance property and the new static method can co-exist.
For more information see [MDL-81521](https://tracker.moodle.org/browse/MDL-81521)
## 4.5
### core
@@ -105,10 +105,9 @@ class task_log extends base {
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$tablealias}.classname, {$tablealias}.id")
->add_field("{$tablealias}.classname")
->set_is_sortable(true)
->add_callback(static function($value, stdClass $row): string {
$classname = $row->classname;
->add_callback(static function(string $classname): string {
$output = '';
if (class_exists($classname)) {
$task = new $classname;
@@ -119,7 +118,6 @@ class task_log extends base {
$output .= \html_writer::tag('div', "\\{$classname}", [
'class' => 'small text-muted',
]);
$output = \html_writer::link(new \moodle_url('/admin/tasklogs.php', ['logid' => $row->id]), $output);
return $output;
});
@@ -20,10 +20,12 @@ use context_system;
use core_admin\reportbuilder\local\entities\task_log;
use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\report\action;
use core_reportbuilder\system_report;
use html_writer;
use lang_string;
use moodle_url;
use pix_icon;
use core_reportbuilder\system_report;
use stdClass;
/**
* Task logs system report class implementation
@@ -89,7 +91,9 @@ class task_logs extends system_report {
* unique identifier
*/
public function add_columns(): void {
$columns = [
$entitymainalias = $this->get_entity('task_log')->get_table_alias('task_log');
$this->add_columns_from_entities([
'task_log:name',
'task_log:type',
'user:fullname',
@@ -99,14 +103,18 @@ class task_logs extends system_report {
'task_log:pid',
'task_log:database',
'task_log:result',
];
]);
$this->add_columns_from_entities($columns);
// Wrap the task name in a link.
$this->get_column('task_log:name')
->add_field("{$entitymainalias}.id")
->add_callback(static function(string $output, stdClass $row): string {
return html_writer::link(new moodle_url('/admin/tasklogs.php', ['logid' => $row->id]), $output);
});
// 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'));
}
// Rename the user fullname column.
$this->get_column('user:fullname')
->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);
@@ -119,16 +127,14 @@ class task_logs extends system_report {
* unique identifier
*/
protected function add_filters(): void {
$filters = [
$this->add_filters_from_entities([
'task_log:name',
'task_log:type',
'task_log:output',
'task_log:result',
'task_log:timestart',
'task_log:duration',
];
$this->add_filters_from_entities($filters);
]);
}
/**
+195
View File
@@ -4703,4 +4703,199 @@
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="5.0" requires="4.2.3">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="10.11.0" />
<VENDOR name="mysql" version="8.4" />
<VENDOR name="postgres" version="14" />
<VENDOR name="mssql" version="14.0" />
<VENDOR name="oracle" version="19" />
</DATABASE>
<PHP version="8.2.0" level="required">
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="required">
<FEEDBACK>
<ON_ERROR message="mbstringrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
<PHP_EXTENSION name="sodium" level="required"/>
<PHP_EXTENSION name="exif" level="optional"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
<FEEDBACK>
<ON_ERROR message="sixtyfourbitsrequired" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
<FEEDBACK>
<ON_CHECK message="iscustomadminwarnings" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+1 -1
View File
@@ -180,7 +180,7 @@ class generator_test extends \advanced_testcase {
*
* @return array
*/
public function create_preset_provider(): array {
public static function create_preset_provider(): array {
return [
'Default values' => [
],
+6 -6
View File
@@ -84,7 +84,7 @@ class helper_test extends \advanced_testcase {
*
* @return array
*/
public function create_preset_provider(): array {
public static function create_preset_provider(): array {
return [
'Default values' => [
],
@@ -177,7 +177,7 @@ class helper_test extends \advanced_testcase {
*
* @return array
*/
public function add_item_provider(): array {
public static function add_item_provider(): array {
return [
'Setting without plugin' => [
'name' => 'settingname',
@@ -239,7 +239,7 @@ class helper_test extends \advanced_testcase {
*
* @return array
*/
public function add_plugin_provider(): array {
public static function add_plugin_provider(): array {
return [
'Plugin: enabled (using int)' => [
'type' => 'plugintype',
@@ -321,7 +321,7 @@ class helper_test extends \advanced_testcase {
*
* @return array
*/
public function change_default_preset_provider(): array {
public static function change_default_preset_provider(): array {
return [
'Starter preset' => [
'preset' => 'starter',
@@ -364,7 +364,7 @@ class helper_test extends \advanced_testcase {
'preset' => 'unexisting',
],
'Valid XML file' => [
'preset' => __DIR__ . '/fixtures/import_settings_plugins.xml',
'preset' => self::get_fixture_path(__NAMESPACE__, 'import_settings_plugins.xml'),
'settings' => [
'allowemojipicker' => 1,
'enableportfolios' => 1,
@@ -377,7 +377,7 @@ class helper_test extends \advanced_testcase {
],
],
'Invalid XML file' => [
'preset' => __DIR__ . '/fixtures/invalid_xml_file.xml',
'preset' => self::get_fixture_path(__NAMESPACE__, 'invalid_xml_file.xml'),
],
'Unexisting XML file' => [
'preset' => __DIR__ . '/fixtures/unexisting.xml',
@@ -72,7 +72,7 @@ class adminpresets_admin_setting_bloglevel_test extends \advanced_testcase {
*
* @return array
*/
public function save_value_provider(): array {
public static function save_value_provider(): array {
return [
'Save the bloglevel and set blog_menu block visibility to true' => [
'setttingvalue' => BLOG_USER_LEVEL,
@@ -66,7 +66,7 @@ class adminpresets_admin_setting_sitesettext_test extends \advanced_testcase {
*
* @return array
*/
public function save_value_provider(): array {
public static function save_value_provider(): array {
return [
'Fullname: different value' => [
'settingname' => 'fullname',
@@ -77,7 +77,7 @@ class adminpresets_setting_test extends \advanced_testcase {
*
* @return array
*/
public function save_value_provider(): array {
public static function save_value_provider(): array {
return [
'Core setting with the same value is not saved' => [
'category' => 'optionalsubsystems',
@@ -167,7 +167,7 @@ class adminpresets_setting_test extends \advanced_testcase {
*
* @return array
*/
public function save_attributes_values_provider(): array {
public static function save_attributes_values_provider(): array {
return [
'Plugin setting with the same value is not saved' => [
'category' => 'modsettinglesson',
+23 -10
View File
@@ -368,7 +368,7 @@ class manager_test extends \advanced_testcase {
*
* @return array
*/
public function export_preset_provider(): array {
public static function export_preset_provider(): array {
return [
'Export settings and plugins, excluding sensible' => [
'includesensible' => false,
@@ -531,26 +531,32 @@ class manager_test extends \advanced_testcase {
*
* @return array
*/
public function import_preset_provider(): array {
public static function import_preset_provider(): array {
return [
'Import settings from an empty file' => [
'filecontents' => '',
'expectedpreset' => false,
],
'Import settings and plugins from a valid XML file' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_plugins.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings_plugins.xml')
),
'expectedpreset' => true,
'expectedsettings' => true,
'expectedplugins' => true,
],
'Import only settings from a valid XML file' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings.xml')
),
'expectedpreset' => true,
'expectedsettings' => true,
'expectedplugins' => false,
],
'Import settings and plugins from a valid XML file with Starter name, which will be marked as non-core' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_starter_name.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'import_starter_name.xml')
),
'expectedpreset' => true,
'expectedsettings' => true,
'expectedplugins' => true,
@@ -559,7 +565,9 @@ class manager_test extends \advanced_testcase {
'expectedpresetname' => 'Starter',
],
'Import settings from an invalid XML file' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/invalid_xml_file.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'invalid_xml_file.xml')
),
'expectedpreset' => false,
'expectedsettings' => false,
'expectedplugins' => false,
@@ -567,20 +575,26 @@ class manager_test extends \advanced_testcase {
'expectedexception' => \Exception::class,
],
'Import unexisting settings category' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_category.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'unexisting_category.xml')
),
'expectedpreset' => false,
'expectedsettings' => false,
'expectedplugins' => false,
],
'Import unexisting setting' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_setting.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'unexisting_setting.xml')
),
'expectedpreset' => false,
'expectedsettings' => false,
'expectedplugins' => false,
'expecteddebugging' => true,
],
'Import valid settings with one unexisting setting too' => [
'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_with_unexisting_setting.xml'),
'filecontents' => file_get_contents(
filename: self::get_fixture_path(__NAMESPACE__, 'import_settings_with_unexisting_setting.xml'),
),
'expectedpreset' => true,
'expectedsettings' => false,
'expectedplugins' => false,
@@ -589,7 +603,6 @@ class manager_test extends \advanced_testcase {
];
}
/**
* Test the behaviour of delete_preset() method when the preset id doesn't exist.
*
+1 -1
View File
@@ -84,7 +84,7 @@ class preset_test extends \advanced_testcase {
public function test_mixed_levels(): void {
// The problem here is that we cannot guarantee plugin contexts
// have unique short names, so we have to also support level numbers.
$xml = file_get_contents(__DIR__ . '/fixtures/mixed_levels.xml');
$xml = file_get_contents(self::get_fixture_path(__NAMESPACE__, 'mixed_levels.xml'));
$this->assertTrue(\core_role_preset::is_valid_preset($xml));
$preset = \core_role_preset::parse_preset($xml);
+24 -1
View File
@@ -420,6 +420,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
new lang_string('generalgroups', 'backup'), new lang_string('configgeneralgroups', 'backup'),
array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), array('value'=>1, 'locked'=>0)));
$temp->add(new admin_setting_configcheckbox_with_lock(
'backup/backup_general_customfield',
new lang_string('generalcustomfield', 'backup'),
new lang_string('configgeneralcustomfield', 'backup'),
['value' => 1, 'locked' => 0],
));
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_contentbankcontent',
new lang_string('generalcontentbankcontent', 'backup'),
new lang_string('configgeneralcontentbankcontent', 'backup'),
@@ -431,7 +437,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
['value' => 1, 'locked' => 0])
);
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_general_legacyfiles',
new lang_string('generallegacyfiles', 'backup'),
new lang_string('configlegacyfiles', 'backup'), array('value' => 1, 'locked' => 0)));
@@ -460,6 +465,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
new lang_string('generalgroups', 'backup'), new lang_string('configgeneralgroups', 'backup'),
array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock('backup/backup_import_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), array('value'=>1, 'locked'=>0)));
$temp->add(new admin_setting_configcheckbox_with_lock(
'backup/backup_import_customfield',
new lang_string('generalcustomfield', 'backup'),
new lang_string('configgeneralcustomfield', 'backup'),
['value' => 1, 'locked' => 0],
));
$temp->add(new admin_setting_configcheckbox_with_lock(
'backup/backup_import_contentbankcontent',
new lang_string('generalcontentbankcontent', 'backup'),
@@ -589,6 +600,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_groups', new lang_string('generalgroups', 'backup'),
new lang_string('configgeneralgroups', 'backup'), 1));
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_competencies', new lang_string('generalcompetencies','backup'), new lang_string('configgeneralcompetencies','backup'), 1));
$temp->add(new admin_setting_configcheckbox(
'backup/backup_auto_customfield',
new lang_string('generalcustomfield', 'backup'),
new lang_string('configgeneralcustomfield', 'backup'),
1,
));
$temp->add(new admin_setting_configcheckbox(
'backup/backup_auto_contentbankcontent',
new lang_string('generalcontentbankcontent', 'backup'),
@@ -668,6 +685,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_competencies',
new lang_string('generalcompetencies', 'backup'),
new lang_string('configrestorecompetencies', 'backup'), array('value' => 1, 'locked' => 0)));
$temp->add(new admin_setting_configcheckbox_with_lock(
'restore/restore_general_customfield',
new lang_string('generalcustomfield', 'backup'),
new lang_string('configrestorecustomfield', 'backup'),
['value' => 1, 'locked' => 0],
));
$temp->add(new admin_setting_configcheckbox_with_lock('restore/restore_general_contentbankcontent',
new lang_string('generalcontentbankcontent', 'backup'),
new lang_string('configrestorecontentbankcontent', 'backup'), array('value' => 1, 'locked' => 0)));
+1 -1
View File
@@ -85,7 +85,7 @@ class set_block_protection_test extends \externallib_advanced_testcase {
*
* @return array
*/
public function execute_provider(): array {
public static function execute_provider(): array {
return [
[
'block_login',
+2 -2
View File
@@ -72,7 +72,7 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
*
* @return array
*/
public function execute_editor_provider(): array {
public static function execute_editor_provider(): array {
$pluginmanager = \core_plugin_manager::instance();
$allplugins = array_keys($pluginmanager->get_plugins_of_type('editor'));
@@ -142,7 +142,7 @@ class set_plugin_order_test extends \externallib_advanced_testcase {
$this->assertIsArray(set_plugin_order::execute($plugin, 1));
}
public function execute_non_orderable_provider(): array {
public static function execute_non_orderable_provider(): array {
return [
// Activities do not support ordering.
['mod_assign'],
+1 -1
View File
@@ -66,7 +66,7 @@ class set_plugin_state_test extends \externallib_advanced_testcase {
*
* @return array
*/
public function execute_standard_provider(): array {
public static function execute_standard_provider(): array {
$generatetestsfor = function (string $plugin): array {
return [
[
@@ -110,7 +110,7 @@ class task_logs_test extends core_reportbuilder_testcase {
*
* @return array[]
*/
public function datasource_filters_provider(): array {
public static function datasource_filters_provider(): array {
return [
'Filter name' => ['task_log:name', [
'task_log:name_values' => [send_schedules::class],
@@ -70,7 +70,7 @@ class base_test extends \advanced_testcase {
*
* @return array
*/
public function log_provider(): array {
public static function log_provider(): array {
return [
// Action = base.
'action=base and mode = show' => [
@@ -156,7 +156,7 @@ class export_test extends \advanced_testcase {
*
* @return array
*/
public function export_execute_provider(): array {
public static function export_execute_provider(): array {
return [
'Export settings and plugins, excluding sensible' => [
'includesensible' => false,
@@ -190,7 +190,7 @@ class import_test extends \advanced_testcase {
*
* @return array
*/
public function import_execute_provider(): array {
public static function import_execute_provider(): array {
$fixturesfolder = __DIR__ . '/../../../../../presets/tests/fixtures/';
return [
@@ -0,0 +1,61 @@
@tool @tool_behat
Feature: Frozen clock in Behat
In order to write tests that depend on the current system time
As a test writer
I need to set the time using a Behat step
Background:
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
And the following "activities" exist:
| activity | course | name | idnumber | externalurl |
| url | C1 | Fixture | url1 | #wwwroot#/admin/tool/behat/tests/fixtures/core/showtime.php |
| forum | C1 | TestForum | forum1 | |
Scenario: Time has been frozen
# Set up 2 forum discussions at different times. This tests the clock in the Behat CLI process.
Given the time is frozen at "2024-03-01 12:34:56"
And the following "mod_forum > discussions" exist:
| user | forum | name | message |
| admin | forum1 | Subject1 | Message1 |
And the time is frozen at "2024-08-01 12:34:56"
And the following "mod_forum > discussions" exist:
| user | forum | name | message |
| admin | forum1 | Subject2 | Message2 |
When I am on the "TestForum" "forum activity" page logged in as admin
Then I should see "1 Mar 2024" in the "Subject1" "table_row"
And I should see "1 Aug 2024" in the "Subject2" "table_row"
# Also view time on the fixture page. This tests the clock for Behat web server requests.
And I am on the "Fixture" "url activity" page
And I should see "Behat time is not the same as real time"
# This Unix time corresponds to 12:34:56 in Perth time zone.
And I should see "Unix time 1722486896"
And I should see "Date-time 2024-08-01 12:34:56"
# This scenario is second, to verify that the clock automatically goes back to normal after test.
Scenario: Time is normal
Given the following "mod_forum > discussions" exist:
| user | forum | name | message |
| admin | forum1 | Subject1 | Message1 |
When I am on the "TestForum" "forum activity" page logged in as admin
# The time should be the real current time, not the frozen time.
Then I should see "## today ##%d %b %Y##" in the "Subject1" "table_row"
And I am on the "Fixture" "url activity" page
And I should see "Behat time is the same as real time"
Scenario: Time is frozen and then unfrozen
Given the time is frozen at "2024-03-01 12:34:56"
And the following "mod_forum > discussions" exist:
| user | forum | name | message |
| admin | forum1 | Subject1 | Message1 |
And the time is no longer frozen
And the following "mod_forum > discussions" exist:
| user | forum | name | message |
| admin | forum1 | Subject2 | Message2 |
When I am on the "TestForum" "forum activity" page logged in as admin
Then I should see "1 Mar 2024" in the "Subject1" "table_row"
# The time should be the real current time, not the frozen time for this entry.
And I should see "## today ##%d %b %Y##" in the "Subject2" "table_row"
And I am on the "Fixture" "url activity" page
And I should see "Behat time is the same as real time"
@@ -53,7 +53,7 @@ class behat_form_text_test extends \basic_testcase {
*
* @return array of value and expectation pairs to be tested.
*/
public function provider_test_set_get_value() {
public static function provider_test_set_get_value(): array {
return [
'null' => [null, null],
'int' => [3, 3],
@@ -68,7 +68,7 @@ class behat_form_text_test extends \basic_testcase {
*
* @param mixed $value value to be set.
* @param mixed $expectation value to be checked.
* @dataProvider provider_test_set_get_value()
* @dataProvider provider_test_set_get_value
*/
public function test_set_get_value($value, $expectation): void {
$session = $this->createMock(Session::class);
@@ -85,7 +85,7 @@ class behat_form_text_test extends \basic_testcase {
*
* @return array of decsep, value, match and result pairs to be tested.
*/
public function provider_test_matches() {
public static function provider_test_matches(): array {
return [
'lazy true' => ['.', 'hello', 'hello', true],
'lazy false' => ['.', 'hello', 'bye', false],
@@ -113,7 +113,7 @@ class behat_form_text_test extends \basic_testcase {
* @param mixed $value value to be set.
* @param mixed $match value to be matched.
* @param bool $result expected return status of the function.
* @dataProvider provider_test_matches()
* @dataProvider provider_test_matches
*/
public function test_matches($decsep, $value, $match, $result): void {
global $CFG;
+52
View File
@@ -0,0 +1,52 @@
<?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/>.
/**
* Fixture to show the current server time using \core\clock.
*
* @package tool_behat
* @copyright 2024 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// phpcs:disable moodle.Files.RequireLogin.Missing
require(__DIR__ . '/../../../../../../config.php');
defined('BEHAT_SITE_RUNNING') || die('Behat fixture');
$PAGE->set_context(\context_system::instance());
$PAGE->set_url(new \moodle_url('/admin/tool/behat/tests/fixtures/core/showtime.php'));
echo $OUTPUT->header();
$clock = \core\di::get(\core\clock::class);
$dt = $clock->now();
$realbefore = time();
$time = $clock->time();
$realafter = time();
echo html_writer::div('Unix time ' . $time);
echo html_writer::div('Date-time ' . $dt->format('Y-m-d H:i:s'));
echo html_writer::div('TZ ' . $dt->getTimezone()->getName());
if ($time >= $realbefore && $time <= $realafter) {
echo html_writer::div('Behat time is the same as real time');
} else {
echo html_writer::div('Behat time is not the same as real time');
}
echo $OUTPUT->footer();
+5 -5
View File
@@ -107,11 +107,11 @@ class manager_util_test extends \advanced_testcase {
*/
private function get_behat_config_util($behatconfigutil, $notheme = false) {
// Create a map of arguments to return values.
$map = array(
array('withfeatures', __DIR__.'/fixtures/theme/withfeatures'),
array('nofeatures', __DIR__.'/fixtures/theme/nofeatures'),
array('defaulttheme', __DIR__.'/fixtures/theme/defaulttheme'),
);
$map = [
['withfeatures', self::get_fixture_path(__NAMESPACE__, 'theme/withfeatures')],
['nofeatures', self::get_fixture_path(__NAMESPACE__, 'theme/nofeatures')],
['defaulttheme', self::get_fixture_path(__NAMESPACE__, 'theme/defaulttheme')],
];
// List of themes is const for test.
if ($notheme) {
$themelist = array('defaulttheme');
@@ -410,13 +410,13 @@ class brickfield_accessibility_color_test extends brickfield_accessibility_test
$pos3 = stripos($fontsize, 'px');
if ($pos1 !== false) {
$rem = substr($fontsize, 0, -3);
$newfontsize = $newfontsize * $rem;
$newfontsize = is_numeric($rem) ? $newfontsize * $rem : $newfontsize;
} else if ($pos2 !== false) {
$em = substr($fontsize, 0, -2);
$newfontsize = $newfontsize * $em;
$newfontsize = is_numeric($em) ? $newfontsize * $em : $newfontsize;
} else if ($pos3 !== false) {
$px = substr($fontsize, 0, -2);
$newfontsize = 0.75 * $px;
$newfontsize = is_numeric($px) ? 0.75 * $px : $newfontsize;
} else if (in_array($fontsize, array_keys($this->fontsizenames))) {
$newfontsize = $this->fontsizenames[$fontsize];
} else {
@@ -16,7 +16,7 @@
namespace tool_brickfield\local\htmlchecker\common\checks;
use tool_brickfield\local\htmlchecker\common\brickfield_accessibility_tag_test;
use tool_brickfield\local\htmlchecker\common\brickfield_accessibility_test;
/**
* Brickfield accessibility HTML checker library.
@@ -28,11 +28,25 @@ use tool_brickfield\local\htmlchecker\common\brickfield_accessibility_tag_test;
* @copyright 2020 onward: Brickfield Education Labs, www.brickfield.ie
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class i_is_not_used extends brickfield_accessibility_tag_test {
class i_is_not_used extends brickfield_accessibility_test {
/** @var int The default severity code for this test. */
public $defaultseverity = \tool_brickfield\local\htmlchecker\brickfield_accessibility::BA_TEST_SEVERE;
/** @var string The tag this test will fire on. */
public $tag = 'i';
/**
* Check for any i elements and flag them as errors
* while allowing font awesome icons to be used.
*/
public function check(): void {
foreach ($this->get_all_elements('i') as $element) {
// Ensure this is not a font awesome icon with aria-hidden.
if (str_contains($element->getAttribute('class'), 'fa-') && $element->getAttribute('aria-hidden') === 'true') {
continue;
}
$this->add_report($element);
}
}
}
@@ -46,7 +46,7 @@ class table_data_should_have_th extends brickfield_accessibility_table_test {
foreach ($tr->childNodes as $th) {
if ($this->property_is_equal($th, 'tagName', 'th')) {
break 3;
} else {
} else if ($th->nodeName !== '#text') {
$this->add_report($table);
break 3;
}
@@ -57,7 +57,7 @@ class table_data_should_have_th extends brickfield_accessibility_table_test {
foreach ($child->childNodes as $th) {
if ($this->property_is_equal($th, 'tagName', 'th')) {
break 2;
} else {
} else if ($th->nodeName !== '#text') {
$this->add_report($table);
break 2;
}
@@ -32,7 +32,7 @@ require_once('all_checks.php');
* Class test_css_text_has_contrast_test
* @covers \tool_brickfield\local\htmlchecker\brickfield_accessibility
*/
class css_text_has_contrast_test extends all_checks {
final class css_text_has_contrast_test extends all_checks {
/** @var string The check type. */
protected $checktype = 'css_text_has_contrast';
@@ -227,6 +227,18 @@ EOD;
This is contrasty enough.</p></body>
EOD;
/** @var string HTML with calculated size colour values. */
private $calculatedfail = <<<EOD
<body><p style="color:#EF0000; background-color:white; font-size: calc(0.90375rem + 0.045vw)">
This is not contrasty enough.</p></body>
EOD;
/** @var string HTML with calculated size colour values. */
private $calculatedpass = <<<EOD
<body><p style="color:#E60000; background-color:white; font-size: calc(0.90375rem + 0.045vw);">
This is contrasty enough.</p></body>
EOD;
/**
* Test for the area assign intro
*/
@@ -458,4 +470,20 @@ EOD;
$results = $this->get_checker_results($html);
$this->assertEmpty($results);
}
/**
* Test for calculated (12pt) text with insufficient contrast of 4.49.
*/
public function test_check_for_calculated_fail(): void {
$results = $this->get_checker_results($this->calculatedfail);
$this->assertTrue($results[0]->element->tagName == 'p');
}
/**
* Test for calculated (12pt) text with sufficient contrast of 4.81.
*/
public function test_check_for_calculated_pass(): void {
$results = $this->get_checker_results($this->calculatedpass);
$this->assertEmpty($results);
}
}
@@ -30,6 +30,8 @@ require_once('all_checks.php');
/**
* Class i_is_not_used_testcase
*
* @covers \tool_brickfield\local\htmlchecker\common\checks\i_is_not_used
*/
class i_is_not_used_test extends all_checks {
/** @var string Check type */
@@ -71,4 +73,13 @@ EOD;
$results = $this->get_checker_results($this->htmlpass);
$this->assertEmpty($results);
}
/**
* Test for font awesome icon.
*/
public function test_fa_icon(): void {
$html = '<div><i class="fa fa-user"></i><i>Hello there</i><i class="fa fa-address-book" aria-hidden="true"></i></div>';
$results = $this->get_checker_results($html);
$this->assertCount(2, $results);
}
}
@@ -30,6 +30,8 @@ require_once('all_checks.php');
/**
* Class table_data_should_have_th_test
*
* @covers \tool_brickfield\local\htmlchecker\common\checks\table_data_should_have_th
*/
class table_data_should_have_th_test extends all_checks {
/** @var string Check type */
@@ -113,6 +115,117 @@ EOD;
</table>
</body>
</html>
EOD;
/** @var string HTML that should not get flagged. */
private $htmlpass3 = <<<EOD
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Table should have at least one th - pass</title>
</head>
<body>
<table>
<thead>
<tr>
<th>
This is table heading
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
This is a tables data
</td>
</tr>
</tbody>
</table>
</body>
</html>
EOD;
/** @var string HTML that should not get flagged. */
private $htmlpass4 = <<<EOD
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Table should have at least one th - pass</title>
</head>
<body>
<table>
<tr>
<th>
This is table heading
</th>
</tr>
<tr>
<td>
This is a tables data
</td>
</tr>
</table>
</body>
</html>
EOD;
/** @var string HTML that should not get flagged. */
private $htmlpass5 = <<<EOD
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Table should have at least one th - pass</title>
</head>
<body>
<table>
<thead>
<tr>
<th>
This is table heading
</th>
</tr>
</thead>
<tbody>
<tr>
<th>
This is a table heading in table data
</th>
</tr>
<tr>
<td>
This is a tables data
</td>
</tr>
</tbody>
</table>
</body>
</html>
EOD;
/** @var string HTML that should not get flagged. */
private $htmlpass6 = <<<EOD
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Table should have at least one th - pass</title>
</head>
<body>
<table>
<tbody>
<tr>
<th>
This is a table heading in table data
</th>
</tr>
<tr>
<td>
This is a tables data
</td>
</tr>
</tbody>
</table>
</body>
</html>
EOD;
/**
* Test that th does not exist
@@ -134,5 +247,17 @@ EOD;
$results = $this->get_checker_results($this->htmlpass2);
$this->assertEmpty($results);
$results = $this->get_checker_results($this->htmlpass3);
$this->assertEmpty($results);
$results = $this->get_checker_results($this->htmlpass4);
$this->assertEmpty($results);
$results = $this->get_checker_results($this->htmlpass5);
$this->assertEmpty($results);
$results = $this->get_checker_results($this->htmlpass6);
$this->assertEmpty($results);
}
}
+5 -5
View File
@@ -30,7 +30,7 @@ use tool_brickfield\local\tool\tool;
class tool_test extends \advanced_testcase {
/** @var string base 64 image */
protected $base64img = <<<EOF
protected static string $base64img = <<<EOF
<img src="data:image/gif;base64,R0lGODlhPQBEAPeoAJosM//AwO/AwHVYZ/z595kzAP/s7P+goOXMv8+fhw/v739/f+8PD98fH/
8mJl+fn/9ZWb8/PzWlwv///6wWGbImAPgTEMImIN9gUFCEm/gDALULDN8PAD6atYdCTX9gUNKlj8wZAKUsAOzZz+UMAOsJAP/Z2ccMDA8PD/95eX5N
WvsJCOVNQPtfX/8zM8+QePLl38MGBr8JCP+zs9myn/8GBqwpAP/GxgwJCPny78lzYLgjAJ8vAP9fX/+MjMUcAN8zM/9wcM8ZGcATEL+QePdZWf/29u
@@ -118,11 +118,11 @@ EOF;
* Base64 image provider.
* @return array
*/
public function base64_img_provider(): array {
public static function base64_img_provider(): array {
$img = '<img src="myimage.jpg" />';
return [
'Image tag alone (base64)' => [
$this->base64img,
self::$base64img,
true,
],
'Image tag alone (link)' => [
@@ -130,7 +130,7 @@ EOF;
false,
],
'Image tag in string (base64)' => [
"This is my image {$this->base64img}.",
"This is my image " . self::$base64img,
true,
],
'Image tag in string (link)' => [
@@ -162,7 +162,7 @@ EOF;
}
public function test_truncate_base64(): void {
$truncated = tool::truncate_base64($this->base64img);
$truncated = tool::truncate_base64(self::$base64img);
$this->assertStringContainsString('<img src="data:image/gif;base64..."', $truncated);
}
}
@@ -63,11 +63,9 @@ class assign_role_cohort extends moodleform {
$mform->addElement('select', 'roleid', get_string('selectrole', 'tool_cohortroles'), $options);
$mform->addRule('roleid', null, 'required');
$context = context_system::instance();
$options = array(
'multiple' => true,
'data-contextid' => $context->id,
'data-includes' => 'all'
'includes' => 'all',
);
$mform->addElement('cohort', 'cohortids', get_string('selectcohorts', 'tool_cohortroles'), $options);
$mform->addRule('cohortids', null, 'required');
+3
View File
@@ -51,5 +51,8 @@ function xmldb_tool_cohortroles_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+3
View File
@@ -36,5 +36,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -60,7 +60,7 @@ class langstring_test extends advanced_testcase {
*
* @return array
*/
public function fix_syntax_data(): array {
public static function fix_syntax_data(): array {
return [
// Syntax sanity v1 strings.
[
@@ -79,7 +79,7 @@ class phpparser_test extends advanced_testcase {
*
* @return array
*/
public function parse_provider(): array {
public static function parse_provider(): array {
return [
'Invalid PHP code' => [
'No PHP code', [], false
+3
View File
@@ -106,5 +106,8 @@ function xmldb_tool_dataprivacy_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+8 -8
View File
@@ -633,7 +633,7 @@ class api_test extends \advanced_testcase {
*
* @return array
*/
public function data_request_creation_provider() {
public static function data_request_creation_provider(): array {
return [
'Export request by user, automatic approval off' => [
false, api::DATAREQUEST_TYPE_EXPORT, 'automaticdataexportapproval', false, 0,
@@ -815,7 +815,7 @@ class api_test extends \advanced_testcase {
*
* @return array
*/
public function get_data_requests_provider() {
public static function get_data_requests_provider(): array {
$completeonly = [api::DATAREQUEST_STATUS_COMPLETE, api::DATAREQUEST_STATUS_DOWNLOAD_READY, api::DATAREQUEST_STATUS_DELETED];
$completeandcancelled = array_merge($completeonly, [api::DATAREQUEST_STATUS_CANCELLED]);
@@ -1000,7 +1000,7 @@ class api_test extends \advanced_testcase {
/**
* Data provider for test_has_ongoing_request.
*/
public function status_provider() {
public static function status_provider(): array {
return [
[api::DATAREQUEST_STATUS_AWAITING_APPROVAL, true],
[api::DATAREQUEST_STATUS_APPROVED, true],
@@ -1090,7 +1090,7 @@ class api_test extends \advanced_testcase {
*
* @return array
*/
public function notify_dpo_provider() {
public static function notify_dpo_provider(): array {
return [
[false, api::DATAREQUEST_TYPE_EXPORT, 'requesttypeexport', 'Export my user data'],
[false, api::DATAREQUEST_TYPE_DELETE, 'requesttypedelete', 'Delete my user data'],
@@ -1442,7 +1442,7 @@ class api_test extends \advanced_testcase {
/**
* Data provider for invalid contextlevel fetchers.
*/
public function invalid_effective_contextlevel_provider() {
public static function invalid_effective_contextlevel_provider(): array {
return [
[CONTEXT_COURSECAT],
[CONTEXT_COURSE],
@@ -2002,7 +2002,7 @@ class api_test extends \advanced_testcase {
/**
* Data provider for \tool_dataprivacy_api_testcase::test_set_context_defaults
*/
public function set_context_defaults_provider() {
public static function set_context_defaults_provider(): array {
$contextlevels = [
[CONTEXT_COURSECAT],
[CONTEXT_COURSE],
@@ -2477,7 +2477,7 @@ class api_test extends \advanced_testcase {
*
* @return array
*/
public function queue_data_request_task_provider() {
public static function queue_data_request_task_provider(): array {
return [
'With user ID provided' => [true],
'Without user ID provided' => [false],
@@ -2514,7 +2514,7 @@ class api_test extends \advanced_testcase {
/**
* Data provider for test_is_automatic_request_approval_on().
*/
public function automatic_request_approval_setting_provider() {
public static function automatic_request_approval_setting_provider(): array {
return [
'Data export, not set' => [
'automaticdataexportapproval', api::DATAREQUEST_TYPE_EXPORT, null, false
@@ -35,7 +35,7 @@ class data_request_test extends data_privacy_testcase {
*
* @return array
*/
public function status_state_provider(): array {
public static function status_state_provider(): array {
return [
[
'state' => api::DATAREQUEST_STATUS_PENDING,
@@ -138,9 +138,9 @@ class data_request_test extends data_privacy_testcase {
*
* @return array
*/
public function non_resettable_provider(): array {
public static function non_resettable_provider(): array {
$states = [];
foreach ($this->status_state_provider() as $thisstatus) {
foreach (self::status_state_provider() as $thisstatus) {
if (!$thisstatus['resettable']) {
$states[] = $thisstatus;
}
@@ -1370,12 +1370,20 @@ class expired_contexts_test extends \advanced_testcase {
])
->getMock();
$mockprivacymanager->expects($this->atLeastOnce())->method('delete_data_for_user');
$mockprivacymanager->expects($this->exactly(2))
$deleteinvocations = $this->exactly(2);
$mockprivacymanager->expects($deleteinvocations)
->method('delete_data_for_all_users_in_context')
->withConsecutive(
[$blockcontext],
[$usercontext]
);
->willReturnCallback(function ($context) use (
$deleteinvocations,
$blockcontext,
$usercontext,
): void {
match (self::getInvocationCount($deleteinvocations)) {
1 => $this->assertEquals($blockcontext, $context),
2 => $this->assertEquals($usercontext, $context),
default => $this->fail('Unexpected invocation count'),
};
});
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
->onlyMethods(['get_privacy_manager'])
@@ -1588,12 +1596,20 @@ class expired_contexts_test extends \advanced_testcase {
])
->getMock();
$mockprivacymanager->expects($this->atLeastOnce())->method('delete_data_for_user');
$mockprivacymanager->expects($this->exactly(2))
$deleteinvocations = $this->exactly(2);
$mockprivacymanager->expects($deleteinvocations)
->method('delete_data_for_all_users_in_context')
->withConsecutive(
[$blockcontext],
[$usercontext]
);
->willReturnCallback(function ($context) use (
$deleteinvocations,
$blockcontext,
$usercontext,
): void {
match (self::getInvocationCount($deleteinvocations)) {
1 => $this->assertEquals($blockcontext, $context),
2 => $this->assertEquals($usercontext, $context),
default => $this->fail('Unexpected invocation count'),
};
});
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
->onlyMethods(['get_privacy_manager'])
@@ -1641,12 +1657,20 @@ class expired_contexts_test extends \advanced_testcase {
])
->getMock();
$mockprivacymanager->expects($this->atLeastOnce())->method('delete_data_for_user');
$mockprivacymanager->expects($this->exactly(2))
$deleteinvocations = $this->exactly(2);
$mockprivacymanager->expects($deleteinvocations)
->method('delete_data_for_all_users_in_context')
->withConsecutive(
[$blockcontext],
[$usercontext]
);
->willReturnCallback(function ($context) use (
$deleteinvocations,
$blockcontext,
$usercontext,
): void {
match (self::getInvocationCount($deleteinvocations)) {
1 => $this->assertEquals($blockcontext, $context),
2 => $this->assertEquals($usercontext, $context),
default => $this->fail('Unexpected invocation count'),
};
});
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
->onlyMethods(['get_privacy_manager'])
@@ -1860,12 +1884,20 @@ class expired_contexts_test extends \advanced_testcase {
])
->getMock();
$mockprivacymanager->expects($this->never())->method('delete_data_for_user');
$mockprivacymanager->expects($this->exactly(2))
$deleteinvocations = $this->exactly(2);
$mockprivacymanager->expects($deleteinvocations)
->method('delete_data_for_all_users_in_context')
->withConsecutive(
[$forumcontext],
[$coursecontext]
);
->willReturnCallback(function ($context) use (
$deleteinvocations,
$forumcontext,
$coursecontext,
): void {
match (self::getInvocationCount($deleteinvocations)) {
1 => $this->assertEquals($forumcontext, $context),
2 => $this->assertEquals($coursecontext, $context),
default => $this->fail('Unexpected invocation count'),
};
});
$manager = $this->getMockBuilder(\tool_dataprivacy\expired_contexts_manager::class)
->onlyMethods(['get_privacy_manager'])
@@ -1918,7 +1950,7 @@ class expired_contexts_test extends \advanced_testcase {
*
* @return array
*/
public function can_process_deletion_provider(): array {
public static function can_process_deletion_provider(): array {
return [
'Pending' => [
expired_context::STATUS_EXPIRED,
@@ -1956,7 +1988,7 @@ class expired_contexts_test extends \advanced_testcase {
*
* @return array
*/
public function is_complete_provider(): array {
public static function is_complete_provider(): array {
return [
'Pending' => [
expired_context::STATUS_EXPIRED,
@@ -1991,7 +2023,7 @@ class expired_contexts_test extends \advanced_testcase {
*
* @return array
*/
public function is_fully_expired_provider(): array {
public static function is_fully_expired_provider(): array {
return [
'Fully expired' => [
[
+2 -2
View File
@@ -580,7 +580,7 @@ class external_test extends externallib_advanced_testcase {
/**
* Data provider for \tool_dataprivacy_external_testcase::test_XX_options().
*/
public function get_options_provider() {
public static function get_options_provider(): array {
return [
[false, false],
[false, true],
@@ -705,7 +705,7 @@ class external_test extends externallib_advanced_testcase {
/**
* Data provider for \tool_dataprivacy_external_testcase::get_activity_options().
*/
public function get_activity_options_provider() {
public static function get_activity_options_provider(): array {
return [
[false, false, true],
[false, true, true],
@@ -57,7 +57,7 @@ class filtered_userlist_test extends \advanced_testcase {
*
* @return array
*/
public function apply_expired_contexts_filters_provider(): array {
public static function apply_expired_contexts_filters_provider(): array {
return [
// Entire list should be preserved.
'No overrides' => [
@@ -38,20 +38,20 @@ class httpsreplace_test extends \advanced_testcase {
/**
* Data provider for test_upgrade_http_links
*/
public function upgrade_http_links_provider() {
public static function upgrade_http_links_provider(): array {
global $CFG;
// Get the http url, since the default test wwwroot is https.
$wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
return [
"Test image from another site should be replaced" => [
"content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
"content" => '<img src="' . self::getExternalTestFileUrl('/test.jpg', false) . '">',
"outputregex" => '/UPDATE/',
"expectedcontent" => '<img src="' . $this->get_converted_http_link('/test.jpg') . '">',
"expectedcontent" => '<img src="' . self::get_converted_http_link('/test.jpg') . '">',
],
"Test object from another site should be replaced" => [
"content" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
"content" => '<object data="' . self::getExternalTestFileUrl('/test.swf', false) . '">',
"outputregex" => '/UPDATE/',
"expectedcontent" => '<object data="' . $this->get_converted_http_link('/test.swf') . '">',
"expectedcontent" => '<object data="' . self::get_converted_http_link('/test.swf') . '">',
],
"Test image from a site with international name should be replaced" => [
"content" => '<img src="http://中国互联网络信息中心.中国/logosy/201706/W01.png">',
@@ -79,9 +79,9 @@ class httpsreplace_test extends \advanced_testcase {
"expectedcontent" => '<img src="https://anothersite.com?param=http://asdf.com">',
],
"Search for params should be case insensitive" => [
"content" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
"content" => '<object DATA="' . self::getExternalTestFileUrl('/test.swf', false) . '">',
"outputregex" => '/UPDATE/',
"expectedcontent" => '<object DATA="' . $this->get_converted_http_link('/test.swf') . '">',
"expectedcontent" => '<object DATA="' . self::get_converted_http_link('/test.swf') . '">',
],
"URL should be case insensitive" => [
"content" => '<object data="HTTP://some.site/path?query">',
@@ -89,30 +89,30 @@ class httpsreplace_test extends \advanced_testcase {
"expectedcontent" => '<object data="https://some.site/path?query">',
],
"More params should not interfere" => [
"content" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', false) .
"content" => '<img alt="A picture" src="' . self::getExternalTestFileUrl('/test.png', false) .
'" width="1”><p style="font-size: \'20px\'"></p>',
"outputregex" => '/UPDATE/',
"expectedcontent" => '<img alt="A picture" src="' . $this->get_converted_http_link('/test.png') .
"expectedcontent" => '<img alt="A picture" src="' . self::get_converted_http_link('/test.png') .
'" width="1”><p style="font-size: \'20px\'"></p>',
],
"Broken URL should not be changed" => [
"content" => '<img src="broken.' . $this->getExternalTestFileUrl('/test.png', false) . '">',
"content" => '<img src="broken.' . self::getExternalTestFileUrl('/test.png', false) . '">',
"outputregex" => '/^$/',
"expectedcontent" => '<img src="broken.' . $this->getExternalTestFileUrl('/test.png', false) . '">',
"expectedcontent" => '<img src="broken.' . self::getExternalTestFileUrl('/test.png', false) . '">',
],
"Link URL should not be changed" => [
"content" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '">' .
$this->getExternalTestFileUrl('/test.png', false) . '</a>',
"content" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '">' .
self::getExternalTestFileUrl('/test.png', false) . '</a>',
"outputregex" => '/^$/',
"expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '">' .
$this->getExternalTestFileUrl('/test.png', false) . '</a>',
"expectedcontent" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '">' .
self::getExternalTestFileUrl('/test.png', false) . '</a>',
],
"Test image from another site should be replaced but link should not" => [
"content" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
$this->getExternalTestFileUrl('/test.jpg', false) . '"></a>',
"content" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '"><img src="' .
self::getExternalTestFileUrl('/test.jpg', false) . '"></a>',
"outputregex" => '/UPDATE/',
"expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
$this->get_converted_http_link('/test.jpg') . '"></a>',
"expectedcontent" => '<a href="' . self::getExternalTestFileUrl('/test.png', false) . '"><img src="' .
self::get_converted_http_link('/test.jpg') . '"></a>',
],
];
}
@@ -127,8 +127,8 @@ class httpsreplace_test extends \advanced_testcase {
* @param string $path Path to be rewritten
* @return string
*/
protected function get_converted_http_link($path) {
return preg_replace('/^http:/', 'https:', $this->getExternalTestFileUrl($path, false));
protected static function get_converted_http_link($path) {
return preg_replace('/^http:/', 'https:', self::getExternalTestFileUrl($path, false));
}
/**
@@ -160,15 +160,15 @@ class httpsreplace_test extends \advanced_testcase {
/**
* Data provider for test_http_link_stats
*/
public function http_link_stats_provider() {
public static function http_link_stats_provider(): array {
global $CFG;
// Get the http url, since the default test wwwroot is https.
$wwwrootdomain = 'www.example.com';
$wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
$testdomain = $this->get_converted_http_link('');
$testdomain = self::get_converted_http_link('');
return [
"Test image from an available site so shouldn't be reported" => [
"content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
"content" => '<img src="' . self::getExternalTestFileUrl('/test.jpg', false) . '">',
"domain" => $testdomain,
"expectedcount" => 0,
],
@@ -48,7 +48,7 @@ class controller_test extends \advanced_testcase {
*
* @return array
*/
public function uninstall_lang_invalid_provider(): array {
public static function uninstall_lang_invalid_provider(): array {
return [
'Empty string' => [''],
'Meaningless empty string' => [' '],
+16 -4
View File
@@ -55,8 +55,14 @@ final class locale_test extends \advanced_testcase {
'set_locale',
])
->getMock();
$mock->method('get_locale')->will($this->onConsecutiveCalls('en'));
$mock->method('set_locale')->will($this->onConsecutiveCalls('es', 'en'));
$mock->method('get_locale')->will($this->returnValue('en'));
$setinvocations = $this->exactly(2);
$mock
->expects($setinvocations)
->method('set_locale')->willReturnCallback(fn () => match (self::getInvocationCount($setinvocations)) {
1 => 'es',
2 => 'en',
});
// Test what happen when locale is available on system.
$result = $mock->check_locale_availability('en');
@@ -72,8 +78,14 @@ final class locale_test extends \advanced_testcase {
'set_locale',
])
->getMock();
$mock->method('get_locale')->will($this->onConsecutiveCalls('en'));
$mock->method('set_locale')->will($this->onConsecutiveCalls(false, 'en'));
$mock->expects($this->exactly(1))->method('get_locale')->will($this->returnValue('en'));
$setinvocations = $this->exactly(2);
$mock
->expects($setinvocations)
->method('set_locale')->willReturnCallback(fn () => match (self::getInvocationCount($setinvocations)) {
1 => false,
2 => 'en',
});
// Test what happen when locale is not available on system.
$result = $mock->check_locale_availability('en');
+3
View File
@@ -41,5 +41,8 @@ function xmldb_tool_log_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -35,5 +35,8 @@ function xmldb_logstore_database_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -35,5 +35,8 @@ function xmldb_logstore_standard_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -389,7 +389,7 @@ class store_test extends \advanced_testcase {
*
* @return array Array of parameters
*/
public function decode_other_provider(): array {
public static function decode_other_provider(): array {
return [
[['info' => 'd2819896', 'logurl' => 'discuss.php?d=2819896']],
[null],
+2
View File
@@ -864,6 +864,8 @@ class external extends external_api {
$context = context_system::instance();
self::validate_context($context);
require_capability('moodle/competency:templatemanage', $context);
$output = $PAGE->get_renderer('tool_lp');
list($filtercapsql, $filtercapparams) = api::filter_users_with_capability_on_user_context_sql($cap,
+1 -1
View File
@@ -128,7 +128,7 @@ $functions = array(
'classpath' => '',
'description' => 'Search for users.',
'type' => 'read',
'capabilities' => '',
'capabilities' => 'moodle/competency:templatemanage',
'ajax' => true,
),
// This function was originally in this plugin but has been moved to core.
+10 -7
View File
@@ -142,17 +142,14 @@ class externallib_test extends externallib_advanced_testcase {
'email' => 'bobbyyy@dyyylan.com', 'phone1' => '123456', 'phone2' => '78910', 'department' => 'Marketing',
'institution' => 'HQ'));
// First we search with no capability assigned.
// Assign capability required to perform the search.
$this->setUser($ux);
$result = external::search_users('yyylan', 'moodle/competency:planmanage');
$result = external_api::clean_returnvalue(external::search_users_returns(), $result);
$this->assertCount(0, $result['users']);
$this->assertEquals(0, $result['count']);
$systemcontext = \context_system::instance();
$customrole = $this->assignUserCapability('moodle/competency:templatemanage', $systemcontext->id);
// Now we assign a different capability.
$usercontext = \context_user::instance($u1->id);
$systemcontext = \context_system::instance();
$customrole = $this->assignUserCapability('moodle/competency:planview', $usercontext->id);
$this->assignUserCapability('moodle/competency:templatemanage', $usercontext->id, $customrole);
$result = external::search_users('yyylan', 'moodle/competency:planmanage');
$result = external_api::clean_returnvalue(external::search_users_returns(), $result);
@@ -188,6 +185,8 @@ class externallib_test extends externallib_advanced_testcase {
$ux3 = $dg->create_user();
role_assign($this->creatorrole, $ux3->id, $usercontext->id);
$this->setUser($ux3);
$systemcontext = \context_system::instance();
$customrole = $this->assignUserCapability('moodle/competency:templatemanage', $systemcontext->id, $customrole);
$result = external::search_users('yyylan', 'moodle/competency:planmanage');
$result = external_api::clean_returnvalue(external::search_users_returns(), $result);
$this->assertCount(1, $result['users']);
@@ -263,6 +262,7 @@ class externallib_test extends externallib_advanced_testcase {
// Now do the test.
$this->setUser($master);
$dummyrole = $this->assignUserCapability('moodle/competency:templatemanage', $syscontext->id);
$result = external::search_users('MOODLER', 'moodle/site:config');
$this->assertCount(2, $result['users']);
$this->assertEquals(2, $result['count']);
@@ -270,6 +270,7 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertArrayHasKey($slave3->id, $result['users']);
$this->setUser($manager);
$this->assignUserCapability('moodle/competency:templatemanage', $syscontext->id, $dummyrole);
$result = external::search_users('MOODLER', 'moodle/site:config');
$this->assertCount(1, $result['users']);
$this->assertEquals(1, $result['count']);
@@ -378,6 +379,8 @@ class externallib_test extends externallib_advanced_testcase {
// Switch to a user that cannot view identity fields.
$this->setUser($ux);
$systemcontext = \context_system::instance();
$this->assignUserCapability('moodle/competency:templatemanage', $systemcontext->id, $dummyrole);
$CFG->showuseridentity = 'idnumber,email,phone1,phone2,department,institution';
// Only names are included.
+1 -1
View File
@@ -25,6 +25,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024100700; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2024100701; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024100100; // Requires this Moodle version.
$plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).
+3 -1
View File
@@ -31,7 +31,9 @@ class import_test extends \advanced_testcase {
$this->resetAfterTest(true);
$this->setAdminUser();
$importer = new framework_importer(file_get_contents(__DIR__ . '/fixtures/example.csv'));
$importer = new framework_importer(
file_get_contents(self::get_fixture_path(__NAMESPACE__, 'example.csv')),
);
$this->assertEquals('', $importer->get_error());
@@ -1,3 +1,3 @@
define("tool_mfa/autosubmit_verification_code",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=()=>{const codeInput=document.querySelector("#id_verificationcode"),codeForm=codeInput.closest("form"),submitButton=codeForm.querySelector("#id_submitbutton");codeInput.addEventListener("keyup",(function(){this.value.length>=6&&codeForm.submit()})),codeInput.disabled&&(submitButton.disabled=!0)}}));
define("tool_mfa/autosubmit_verification_code",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=()=>{const codeInput=document.querySelector("#id_verificationcode"),codeForm=codeInput.closest("form"),submitButton=codeForm.querySelector("#id_submitbutton");codeInput.addEventListener("input",(function(){this.value.length>=6&&(codeForm.submit(),codeInput.readOnly=!0,submitButton.disabled=!0)})),codeInput.disabled&&(submitButton.disabled=!0)}}));
//# sourceMappingURL=autosubmit_verification_code.min.js.map
@@ -1 +1 @@
{"version":3,"file":"autosubmit_verification_code.min.js","sources":["../src/autosubmit_verification_code.js"],"sourcesContent":["\n// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to autosubmit the verification code element when it reaches 6 characters.\n *\n * @module tool_mfa/autosubmit_verification_code\n * @copyright 2020 Peter Burnett <peterburnett@catalyst-au.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const init = () => {\n const codeInput = document.querySelector(\"#id_verificationcode\");\n const codeForm = codeInput.closest(\"form\");\n const submitButton = codeForm.querySelector(\"#id_submitbutton\");\n\n // Event listener for code input field.\n codeInput.addEventListener('keyup', function() {\n if (this.value.length >= 6) {\n // Submits the closes form (parent).\n codeForm.submit();\n }\n });\n\n // Disable the submit button if the input field is disabled.\n // This occurs if there are no more attempts left for the factor.\n if (codeInput.disabled) {\n submitButton.disabled = true;\n }\n};\n"],"names":["codeInput","document","querySelector","codeForm","closest","submitButton","addEventListener","this","value","length","submit","disabled"],"mappings":"0KAwBoB,WACVA,UAAYC,SAASC,cAAc,wBACnCC,SAAWH,UAAUI,QAAQ,QAC7BC,aAAeF,SAASD,cAAc,oBAG5CF,UAAUM,iBAAiB,SAAS,WAC5BC,KAAKC,MAAMC,QAAU,GAErBN,SAASO,YAMbV,UAAUW,WACVN,aAAaM,UAAW"}
{"version":3,"file":"autosubmit_verification_code.min.js","sources":["../src/autosubmit_verification_code.js"],"sourcesContent":["\n// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Module to autosubmit the verification code element when it reaches 6 characters.\n *\n * @module tool_mfa/autosubmit_verification_code\n * @copyright 2020 Peter Burnett <peterburnett@catalyst-au.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport const init = () => {\n const codeInput = document.querySelector(\"#id_verificationcode\");\n const codeForm = codeInput.closest(\"form\");\n const submitButton = codeForm.querySelector(\"#id_submitbutton\");\n\n // Event listener for code input field.\n codeInput.addEventListener('input', function() {\n if (this.value.length >= 6) {\n // Submits the closest form (parent) and prevents accidental resubmission.\n codeForm.submit();\n codeInput.readOnly = true;\n submitButton.disabled = true;\n }\n });\n\n // Disable the submit button if the input field is disabled.\n // This occurs if there are no more attempts left for the factor.\n if (codeInput.disabled) {\n submitButton.disabled = true;\n }\n};\n"],"names":["codeInput","document","querySelector","codeForm","closest","submitButton","addEventListener","this","value","length","submit","readOnly","disabled"],"mappings":"0KAwBoB,WACVA,UAAYC,SAASC,cAAc,wBACnCC,SAAWH,UAAUI,QAAQ,QAC7BC,aAAeF,SAASD,cAAc,oBAG5CF,UAAUM,iBAAiB,SAAS,WAC5BC,KAAKC,MAAMC,QAAU,IAErBN,SAASO,SACTV,UAAUW,UAAW,EACrBN,aAAaO,UAAW,MAM5BZ,UAAUY,WACVP,aAAaO,UAAW"}
@@ -28,10 +28,12 @@ export const init = () => {
const submitButton = codeForm.querySelector("#id_submitbutton");
// Event listener for code input field.
codeInput.addEventListener('keyup', function() {
codeInput.addEventListener('input', function() {
if (this.value.length >= 6) {
// Submits the closes form (parent).
// Submits the closest form (parent) and prevents accidental resubmission.
codeForm.submit();
codeInput.readOnly = true;
submitButton.disabled = true;
}
});
@@ -51,5 +51,8 @@ function xmldb_factor_auth_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+3
View File
@@ -73,5 +73,8 @@ function xmldb_factor_sms_upgrade(int $oldversion): bool {
upgrade_plugin_savepoint(true, 2024082201, 'factor', 'sms');
}
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -42,7 +42,7 @@ $string['managefactor'] = 'Manage SMS';
$string['managefactorbutton'] = 'Manage';
$string['manageinfo'] = 'You are using \'{$a}\' to authenticate.';
$string['notification:smsgatewaymigration'] = 'SMS settings have moved';
$string['notification:smsgatewaymigrationinfo'] = 'A new SMS subsystem is now available for managing and configuring all SMS-related functions. Your existing SMS configurations have been seamlessly migrated. You can find and manage them on the new <a href="{$a}">SMS Gateways page</a>.';
$string['notification:smsgatewaymigrationinfo'] = 'A new SMS subsystem is now available for managing and configuring all SMS-related functions. Your existing SMS configurations have been migrated to the page <a href="{$a}">SMS gateways</a>.';
$string['logintitle'] = 'Enter the verification code sent to your mobile';
$string['phonehelp'] = 'Enter your mobile number (including country code) to receive a verification code.';
$string['pluginname'] = 'SMS mobile phone';
@@ -32,7 +32,7 @@ class factor_test extends \advanced_testcase {
*
* @return array of different country codes and phone numbers.
*/
public function format_number_provider(): array {
public static function format_number_provider(): array {
return [
'Phone number with local format' => [
@@ -88,7 +88,7 @@ class factor_test extends \advanced_testcase {
*
* @return array with different phone numebr tests
*/
public function is_valid_phonenumber_provider(): array {
public static function is_valid_phonenumber_provider(): array {
return [
['+919367788755', true],
['8989829304', false],
@@ -276,7 +276,7 @@ class factor_test extends \advanced_testcase {
* Increments by 30 minutes to cover half hour and hour cases.
* Starting timestamp: 2022-01-15 07:30:00 Australia/Melbourne time.
*/
public function timestamp_provider() {
public static function timestamp_provider(): array {
$starttimestamp = 1642192200;
foreach (range(0, 23) as $i) {
$timestamps[] = [$starttimestamp + ($i * HOURSECS)];
@@ -39,5 +39,8 @@ function xmldb_factor_totp_upgrade($oldversion): bool {
upgrade_plugin_savepoint(true, 2024081600, 'factor', 'totp');
}
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -51,7 +51,7 @@ class admin_setting_managemfa_test extends \advanced_testcase {
*
* @return array
*/
public function get_factor_combinations_provider() {
public static function get_factor_combinations_provider(): array {
$provider = [];
$factors = [];
+1 -1
View File
@@ -157,7 +157,7 @@ class manager_test extends \advanced_testcase {
*
* @return array
*/
public static function should_redirect_urls_provider() {
public static function should_redirect_urls_provider(): array {
$badurl1 = new \moodle_url('/');
$badparam1 = $badurl1->out();
$badurl2 = new \moodle_url('admin/tool/mfa/auth.php');
+3
View File
@@ -41,5 +41,8 @@ function xmldb_tool_mobile_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+3
View File
@@ -41,5 +41,8 @@ function xmldb_tool_monitor_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+3
View File
@@ -41,5 +41,8 @@ function xmldb_tool_moodlenet_upgrade(int $oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+1 -1
View File
@@ -52,7 +52,7 @@ class lib_test extends \advanced_testcase {
*
* @return array
*/
public function get_endpoints_provider() {
public static function get_endpoints_provider(): array {
global $CFG;
return [
[
@@ -59,7 +59,7 @@ class import_handler_info_test extends \advanced_testcase {
*
* @return array the data for creation of the info object.
*/
public function handler_info_data_provider() {
public static function handler_info_data_provider(): array {
return [
'All data present' => ['label', 'Add a label to the course', false],
'Empty module name' => ['', 'Add a file resource to the course', true],
@@ -53,10 +53,10 @@ class remote_resource_test extends \advanced_testcase {
*
* @return array
*/
public function remote_resource_data_provider() {
public static function remote_resource_data_provider(): array {
return [
'With filename and extension' => [
$this->getExternalTestFileUrl('/test.html'),
self::getExternalTestFileUrl('/test.html'),
(object) [
'name' => 'Test html file',
'description' => 'Full description of the html file'
@@ -78,8 +78,8 @@ class remote_resource_test extends \advanced_testcase {
* Test confirming the network based operations of a remote_resource.
*/
public function test_network_features(): void {
$url = $this->getExternalTestFileUrl('/test.html');
$nonexistenturl = $this->getExternalTestFileUrl('/test.htmlzz');
$url = self::getExternalTestFileUrl('/test.html');
$nonexistenturl = self::getExternalTestFileUrl('/test.htmlzz');
$remoteres = new remote_resource(
new \curl(),
@@ -55,7 +55,7 @@ class url_test extends \advanced_testcase {
*
* @return array
*/
public function url_provider() {
public static function url_provider(): array {
return [
'No path' => [
'url' => 'https://example.moodle.net',
+3
View File
@@ -42,5 +42,8 @@ function xmldb_tool_policy_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
@@ -176,7 +176,7 @@ class category_bin_test extends \advanced_testcase {
* Used to verify that recycle bin is immune to various settings. Provides plugin, name, value for
* direct usage with set_config()
*/
public function recycle_bin_settings_provider() {
public static function recycle_bin_settings_provider(): array {
return [
'backup/backup_auto_storage moodle' => [[
(object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 0],
@@ -176,7 +176,7 @@ class course_bin_test extends \advanced_testcase {
* Used to verify that recycle bin is immune to various settings. Provides plugin, name, value for
* direct usage with set_config()
*/
public function recycle_bin_settings_provider() {
public static function recycle_bin_settings_provider(): array {
return [
'backup/backup_auto_storage moodle' => [[
(object)['plugin' => 'backup', 'name' => 'backup_auto_storage', 'value' => 0],
+25 -8
View File
@@ -967,8 +967,14 @@ class course_test extends \advanced_testcase {
// Restore from a file, checking that the file takes priority over the templatecourse.
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
$data = [
'shortname' => 'A1',
'backupfile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
'summary' => 'A',
'category' => 1,
'fullname' => 'A1',
'templatecourse' => $c1->shortname,
];
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
$this->assertTrue($co->prepare());
$co->proceed();
@@ -986,8 +992,13 @@ class course_test extends \advanced_testcase {
$this->assertTrue($found);
// Restoring twice from the same file should work.
$data = array('shortname' => 'B1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
'summary' => 'B', 'category' => 1, 'fullname' => 'B1');
$data = [
'shortname' => 'B1',
'backupfile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
'summary' => 'B',
'category' => 1,
'fullname' => 'B1',
];
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
$this->assertTrue($co->prepare());
$co->proceed();
@@ -1020,8 +1031,14 @@ class course_test extends \advanced_testcase {
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
$data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
$data = [
'shortname' => 'A1',
'backupfile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
'summary' => 'A',
'category' => 1,
'fullname' => 'A1',
'templatecourse' => $c1->shortname,
];
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
$this->assertTrue($co->prepare());
$co->proceed();
@@ -1259,7 +1276,7 @@ class course_test extends \advanced_testcase {
*
* @return array
*/
public function enrolment_uploaddata_error_provider(): array {
public static function enrolment_uploaddata_error_provider(): array {
return [
['errorcannotcreateorupdateenrolment', [
'shortname' => 'C1',
@@ -1487,7 +1504,7 @@ class course_test extends \advanced_testcase {
// Create our custom field.
$category = $this->get_customfield_generator()->create_category();
$this->create_custom_field($category, 'date', 'mydate',
['mindate' => strtotime('2020-04-01'), 'maxdate' => '2020-04-30']);
['mindate' => strtotime('2020-04-01'), 'maxdate' => strtotime('2020-04-30')]);
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
@@ -110,11 +110,11 @@ class processor_test extends \advanced_testcase {
$cir->load_csv_content($content, 'utf-8', 'comma');
$cir->init();
$options = array(
$options = [
'mode' => tool_uploadcourse_processor::MODE_CREATE_NEW,
'restorefile' => __DIR__ . '/fixtures/backup.mbz',
'templatecourse' => 'DoesNotExist' // Restorefile takes priority.
);
'restorefile' => self::get_fixture_path(__NAMESPACE__, 'backup.mbz'),
'templatecourse' => 'DoesNotExist', // Restorefile takes priority.
];
$defaults = array('category' => '1');
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
@@ -30,7 +30,7 @@ class field_value_validators_test extends \advanced_testcase {
/**
* Data provider for \field_value_validators_testcase::test_validate_theme().
*/
public function themes_provider() {
public static function themes_provider(): array {
return [
'User themes disabled' => [
false, 'boost', 'warning', get_string('userthemesnotallowed', 'tool_uploaduser')
+3
View File
@@ -52,5 +52,8 @@ function xmldb_tool_usertours_upgrade($oldversion) {
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.5.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+5 -5
View File
@@ -106,7 +106,7 @@ final class helper_test extends \advanced_testcase {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/invalid_serverside_hook_fixture.php',
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'invalid_serverside_hook_fixture.php'),
]),
);
@@ -118,7 +118,7 @@ final class helper_test extends \advanced_testcase {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/clientside_filter_for_serverside_hook.php',
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'clientside_filter_for_serverside_hook.php'),
]),
);
@@ -130,7 +130,7 @@ final class helper_test extends \advanced_testcase {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/serverside_filter_for_clientside_hook.php',
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'serverside_filter_for_clientside_hook.php'),
]),
);
@@ -142,7 +142,7 @@ final class helper_test extends \advanced_testcase {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/hook_fixtures.php',
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'hook_fixtures.php'),
]),
);
@@ -175,7 +175,7 @@ final class helper_test extends \advanced_testcase {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/invalid_clientside_hook_fixture.php',
'test_plugin1' => self::get_fixture_path(__NAMESPACE__, 'invalid_clientside_hook_fixture.php'),
]),
);
+42 -13
View File
@@ -527,14 +527,30 @@ class tour_test extends \advanced_testcase {
// Mock the database.
$DB = $this->mock_database();
$DB->expects($this->exactly(3))
$deleteinvocations = $this->exactly(3);
$DB->expects($deleteinvocations)
->method('delete_records')
->withConsecutive(
[$this->equalTo('tool_usertours_tours'), $this->equalTo(['id' => $id])],
[$this->equalTo('user_preferences'), $this->equalTo(['name' => tour::TOUR_LAST_COMPLETED_BY_USER . $id])],
[$this->equalTo('user_preferences'), $this->equalTo(['name' => tour::TOUR_REQUESTED_BY_USER . $id])]
)
->willReturn(null);
->willReturnCallback(function ($table, $conditions) use ($deleteinvocations, $id) {
switch (self::getInvocationCount($deleteinvocations)) {
case 1:
$this->assertEquals('tool_usertours_tours', $table);
$this->assertEquals(['id' => $id], $conditions);
return null;
break;
case 2:
$this->assertEquals('user_preferences', $table);
$this->assertEquals(['name' => tour::TOUR_LAST_COMPLETED_BY_USER . $id], $conditions);
return null;
break;
case 3:
$this->assertEquals('user_preferences', $table);
$this->assertEquals(['name' => tour::TOUR_REQUESTED_BY_USER . $id], $conditions);
return null;
break;
default:
$this->fail('Unexpected call to delete_records');
}
});
$DB->expects($this->once())
->method('get_records')
@@ -554,7 +570,7 @@ class tour_test extends \advanced_testcase {
for ($i = 4; $i >= 0; $i--) {
$id = rand($i * 10, ($i * 10) + 9);
$mockdata[] = (object) ['id' => $id];
$expectations[] = [$this->equalTo('tool_usertours_steps'), $this->equalTo('sortorder'), 4 - $i, ['id' => $id]];
$expectations[] = [4 - $i, ['id' => $id]];
}
// Mock the database.
@@ -563,9 +579,19 @@ class tour_test extends \advanced_testcase {
->method('get_records')
->willReturn($mockdata);
$setfield = $DB->expects($this->exactly(5))
->method('set_field');
call_user_func_array([$setfield, 'withConsecutive'], $expectations);
$setfieldinvocations = $this->exactly(5);
$DB->expects($setfieldinvocations)
->method('set_field')
->willReturnCallback(function ($table, $field, $value, $conditions) use (
$setfieldinvocations,
$expectations,
): void {
$expectation = $expectations[self::getInvocationCount($setfieldinvocations) - 1];
$this->assertEquals('tool_usertours_steps', $table);
$this->assertEquals('sortorder', $field);
$this->assertEquals($expectation[0], $value);
$this->assertEquals($expectation[1], $conditions);
});
$tour->reset_step_sortorder();
}
@@ -764,9 +790,12 @@ class tour_test extends \advanced_testcase {
->getMock();
if ($getconfig) {
$tour->expects($this->exactly(count($getconfig)))
$getinvocations = $this->exactly(count($getconfig));
$tour->expects($getinvocations)
->method('get_config')
->will(call_user_func_array([$this, 'onConsecutiveCalls'], $getconfig));
->willReturnCallback(function () use ($getinvocations, $getconfig) {
return $getconfig[self::getInvocationCount($getinvocations) - 1];
});
}
if ($setconfig) {
+8
View File
@@ -72,6 +72,14 @@ abstract class provider {
return [];
}
/**
* Check if the request is allowed by the rate limiter.
*
* @param aiactions\base $action The action to check.
* @return array|bool True on success, array of error details on failure.
*/
abstract public function is_request_allowed(aiactions\base $action): array|bool;
/**
* Check if a provider has the minimal configuration to work.
*
+1 -1
View File
@@ -1,3 +1,3 @@
define("aiplacement_courseassist/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={ELEMENTS:{AIDRAWER:"#ai-drawer",AIDRAWER_BODY:"#ai-drawer .ai-drawer-body",PAGE:"#page",MAIN_REGION:'[role="main"]'},ACTIONS:{SUMMARY:'[data-action="course-summarise"]',RETRY:'[data-action="course-summarise-retry"]',DECLINE:'[data-action="course-summarise-policy-decline"]',ACCEPT:'.ai-policy-block [data-action="accept"]',REGENERATE:'[data-action="course-summarise-regenerate"]',CANCEL:'.ai-policy-block [data-action="decline"]'}},_exports.default}));
define("aiplacement_courseassist/selectors",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={ELEMENTS:{AIDRAWER:"#ai-drawer",AIDRAWER_BODY:"#ai-drawer .ai-drawer-body",PAGE:"#page",MAIN_REGION:'[role="main"]'},ACTIONS:{SUMMARY:'[data-action="course-summarise"]',RETRY:'[data-action="course-summarise-retry"]',DECLINE:'.ai-policy-block [data-action="decline"]',ACCEPT:'.ai-policy-block [data-action="accept"]',REGENERATE:'[data-action="course-summarise-regenerate"]',CANCEL:'[data-action="course-summarise-cancel"]'}},_exports.default}));
//# sourceMappingURL=selectors.min.js.map
@@ -1 +1 @@
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the AI Course assistant.\n *\n * @module aiplacement_courseassist/selectors\n * @copyright 2024 Huong Nguyen <huongnv13@gmail.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default {\n ELEMENTS: {\n AIDRAWER: '#ai-drawer',\n AIDRAWER_BODY: '#ai-drawer .ai-drawer-body',\n PAGE: '#page',\n MAIN_REGION: '[role=\"main\"]',\n },\n ACTIONS: {\n SUMMARY: '[data-action=\"course-summarise\"]',\n RETRY: '[data-action=\"course-summarise-retry\"]',\n DECLINE: '[data-action=\"course-summarise-policy-decline\"]',\n ACCEPT: '.ai-policy-block [data-action=\"accept\"]',\n REGENERATE: '[data-action=\"course-summarise-regenerate\"]',\n CANCEL: '.ai-policy-block [data-action=\"decline\"]',\n }\n};\n"],"names":["ELEMENTS","AIDRAWER","AIDRAWER_BODY","PAGE","MAIN_REGION","ACTIONS","SUMMARY","RETRY","DECLINE","ACCEPT","REGENERATE","CANCEL"],"mappings":"oLAsBe,CACXA,SAAU,CACNC,SAAU,aACVC,cAAe,6BACfC,KAAM,QACNC,YAAa,iBAEjBC,QAAS,CACLC,QAAS,mCACTC,MAAO,yCACPC,QAAS,kDACTC,OAAQ,0CACRC,WAAY,8CACZC,OAAQ"}
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the AI Course assistant.\n *\n * @module aiplacement_courseassist/selectors\n * @copyright 2024 Huong Nguyen <huongnv13@gmail.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nexport default {\n ELEMENTS: {\n AIDRAWER: '#ai-drawer',\n AIDRAWER_BODY: '#ai-drawer .ai-drawer-body',\n PAGE: '#page',\n MAIN_REGION: '[role=\"main\"]',\n },\n ACTIONS: {\n SUMMARY: '[data-action=\"course-summarise\"]',\n RETRY: '[data-action=\"course-summarise-retry\"]',\n DECLINE: '.ai-policy-block [data-action=\"decline\"]',\n ACCEPT: '.ai-policy-block [data-action=\"accept\"]',\n REGENERATE: '[data-action=\"course-summarise-regenerate\"]',\n CANCEL: '[data-action=\"course-summarise-cancel\"]',\n }\n};\n"],"names":["ELEMENTS","AIDRAWER","AIDRAWER_BODY","PAGE","MAIN_REGION","ACTIONS","SUMMARY","RETRY","DECLINE","ACCEPT","REGENERATE","CANCEL"],"mappings":"oLAsBe,CACXA,SAAU,CACNC,SAAU,aACVC,cAAe,6BACfC,KAAM,QACNC,YAAa,iBAEjBC,QAAS,CACLC,QAAS,mCACTC,MAAO,yCACPC,QAAS,2CACTC,OAAQ,0CACRC,WAAY,8CACZC,OAAQ"}
@@ -30,9 +30,9 @@ export default {
ACTIONS: {
SUMMARY: '[data-action="course-summarise"]',
RETRY: '[data-action="course-summarise-retry"]',
DECLINE: '[data-action="course-summarise-policy-decline"]',
DECLINE: '.ai-policy-block [data-action="decline"]',
ACCEPT: '.ai-policy-block [data-action="accept"]',
REGENERATE: '[data-action="course-summarise-regenerate"]',
CANCEL: '.ai-policy-block [data-action="decline"]',
CANCEL: '[data-action="course-summarise-cancel"]',
}
};
@@ -27,9 +27,9 @@ $string['courseassist:summarise_text'] = 'Summarise text';
$string['copy'] = 'Copy';
$string['generatefailtitle'] = 'Something went wrong';
$string['generating'] = 'Generating your response';
$string['nocourseassist'] = 'AI summary is not available for this context';
$string['pluginname'] = 'Course Assistance Placement';
$string['privacy:metadata'] = 'The Course Assistance placement plugin does not store any personal data.';
$string['nocourseassist'] = 'An AI-generated summary is not available for this context.';
$string['pluginname'] = 'Course assistance placement';
$string['privacy:metadata'] = 'The Course assistance placement plugin does not store any personal data.';
$string['regenerate'] = 'Regenerate';
$string['summarise'] = 'Summarise';
$string['summarise_tooltips'] = 'Create an AI-generated summary of the page content';
@@ -28,7 +28,6 @@ Feature: AI Course assist summarise
And I enable "openai" "aiprovider" plugin
And the following config values are set as admin:
| apikey | 123 | aiprovider_openai |
| orgid | abc | aiprovider_openai |
And I enable "courseassist" "aiplacement" plugin
@javascript
@@ -47,7 +47,6 @@ final class utils_test extends \advanced_testcase {
set_config('enabled', 1, 'aiprovider_openai');
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', 'abc', 'aiprovider_openai');
// Plugin is not enabled.
$this->setUser($user1);
@@ -22,15 +22,15 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['generatecontent'] = 'Generate AI Content';
$string['generatecontent'] = 'Generate AI content';
$string['generateimage'] = 'AI generate image';
$string['generateimagesetting'] = 'Enable generate image';
$string['generateimagesetting_desc'] = 'Enable or disable the generation of images from a text prompt.';
$string['generatetext'] = 'AI generate text';
$string['generatetextsetting'] = 'Enable generate text';
$string['generatetextsetting_desc'] = 'Enable or disable the generation of text from a text prompt.';
$string['noeditor'] = 'HTML Text Editor Placement is not available for this context';
$string['pluginname'] = 'HTML Text Editor Placement';
$string['privacy:metadata'] = 'The HTML text editor placement plugin does not store any personal data.';
$string['editor:generate_image'] = 'Generate AI Images in HTML Text Editor';
$string['editor:generate_text'] = 'Generate AI Text in HTML Text Editor';
$string['noeditor'] = 'Text editor placement is not available for this context.';
$string['pluginname'] = 'Text editor placement';
$string['privacy:metadata'] = 'The Text editor placement plugin does not store any personal data.';
$string['editor:generate_image'] = 'Generate AI images in text editor';
$string['editor:generate_text'] = 'Generate AI text in text editor';
+1 -2
View File
@@ -20,7 +20,7 @@ use core_ai\aiactions\generate_image;
use core_ai\aiactions\generate_text;
/**
* HTML Text Editor Placement utils test.
* Text editor placement utils test.
*
* @package aiplacement_editor
* @copyright 2024 Huong Nguyen <huongnv13@gmail.com>
@@ -73,7 +73,6 @@ final class utils_test extends \advanced_testcase {
set_config('enabled', 1, 'aiprovider_openai');
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', 'abc', 'aiprovider_openai');
// Plugin is not enabled.
$this->setUser($this->users[1]);
+1 -6
View File
@@ -100,12 +100,7 @@ class provider extends \core_ai\provider {
->withAddedHeader('api-key', $this->apikey);
}
/**
* Check if the request is allowed by the rate limiter.
*
* @param aiactions\base $action The action to check.
* @return array|bool True on success, array of error details on failure.
*/
#[\Override]
public function is_request_allowed(aiactions\base $action): array|bool {
$ratelimiter = \core\di::get(rate_limiter::class);
$component = \core\component::get_component_from_classname(get_class($this));
@@ -25,7 +25,7 @@
$string['action_apiversion'] = 'API version';
$string['action_deployment'] = 'Deployment ID';
$string['action_deployment_desc'] = 'The deployment ID that relates to the API endpoint the provider uses for this action.';
$string['action_systeminstruction'] = 'System Instruction';
$string['action_systeminstruction'] = 'System instruction';
$string['action_systeminstruction_desc'] = 'This instruction is sent to the AI model along with the user\'s prompt. Editing this instruction is not recommended unless absolutely required.';
$string['apikey'] = 'Azure AI API key';
$string['apikey_desc'] = 'Enter your Azure AI API key.';
@@ -36,15 +36,15 @@ $string['enableglobalratelimit_desc'] = 'Limit the number of requests that the A
$string['enableuserratelimit'] = 'Set user rate limit';
$string['enableuserratelimit_desc'] = 'Limit the number of requests each user can make to the Azure AI API provider every hour.';
$string['endpoint'] = 'Azure AI API endpoint';
$string['endpoint_desc'] = 'Enter the endpoint URL for your Azure AI API, in the following format: https://YOUR_RESOURCE_NAME.azureai.azure.com/azureai/deployments';
$string['endpoint_desc'] = 'Enter the endpoint URL for your Azure AI API in the following format: https://YOUR_RESOURCE_NAME.openai.azure.com';
$string['globalratelimit'] = 'Maximum number of site-wide requests';
$string['globalratelimit_desc'] = 'The number of site-wide requests allowed per hour.';
$string['pluginname'] = 'Azure AI API Provider';
$string['privacy:metadata'] = 'The Azure Ai API provider plugin does not store any personal data.';
$string['pluginname'] = 'Azure AI API provider';
$string['privacy:metadata'] = 'The Azure AI API provider plugin does not store any personal data.';
$string['privacy:metadata:aiprovider_azureai:externalpurpose'] = 'This information is sent to the Azure API in order for a response to be generated. Your Azure AI account settings may change how Microsoft stores and retains this data. No user data is explicitly sent to Microsoft or stored in Moodle LMS by this plugin.';
$string['privacy:metadata:aiprovider_azureai:model'] = 'The model used to generate the response.';
$string['privacy:metadata:aiprovider_azureai:numberimages'] = 'The number of images used in the response. When generating images.';
$string['privacy:metadata:aiprovider_azureai:numberimages'] = 'When generating images the number of images used in the response.';
$string['privacy:metadata:aiprovider_azureai:prompttext'] = 'The user entered text prompt used to generate the response.';
$string['privacy:metadata:aiprovider_azureai:responseformat'] = 'The format of the response. When generating images.';
$string['privacy:metadata:aiprovider_azureai:responseformat'] = 'When generating images the format of the response.';
$string['userratelimit'] = 'Maximum number of requests per user';
$string['userratelimit_desc'] = 'The number of requests allowed per hour, per user.';
+2 -7
View File
@@ -102,12 +102,7 @@ class provider extends \core_ai\provider {
->withAddedHeader('OpenAI-Organization', $this->orgid);
}
/**
* Check if the request is allowed by the rate limiter.
*
* @param aiactions\base $action The action to check.
* @return array|bool True on success, array of error details on failure.
*/
#[\Override]
public function is_request_allowed(aiactions\base $action): array|bool {
$ratelimiter = \core\di::get(rate_limiter::class);
$component = \core\component::get_component_from_classname(get_class($this));
@@ -214,6 +209,6 @@ class provider extends \core_ai\provider {
* @return bool Return true if configured.
*/
public function is_provider_configured(): bool {
return !empty($this->apikey) && !empty($this->orgid);
return !empty($this->apikey);
}
}
@@ -36,7 +36,7 @@ $string['action:summarise_text:model_desc'] = 'The model used to summarise the p
$string['action:summarise_text:systeminstruction'] = 'System instruction';
$string['action:summarise_text:systeminstruction_desc'] = 'This instruction is sent to the AI model along with the user\'s prompt. Editing this instruction is not recommended unless absolutely required.';
$string['apikey'] = 'OpenAI API key';
$string['apikey_desc'] = 'Get a key from your <a href="https://platform.openai.com/account/api-keys" target="_blank">OpenAI API keys</a>.';
$string['apikey_desc'] = 'Get a key from <a href="https://platform.openai.com/account/api-keys">OpenAI Platform API keys</a>.';
$string['enableglobalratelimit'] = 'Set site-wide rate limit';
$string['enableglobalratelimit_desc'] = 'Limit the number of requests that the OpenAI API provider can receive across the entire site every hour.';
$string['enableuserratelimit'] = 'Set user rate limit';
@@ -44,13 +44,13 @@ $string['enableuserratelimit_desc'] = 'Limit the number of requests each user ca
$string['globalratelimit'] = 'Maximum number of site-wide requests';
$string['globalratelimit_desc'] = 'The number of site-wide requests allowed per hour.';
$string['orgid'] = 'OpenAI organization ID';
$string['orgid_desc'] = 'Get your OpenAI organization ID from your <a href="https://platform.openai.com/account/org-settings" target="_blank">OpenAI account</a>.';
$string['pluginname'] = 'OpenAI API Provider';
$string['orgid_desc'] = 'Get an OpenAI organization ID from your <a href="https://platform.openai.com/account/org-settings">OpenAI Platform account</a>.';
$string['pluginname'] = 'OpenAI API provider';
$string['privacy:metadata'] = 'The OpenAI API provider plugin does not store any personal data.';
$string['privacy:metadata:aiprovider_openai:externalpurpose'] = 'This information is sent to the OpenAI API in order for a response to be generated. Your OpenAI account settings may change how OpenAI stores and retains this data. No user data is explicitly sent to OpenAI or stored in Moodle LMS by this plugin.';
$string['privacy:metadata:aiprovider_openai:model'] = 'The model used to generate the response.';
$string['privacy:metadata:aiprovider_openai:numberimages'] = 'The number of images used in the response. When generating images.';
$string['privacy:metadata:aiprovider_openai:numberimages'] = 'When generating images the number of images used in the response.';
$string['privacy:metadata:aiprovider_openai:prompttext'] = 'The user entered text prompt used to generate the response.';
$string['privacy:metadata:aiprovider_openai:responseformat'] = 'The format of the response. When generating images.';
$string['privacy:metadata:aiprovider_openai:responseformat'] = 'When generating images the format of the response.';
$string['userratelimit'] = 'Maximum number of requests per user';
$string['userratelimit_desc'] = 'The number of requests allowed per hour, per user.';
@@ -121,15 +121,8 @@ final class provider_test extends \advanced_testcase {
$provider = new \aiprovider_openai\provider();
$this->assertFalse($provider->is_provider_configured());
// Partially configured values.
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', '', 'aiprovider_openai');
$provider = new \aiprovider_openai\provider();
$this->assertFalse($provider->is_provider_configured());
// Properly configured values.
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', 'abc', 'aiprovider_openai');
$provider = new \aiprovider_openai\provider();
$this->assertTrue($provider->is_provider_configured());
}
+5 -5
View File
@@ -36,7 +36,7 @@ final class ai_image_test extends \advanced_testcase {
$height = 20;
// Test for black image.
$imagepath = __DIR__ . '/fixtures/black.png'; // Get the test image from the fixtures file.
$imagepath = self::get_fixture_path(__NAMESPACE__, 'black.png'); // Get the test image from the fixtures file.
$image = new ai_image($imagepath);
// We're working with a private method here, so we need to use reflection.
$method = new \ReflectionMethod($image, 'get_predominant_color');
@@ -47,7 +47,7 @@ final class ai_image_test extends \advanced_testcase {
$this->assertEquals(0, $color['blue']);
// Test for white image.
$imagepath = __DIR__ . '/fixtures/white.png';
$imagepath = self::get_fixture_path(__NAMESPACE__, 'white.png');
$image = new ai_image($imagepath);
// We're working with a private method here, so we need to use reflection.
$method = new \ReflectionMethod($image, 'get_predominant_color');
@@ -58,7 +58,7 @@ final class ai_image_test extends \advanced_testcase {
$this->assertEquals(255, $color['blue']);
// Test for grey image.
$imagepath = __DIR__ . '/fixtures/grey.png';
$imagepath = self::get_fixture_path(__NAMESPACE__, 'grey.png');
$image = new ai_image($imagepath);
// We're working with a private method here, so we need to use reflection.
$method = new \ReflectionMethod($image, 'get_predominant_color');
@@ -75,7 +75,7 @@ final class ai_image_test extends \advanced_testcase {
public function test_is_color_dark(): void {
// Load an image as it is required for class instantiation.
// The color of the image is not important for this test.
$imagepath = __DIR__ . '/fixtures/black.png';
$imagepath = self::get_fixture_path(__NAMESPACE__, 'black.png');
$image = new ai_image($imagepath);
// We're working with a private method here, so we need to use reflection.
$method = new \ReflectionMethod($image, 'is_color_dark');
@@ -92,7 +92,7 @@ final class ai_image_test extends \advanced_testcase {
$this->assertFalse($result);
$imagepath = __DIR__ . '/fixtures/grey.png';
$imagepath = self::get_fixture_path(__NAMESPACE__, 'grey.png');
$image = new ai_image($imagepath);
// We're working with a private method here, so we need to use reflection.
$method = new \ReflectionMethod($image, 'is_color_dark');
+20 -22
View File
@@ -8,44 +8,43 @@ Feature: An administrator can manage AI subsystem settings
Scenario: An administrator can control the enabled state of AI Provider plugins using JavaScript
Given I am logged in as "admin"
And I navigate to "AI > AI providers" in site administration
When I toggle the "Enable OpenAI API Provider" admin switch "on"
And I should see "OpenAI API Provider enabled."
When I toggle the "Enable OpenAI API provider" admin switch "on"
And I should see "OpenAI API provider enabled."
And I reload the page
And I should see "Disable OpenAI API Provider"
And I toggle the "Disable OpenAI API Provider" admin switch "off"
Then I should see "OpenAI API Provider disabled."
And I should see "Disable OpenAI API provider"
And I toggle the "Disable OpenAI API provider" admin switch "off"
Then I should see "OpenAI API provider disabled."
@javascript
Scenario: An administrator can control the enabled state of AI Placement plugins using JavaScript
Scenario: An administrator can control the enabled state of AI placement plugins using JavaScript
Given I am logged in as "admin"
And I navigate to "AI > AI placements" in site administration
When I toggle the "Enable HTML Text Editor Placement" admin switch "on"
And I should see "HTML Text Editor Placement enabled."
When I toggle the "Enable Text editor placement" admin switch "on"
And I should see "Text editor placement enabled."
And I reload the page
And I should see "Disable HTML Text Editor Placement"
And I toggle the "Disable HTML Text Editor Placement" admin switch "off"
Then I should see "HTML Text Editor Placement disabled."
And I should see "Disable Text editor placement"
And I toggle the "Disable Text editor placement" admin switch "off"
Then I should see "Text editor placement disabled."
@javascript
Scenario: Placement actions should be available when an Administrator enables AI Providers using JavaScript
Given I am logged in as "admin"
And I navigate to "AI > AI providers" in site administration
When I toggle the "Enable OpenAI API Provider" admin switch "on"
And I should see "OpenAI API Provider enabled."
When I toggle the "Enable OpenAI API provider" admin switch "on"
And I should see "OpenAI API provider enabled."
And the following config values are set as admin:
| apikey | 123 | aiprovider_openai |
| orgid | abc | aiprovider_openai |
And I navigate to "AI > AI placements" in site administration
And I click on the "Settings" link in the table row containing "HTML Text Editor Placement"
And I click on the "Settings" link in the table row containing "Text editor placement"
Then I should not see "This action is unavailable."
@javascript
Scenario: Placement actions should not be available when an Administrator disables AI Providers using JavaScript
Given I am logged in as "admin"
And I navigate to "AI > AI providers" in site administration
When I toggle the "Enable OpenAI API Provider" admin switch "off"
When I toggle the "Enable OpenAI API provider" admin switch "off"
And I navigate to "AI > AI placements" in site administration
And I click on the "Settings" link in the table row containing "HTML Text Editor Placement"
And I click on the "Settings" link in the table row containing "Text editor placement"
And I should see "This action is unavailable." in the table row containing "Generate text"
Then I should see "This action is unavailable." in the table row containing "Generate image"
@@ -53,14 +52,13 @@ Feature: An administrator can manage AI subsystem settings
Scenario: Placement actions should not be available for enabled Providers when an Administrator disables an Action using JavaScript
Given I am logged in as "admin"
And I navigate to "AI > AI providers" in site administration
When I toggle the "Enable OpenAI API Provider" admin switch "on"
And I should see "OpenAI API Provider enabled."
When I toggle the "Enable OpenAI API provider" admin switch "on"
And I should see "OpenAI API provider enabled."
And the following config values are set as admin:
| apikey | 123 | aiprovider_openai |
| orgid | abc | aiprovider_openai |
And I click on the "Settings" link in the table row containing "OpenAI API Provider"
And I click on the "Settings" link in the table row containing "OpenAI API provider"
And I toggle the "Generate text" admin switch "off"
And I navigate to "AI > AI placements" in site administration
And I click on the "Settings" link in the table row containing "HTML Text Editor Placement"
And I click on the "Settings" link in the table row containing "Text editor placement"
And I should see "This action is unavailable." in the table row containing "Generate text"
Then I should not see "This action is unavailable." in the table row containing "Generate image"
-3
View File
@@ -75,7 +75,6 @@ final class manager_test extends \advanced_testcase {
$this->resetAfterTest();
set_config('enabled', 1, 'aiprovider_openai');
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', 'abc', 'aiprovider_openai');
$manager = \core\di::get(manager::class);
$actions = [
@@ -144,7 +143,6 @@ final class manager_test extends \advanced_testcase {
// Enable the providers.
set_config('enabled', 1, 'aiprovider_openai');
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', 'abc', 'aiprovider_openai');
set_config('enabled', 1, 'aiprovider_azureai');
set_config('apikey', '123', 'aiprovider_azureai');
set_config('endpoint', 'abc', 'aiprovider_azureai');
@@ -420,7 +418,6 @@ final class manager_test extends \advanced_testcase {
$manager = \core_plugin_manager::resolve_plugininfo_class('aiprovider');
$manager::enable_plugin('openai', 1);
set_config('apikey', '123', 'aiprovider_openai');
set_config('orgid', 'abc', 'aiprovider_openai');
// Should now be available.
$result = manager::is_action_available($action);
+18
View File
@@ -1530,4 +1530,22 @@ final class provider_test extends \advanced_testcase {
$this->assertEquals(get_string('pluginname', 'aiprovider_openai'), $provider->get_name());
}
/**
* Test the is_request_allowed method of the provider abstract class.
*/
public function test_is_request_allowed(): void {
$stub = $this->getMockBuilder(\core_ai\provider::class)
->onlyMethods(['is_request_allowed'])
->getMockForAbstractClass();
$stub->expects($this->once())
->method('is_request_allowed')
->willReturn(true);
$actionmock = $this->createMock(\core_ai\aiactions\base::class);
$this->assertTrue($stub->is_request_allowed($actionmock));
}
}
+1 -1
View File
@@ -788,7 +788,7 @@ class manager {
if (preg_match('~^\\\\mod_([^\\\\]+)\\\\~', $indicator, $matches)) {
if (!$allmodules) {
// The first time, get all modules.
$allmodules = \core\plugin_manager::instance()->get_plugins_of_type('mod');
$allmodules = \core\plugin_manager::instance()->get_present_plugins('mod');
}
if (!array_key_exists($matches[1], $allmodules)) {
// Module does not exist, so skip indicator.

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