Compare commits

...

524 Commits

Author SHA1 Message Date
Mihail Geshoski fb02f4fa9f Moodle release 4.5.6 2025-08-08 10:48:30 +08:00
Mihail Geshoski 85a6851a8e NOBUG: Add upgrade notes 2025-08-08 10:48:29 +08:00
Sara Arjona 2db7c80f80 weekly release 4.5.5+ 2025-08-07 16:45:16 +02:00
Sara Arjona ec3ab5528a NOBUG: Add upgrade notes 2025-08-07 16:45:16 +02:00
Sara Arjona 256080fb2c NOBUG: Fixed file access permissions 2025-08-07 16:45:10 +02:00
Sara Arjona 8c2110c80c Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-08-07 16:45:07 +02:00
Huong Nguyen 9a45e5c064 Merge branch 'MDL-86004-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2025-08-07 14:10:00 +07:00
David Woloszyn db896863cb MDL-86004 core: Modify upgrade step for Microsoft endpoints
The upgrade step for Microsoft OAuth2 issuers has been modified
to address an oversight in MDL-84432. The upgrade now only updates
service base urls for multi-tenant issuers.

Co-authored-by: Raju Tummoji <raju.tummoji@moodle.com>
2025-08-07 17:01:14 +10:00
Huong Nguyen 5f0d1b806c Merge branch 'MDL-85718-405' of https://github.com/yusufwib01/moodle into MOODLE_405_STABLE 2025-08-07 12:23:54 +07:00
Huong Nguyen 789f112c86 Merge branch 'MDL-86205-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-08-07 12:15:07 +07:00
Huong Nguyen f35a5c1047 Merge branch 'MDL-85794-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-08-07 11:37:33 +07:00
Jun Pataleta 43aa89c255 MDL-86205 message: Close drawer when activating elements outside of it 2025-08-07 12:31:05 +08:00
Huong Nguyen 99dc7feb31 Merge branch 'MDL-85795-405-2' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-08-07 11:26:26 +07:00
Huong Nguyen eb0dd85d88 MDL-84217 editor_tiny: Remove incorrect map file 2025-08-07 11:13:28 +07:00
Huong Nguyen 13d7e5dc6b Merge branch 'MDL-84217-405' of https://github.com/stevandoMoodle/moodle into MOODLE_405_STABLE 2025-08-07 10:56:34 +07:00
Ilya Tregubov 1646ce747e MDL-63395 user: Fix profile visibility check.
It needs to be done in user_get_user_details as well.
2025-08-07 10:30:04 +07:00
Jun Pataleta 0082009561 Merge branch 'MDL-85674-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2025-08-07 10:44:07 +08:00
Jun Pataleta ec3f9ed5e4 Merge branch 'MDL-78233-405' of https://github.com/Tasiobg/moodle into MOODLE_405_STABLE 2025-08-07 10:35:06 +08:00
Jun Pataleta ca7501babb Merge branch 'MDL-85802-405' of https://github.com/mihailges/moodle into MOODLE_405_STABLE 2025-08-07 10:33:37 +08:00
Mihail Geshoski 6035d07677 Merge branch 'MDL-79540_405_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_405_STABLE 2025-08-07 10:19:19 +08:00
Huong Nguyen f71bd594d1 Merge branch 'MDL-84010-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2025-08-07 09:17:44 +07:00
AMOS bot 19e31c4169 Automatically generated installer lang files 2025-08-07 00:07:56 +00:00
ferran 17c8757314 Merge branch 'MDL-86176-405' of https://github.com/sarjona/moodle into MOODLE_405_STABLE 2025-08-06 16:22:00 +02:00
Sara Arjona 0427e1bf7b MDL-86176 badges: Adjust badges due to Canvas Credentials changes
This change addresses necessary adjustments to how OBV2.0 badges are
sent to backpacks, specifically to ensure compatibility and correct
functionality following recent updates to Canvas Credentials' conditions.

It ensures our badge integration continues to operate smoothly despite
these external changes.
2025-08-06 15:05:55 +02:00
Jun Pataleta 8c84d14195 MDL-85795 behat: Update button text used in search steps 2025-08-06 19:58:09 +08:00
Simey Lameze e375efca79 MDL-85674 behat: replace multiple steps by a single table step 2025-08-06 18:20:54 +08:00
andelacruz d870292683 MDL-85674 mod_grade: Behat test for multiple questions manual grading 2025-08-06 18:20:54 +08:00
Jun Pataleta 2e9c76095c Merge branch 'MDL-86095-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-08-06 15:41:11 +08:00
yusufwib01 0a3e64de5d MDL-85718 tiny_link: Improve image link behavior in TinyMCE 2025-08-06 14:31:16 +07:00
Rajneel Totaram 5008146b77 MDL-86095 mod_book: Let screenreader know print book opens in new window 2025-08-06 18:33:24 +12:00
Huong Nguyen 03430a4060 Merge branch 'MDL-85132_405_STABLE' of https://github.com/vladaskidanovas/moodle into MOODLE_405_STABLE 2025-08-06 10:54:18 +07:00
Laurent David 7616aa1eef MDL-84464 Report: Hide report for teachers without groups 2025-08-06 10:22:13 +07:00
Laurent David 6978147a03 MDL-84463 mod_feedback: Fix typo in behat test description 2025-08-06 03:05:21 +00:00
Laurent David a0f12b787b MDL-84463 mod_feedback: Fix users in no group and email
* Non editing teachers in no group should not receive feedback emails
from students in no group
2025-08-06 03:05:21 +00:00
Laurent David 890d43e1c3 MDL-84463 mod_feedback: Fix show entries and nonrespondents
* Non editing teachers not in a groups should not see entries
from other users
2025-08-06 03:05:21 +00:00
raortegar 4068e8ee2b MDL-85704 mod_bigbluebuttonbn: Update sesskey handling for compatibility 2025-08-06 03:05:21 +00:00
Huong Nguyen 4d12c8fac3 Merge branch 'MDL-85510-405' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_405_STABLE 2025-08-06 08:30:16 +07:00
Khoa Nguyen Dang f56e272ff7 MDL-85510 Questions: clearfix from MDL-84708 affects spacing
Co-authored-by: Mikel Martín Corrales <mikel@moodle.com>
2025-08-05 15:53:22 +07:00
Stevani Andolo 98f8fdee6a MDL-84217 editor_tiny: Added 'img-fluid' class to dropped image files 2025-08-05 15:00:45 +08:00
sam marshall a08193f094 MDL-84010 core_files: sync_external_file can cause infinite recursion 2025-08-05 07:49:02 +01:00
Mihail Geshoski 1159f0763b Merge branch 'MDL-86001-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-08-05 11:42:33 +08:00
Mihail Geshoski 33b7ccdd88 Merge branch 'MDL-85565_405' of https://github.com/PhilippImhof/moodle into MOODLE_405_STABLE 2025-08-05 11:35:54 +08:00
Mihail Geshoski eb97c10d89 Merge branch 'MDL-85492_405' of https://github.com/krisbax/moodle into MOODLE_405_STABLE 2025-08-05 11:20:41 +08:00
Huong Nguyen 49e3a29b00 Merge branch 'MDL-85338-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-08-05 09:11:07 +07:00
Huong Nguyen b784f20565 Merge branch 'MDL-85231-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-08-05 08:50:32 +07:00
Huong Nguyen 375e56bb9b Merge branch 'MDL-86043-405' of https://github.com/tasiobg/moodle into MOODLE_405_STABLE 2025-08-05 08:32:14 +07:00
Jun Pataleta 76f0a88d89 MDL-85795 message: Enclose the search widget in a group 2025-08-04 18:46:50 +08:00
Jun Pataleta c4b864606f MDL-85795 search: Enclose the search widget in a group 2025-08-04 18:46:49 +08:00
Shamim Rezaie 86d14f5932 Merge branch 'MDL-85787-405-2' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-08-04 09:53:52 +10:00
Jun Pataleta d1575b2739 MDL-85794 message: Set notification preferences controls within a group 2025-08-01 18:51:22 +08:00
Mihail Geshoski 9a419d4378 MDL-85802 mod_quiz: Fix double-escaping in notification content
Avoids double-escaping when filtering notification content. Adds
a unit test to validate the content filtering logic.
2025-08-01 18:50:12 +08:00
Iñigo Zendegi dc869f0c05 MDL-85802 mod_quiz: format course/quiz notification content. 2025-08-01 18:50:12 +08:00
Jun Pataleta 9e7c8cd9c0 MDL-85231 message: Style the notification buttons consistently 2025-08-01 13:09:02 +08:00
Jun Pataleta 43b5b809e6 MDL-85231 message_popup: Add a close button on the notification popover
This follows the recommendation on the ARIA Authoring Practices Guide
(APG) for modal dialogues:
> It is strongly recommended that the tab sequence of all dialogs
> include a visible element with role button that closes the dialog,
such as a close icon or cancel button.

https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
2025-08-01 13:09:02 +08:00
Laurent David b56614fce6 MDL-85231 message_popup: Add focustrap in message popup 2025-08-01 13:09:02 +08:00
David Mudrák 8143ad5cb5 MDL-85945 lang: Use fixed strings in the tests, too 2025-07-31 17:06:06 +02:00
Helen Foster 580a46bf12 MDL-85945 lang: Import fixed English strings (en_fix) 2025-07-31 17:05:30 +02:00
Sara Arjona b479c7a056 weekly release 4.5.5+ 2025-07-31 16:08:40 +02:00
Sara Arjona 353f4ed7cc NOBUG: Add upgrade notes 2025-07-31 16:08:39 +02:00
Sara Arjona 599b74c1a2 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-07-31 16:08:33 +02:00
Michael Hawkins 6498193e6d Merge branch 'MDL-85362-405' of https://github.com/HuongNV13/moodle into MOODLE_405_STABLE 2025-07-31 14:37:06 +08:00
Huong Nguyen eea759e64c Merge branch 'MDL-86062-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2025-07-31 10:21:03 +07:00
Huong Nguyen b9bea60fa8 Merge branch 'MDL-84485-Select-webservice-in-wstoken-behat-breadcrumb-405' of https://github.com/farhan6318/moodle into MOODLE_405_STABLE 2025-07-31 10:17:52 +07:00
Huong Nguyen afd0e41b69 Merge branch 'MDL-85897-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2025-07-31 08:58:32 +07:00
AMOS bot 5bf57f83c9 Automatically generated installer lang files 2025-07-31 00:08:02 +00:00
Shamim Rezaie b00188cd82 Merge branch 'MDL-85295-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-07-31 02:44:01 +10:00
Shamim Rezaie 5ea0f0f35e Merge branch 'MDL-72133-filter-deleted-logs-MOODLE_405_STABLE' of https://github.com/bwalkerl/moodle into MOODLE_405_STABLE 2025-07-31 02:27:18 +10:00
Mihail Geshoski 3e43057840 Merge branch 'MDL-86113-405' of https://github.com/snake/moodle into MOODLE_405_STABLE 2025-07-30 23:29:17 +08:00
Mihail Geshoski 8730b522e6 Merge branch 'MDL-85470-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-07-30 23:10:44 +08:00
Tasio 3bcbaf2ec8 MDL-86043 core: test for the task sending new users an email 2025-07-30 16:23:42 +02:00
Tasio d205f1bcb4 MDL-86043 core: fix sql to work in oracle
I’ve updated the query to use sql_isnotempty, which generates the correct SQL for the selected database.
I have aso added an "order by" because after some testing I noticed that Oracle and MySQL retun the results
in different order which feels inconsistent and makes it more difficult to test.
2025-07-30 16:23:34 +02:00
Paul Holden 116dc12ed1 MDL-85338 message: make messaging drawer responsive to sticky footer.
Co-authored-by: David Woloszyn <david.woloszyn@moodle.com>
2025-07-30 13:59:01 +01:00
Jun Pataleta de57e4a1cf Merge branch 'MDL-85995-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-07-30 17:10:09 +08:00
Andrew Nicols 86479d5871 MDL-86062 mod_choice: Stop calling get_string from lib.php 2025-07-30 13:58:40 +08:00
Andrew Nicols 63a21837db MDL-85897 core: Move all deprecations to emit_deprecation 2025-07-30 13:53:27 +08:00
Andrew Nicols 2181327bf2 MDL-85897 core: Add emit_deprecation() method
This changeset adds a new `\core\deprecation::emit_deprecation` method
with the same signature as the `emit_deprecation_if_found()` method.

It is intended to be used in places where something is guaranteed to
have been deprecated, and will throw appropriate debugging if the
deprecated attribute is not found.

The `emit_deprecation_if_found()` method should still be used where the
item being checked is not known to be deprecated or not, for example in
calling code.
2025-07-30 13:53:21 +08:00
Huong Nguyen f12170bb56 Merge branch 'MDL-85590_fix_modal_backdrop_attachment_point_405' of https://github.com/MariaMozgunova/moodle into MOODLE_405_STABLE 2025-07-30 08:37:46 +07:00
Farhan Karmali 4985662a5b MDL-84485 webservice: Add Behat step for mobile web service selection
This commit introduces a mandatory service selection step in our Behat tests
to ensure consistent behavior in environments with multiple third-party services.
2025-07-29 16:00:51 +05:30
Huong Nguyen 763bff0289 Merge branch 'MDL-85855-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-29 16:49:51 +07:00
Jun Pataleta af455ccfe2 MDL-85470 badges: Add a11y Behat test for the manage badges page 2025-07-29 15:17:24 +08:00
Jun Pataleta f83d35c631 MDL-85470 badges: Use badge:namewithimagelink column in badges table 2025-07-29 15:17:24 +08:00
Jun Pataleta bc100f6efa MDL-85470 reportbuilder: New column containing badge image, name, link 2025-07-29 15:17:24 +08:00
Jun Pataleta fde36bb49c MDL-85787 course: Limit course index drag and drop to certain pages only
Only allow the drag and drop functionality in the course index on pages
that provide alternatives to move course items such as the course
homepage and the course section view pages.

This is to meet the WCAG 2.2 Level AA Success Criterion 2.5.7 for
dragging movements.
See: https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements
2025-07-29 11:46:02 +08:00
Jayce Birrell 38fe5cc384 MDL-85698 core: combo box informs screen reader users 2025-07-29 10:52:55 +09:30
AMOS bot 67249bea47 Automatically generated installer lang files 2025-07-28 13:16:59 +00:00
Maria Mozgunova 20dfe6475b MDL-85590 core: Fix modal backdrop attachment point for full screen 2025-07-28 10:46:30 +01:00
Benjamin Walker b08eaaa028 MDL-72133 report_log: Add fallback context display 2025-07-28 09:06:40 +10:00
Benjamin Walker b3e2e81b0d MDL-72133 report_loglive: Display logs filtered by deleted course ids 2025-07-28 09:06:40 +10:00
Benjamin Walker eb0634d489 MDL-72133 report_log: Display logs filtered by deleted course ids 2025-07-28 09:06:40 +10:00
Philipp Imhof 59808c6870 MDL-85565 phpunit: check for <select> before <option>
Make sure that assert_select_options() will fail when the output does
not contain a <select> and therefore does not have the given options.
2025-07-25 13:13:30 +02:00
Jake Dallimore 4a02a9975d MDL-86113 mod_lti: skip slow network calls during tests
This check exists to determine whether a given tool URL is a cartridge,
specifically when the URL does not end in .xml. It hits the URL to
determine this. In tests, we have many mock tool URLs, which won't
resolve, and running this code causes large hangs and random failures.
Any tests covering cartridge support still work fine, provided they
continue to use URLs ending in .xml; this change only skips the check
during tests for other non-xml URLs.
2025-07-25 16:49:07 +08:00
Michael Hawkins 51662cb8ef weekly release 4.5.5+ 2025-07-25 12:14:36 +08:00
Michael Hawkins c3e13a4ca6 Merge branch 'MDL-83111-405' of https://github.com/sh-csg/moodle into MOODLE_405_STABLE 2025-07-24 12:01:17 +08:00
Huong Nguyen 35eec5b9aa Merge branch 'MDL-86049-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2025-07-24 09:47:51 +07:00
Huong Nguyen 3b68cecb15 Merge branch 'MDL-85504-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-07-24 09:44:11 +07:00
Rajneel Totaram 4c3be75ef2 MDL-85995 mod_book: Make previous/next buttons accessible 2025-07-24 10:08:39 +12:00
Jun Pataleta dc91c2144c MDL-85504 mod_feedback: Enhance the question edit form via JS
The drag handle and actions menu should not be within the accessible
labels of the question items. In order to enhance the question edit
form with these, they need to be rendered via JS outside of container
of the questions' accessible name.
2025-07-23 16:15:52 +08:00
Amaia Anabitarte 319113f872 Merge branch 'MDL-85989-405' of https://github.com/sarjona/moodle into MOODLE_405_STABLE 2025-07-23 10:14:00 +02:00
Jun Pataleta e894f95f6c MDL-85504 form: Legend's label template data should not be escaped
The label context data in the fieldset's legend tag should not be
escaped and allow raw HTML given that legend tags can contain
phrasing content and headings.

See developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/legend.
2025-07-23 16:10:53 +08:00
Huong Nguyen 977eacdfc0 Merge branch 'MDL-60799_405' of https://github.com/jonof/moodle into MOODLE_405_STABLE 2025-07-23 09:03:42 +07:00
Huong Nguyen d43a89d86f Merge branch 'MDL-83996-readonly-false-positive-MOODLE_405_STABLE' of https://github.com/bwalkerl/moodle into MOODLE_405_STABLE 2025-07-23 09:00:13 +07:00
Huong Nguyen 39c57e2f02 Merge branch 'MDL-84787-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-23 08:51:37 +07:00
Huong Nguyen c68104c12f Merge branch 'MDL-85573-tool-brickfield-uninstall-405' of https://github.com/szymonk1101/moodle into MOODLE_405_STABLE 2025-07-23 08:33:49 +07:00
Mihail Geshoski b177a0cee6 Merge branch 'MDL-85997-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-22 23:35:25 +08:00
Mihail Geshoski 3d41378956 Merge branch 'MDL-85038-M405_dml_missing_record_exception-when-running-mod_assign-task-send_assignment_due_soon_notification_to_user' of https://github.com/ziegenberg/moodle into MOODLE_405_STABLE 2025-07-22 23:28:41 +08:00
Mihail Geshoski 09f9052355 Merge branch 'MDL-83558-405' of https://github.com/andrewgos/moodle into MOODLE_405_STABLE 2025-07-22 13:54:02 +08:00
Huong Nguyen 1ef0196b0d MDL-85362 core: Define environment requirements for Moodle 5.1 2025-07-22 10:54:17 +07:00
Rajneel Totaram a5e3d3f018 MDL-85295 qtype_ordering: render feedback properly
'answertext' is already passed through format_text(), so no need to escape it in the template.
2025-07-22 11:40:38 +12:00
Andrew Nicols 7c4210b6ea MDL-86049 core: Do not use the component cache before purge
When trying to resolve a corrupt cache where it is not possible to
complete the Moodle setup/bootstrap, it is necessary to ignore the
current cache to load the cache purging infrastructure.
2025-07-21 12:25:26 +08:00
Benjamin Walker 5aec7f1992 MDL-83996 sessions: Fix false positive read only sessions errors 2025-07-21 10:26:27 +10:00
Mihail Geshoski c97987e9ed weekly release 4.5.5+ 2025-07-18 14:52:50 +08:00
Mihail Geshoski 266d5f8857 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-07-18 14:52:37 +08:00
Paul Holden 6a1d35dfa0 MDL-85944 block_myoverview: fix previously badly nested SCSS. 2025-07-17 15:25:05 +07:00
Mihail Geshoski d7d824e872 Merge branch 'MDL-85055-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2025-07-17 12:14:56 +08:00
Paul Holden 396f77e552 MDL-85055 task: correct use of DI provided frozen Clock API.
Fixes some of the usage introduced in tests as part of a35335a9.
2025-07-17 11:56:55 +08:00
Huong Nguyen a736250f33 Merge branch 'MDL-85050-405' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_405_STABLE 2025-07-17 10:24:34 +07:00
Huong Nguyen b0c912d6f0 Merge branch 'MDL-85944-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-17 08:53:01 +07:00
Huong Nguyen 72640fbc5a Merge branch 'MDL-81384-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-17 08:44:04 +07:00
Shamim Rezaie 29fab26069 Merge branch 'MDL-73003-405' of https://github.com/Jayce0808/moodle into MOODLE_405_STABLE 2025-07-17 07:29:47 +10:00
Mihail Geshoski 114917dc65 Merge branch 'MDL-77237-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-07-16 23:53:15 +08:00
Huong Nguyen c9c1d71c32 Merge branch 'MDL-85609-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-16 09:52:48 +07:00
Andrew Gosali a61e0d92ed MDL-83558 mod_forum: fix incorrect message on edge case scenario
(when student tries to see all participants on a forum with visible groups mode)
2025-07-15 22:46:02 +07:00
Daniel Ziegenberg 4e822cccfd MDL-85038 assignment: fix exception on sending assignment notification
When the assignment gets deleted between the creation of the ad-hoc task
mod_assign\task\send_assignment_due_soon_notification_to_user or
mod_assign\task\send_assignment_overdue_notification_to_user and its
execution, the ad-hoc task fails with a dml_missing_record_exception and
the task gets stuck.

In this case we do not want the task to fail and just return with an
appropriate mtrace.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2025-07-15 10:46:35 +02:00
meirzamoodle 07af6ccc73 MDL-77237 core: Suppress debugging during capabilities cleanup
To prevent the debugging messages from appearing during the upgrade,
I set a flag to hide them.

For the test file, I adjusted the parameters in
the unassign_capability() function, which seemed to be using
the parameter intended for assign_capability().
2025-07-15 14:36:26 +07:00
Paul Holden cada977938 MDL-85944 block_myoverview: specific styling for "My courses" page. 2025-07-15 08:02:17 +01:00
Mihail Geshoski cd409009e4 Merge branch 'MDL-85246-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-07-15 11:11:26 +08:00
Huong Nguyen ef0ba8a988 Merge branch 'MDL-72582-MOODLE_405_STABLE' of https://github.com/tsmilan/moodle into MOODLE_405_STABLE 2025-07-15 10:07:55 +07:00
Huong Nguyen 4de8318ca9 Merge branch 'MDL-86016-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2025-07-15 09:56:41 +07:00
Huong Nguyen 9bd33ef7e6 Merge branch 'MDL-85040-405-new' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-07-15 09:42:29 +07:00
Mihail Geshoski 4baac8c6ce Merge branch 'MDL-84385-requireonce-405' of https://github.com/leonstr/moodle into MOODLE_405_STABLE 2025-07-15 09:41:18 +08:00
Andrew Nicols b4092640b8 MDL-86016 core: Remove xmldb test in favour of unit test 2025-07-15 09:33:05 +08:00
Andrew Nicols 75ac9fc3ae MDL-86016 tests: Make install.xml test less restrictive 2025-07-15 09:33:04 +08:00
Amaia Anabitarte b7d3d4f191 MDL-81384 report_participation: Remove innecessary JS parameters
The parameter are usable in course participants page because user
could add bulk notes linked to users. But that script is not used
in report/participants, so we don't need those arguments on the call.

Backported from MDL-75669.
2025-07-14 21:32:30 +01:00
Paul Holden ccb3a73f98 MDL-81384 theme_boost: centre help icon margin/padding. 2025-07-14 21:32:30 +01:00
meirzamoodle d78eccdb13 MDL-85040 forms: Make required form icons decorative
The required icon in mforms is not necessary. The div containing it
already has a title attribute that enables mouse users to hover on the
icon and see its meaning.

Screen reader users will know whether a field is required or not via
the `aria-required` attribute.

Labelling the required icon via `aria-label` does not pass the
a11y audit.

Given these, it only makes sense to make the required icon decorative
for mforms.

Co-authored-by: Jun Pataleta <jun@moodle.com>
2025-07-14 14:25:23 +07:00
AMOS bot 12e3626a6d Automatically generated installer lang files 2025-07-12 00:07:54 +00:00
Paul Holden 86fe6f4ae7 MDL-86001 qbank_columnsortorder: populate preview data question text. 2025-07-11 15:23:46 +01:00
Paul Holden 1708db93e6 MDL-85997 output: require CLI library from corresponding renderer. 2025-07-11 11:59:41 +01:00
Mark Johnson 9f953080d1 MDL-79540 qbank_managecategories: Don't allow own child as parent
When we build the options for a question category selector, the
"nochildrenof" option isn't correctly compared to the category ID. This
means we can select a category's own children as its new parent.
2025-07-11 10:07:49 +01:00
Sara Arjona 0a01a0d119 MDL-85989 output: Fix choicelist when selected 0 is not first
Previously, when the selected value in a choicelist was 0 but not in
the first position, the behavior was incorrect.
This commit fixes that issue, ensuring the choicelist behaves as expected
regardless of the position of the 0 value.
2025-07-11 09:15:02 +02:00
Michael Hawkins ce34e8ff08 weekly release 4.5.5+ 2025-07-11 12:49:25 +08:00
Leon Stringer 34a0d939dd MDL-84385 mod_assign: Remove unneeded require_once 2025-07-10 09:26:28 +01:00
Huong Nguyen 14d442c52c Merge branch 'MDL-85863-405' of https://github.com/yusufwib01/moodle into MOODLE_405_STABLE 2025-07-10 10:46:48 +07:00
Mihail Geshoski c4c11a559f Merge branch 'MDL-85689-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-07-10 11:38:36 +08:00
Mark Johnson 3e8f439d17 MDL-85721 qtype_multianswer: Update find_duplicated_subquestions for Oracle compatibility 2025-07-10 10:29:08 +07:00
Huong Nguyen ab271c4c24 Merge branch 'MDL-85262-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-10 08:33:44 +07:00
Huong Nguyen ed44561319 Merge branch 'MDL-84901-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-10 08:25:44 +07:00
Mihail Geshoski b85edb5f5a Merge branch 'MDL-85939-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-09 23:25:10 +08:00
Mihail Geshoski 0a7c65c43e Merge branch 'MDL-84255-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2025-07-09 23:17:22 +08:00
Rajneel Totaram ba71a95d34 MDL-85246 mod_quiz: Fix quiz grade feedback
Using $CFG->recovergradesdefault and/or $gradeitem->refresh_grades()
are problematic when viewing a quiz. When reenrolling a user with
previous attempts, a teacher can choose not to recover the user's grades,
even when recovergradesdefault=true. This must be respected when
the user views the quiz. For site with recovergradesdefault=false,
the users always see a grade of 0, which is wrong.

This change shows the correct grade score and feedback to users and
avoids unintentionally recovering the grades.
2025-07-09 20:33:14 +12:00
Jun Pataleta 09bbcdaf32 Merge branch 'MDL-85596-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-09 14:14:48 +08:00
andelacruz 0de18a98cf MDL-85689 mod_quiz: Behat for adding and deleting page from quiz 2025-07-09 13:26:39 +08:00
Mihail Geshoski 0f5f7c8dbe Merge branch 'MDL-85721_405_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_405_STABLE 2025-07-09 10:20:09 +08:00
Huong Nguyen 4c406b2d81 Merge branch 'MDL-85697-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-07-09 09:10:53 +07:00
Paul Holden 19edba7020 MDL-85939 qbank_columnsortorder: improve preview page table alignment. 2025-07-08 17:58:38 +01:00
Kristiina.Bax aee5428591 MDL-85492 report_questioninstances: sort qtypes in alphabetical order 2025-07-08 17:14:15 +01:00
Paul Holden 2d4b15f317 MDL-85262 tool_task: switch next run time comparison in renderer.
If a task is "due", then next run time should be considered "ASAP".
2025-07-08 13:49:47 +01:00
Paul Holden 6462abc6df MDL-84901 auth: specific session start error language string. 2025-07-08 12:33:07 +01:00
Huong Nguyen 422a6f94a9 Merge branch 'MDL-84976-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-07-08 18:13:44 +07:00
Huong Nguyen 6f961cacc5 Merge branch 'MDL-85037-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-08 18:09:00 +07:00
Huong Nguyen eed6310a08 Merge branch 'MDL-85947-M405_bump-GHA-ubuntu-24-04' of https://github.com/ziegenberg/moodle into MOODLE_405_STABLE 2025-07-08 17:35:12 +07:00
andelacruz ddcaa5f8a6 MDL-85697 mod_lesson: Behat for lesson group and user overrides 2025-07-08 17:03:21 +08:00
andelacruz 6b9cbd5a19 MDL-85697 mod_assign: Behat for assignment group and user overrides 2025-07-08 17:02:06 +08:00
andelacruz 0b86e7f574 MDL-85697 mod_quiz: Behat for quiz group and user overrides 2025-07-08 16:59:49 +08:00
Luca Bösch 547cd0de94 MDL-84255 quiz: Show quiz title in heading in accessrule_seb layout. 2025-07-08 07:51:51 +02:00
Daniel Ziegenberg 323d7ba996 MDL-85947 ci: Bump GHA to Ubuntu 24.04
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2025-07-07 16:12:45 +02:00
yusufwib01 22c2f2455e MDL-85863 user: Defer new-password email until after transaction commit 2025-07-07 21:03:32 +07:00
Trisha Milan 4e9c6b3f37 MDL-72582 core_files: Add unit test for readfile_accel debugging output
Adds a unit test for the debugging message triggered when readfile_accel() detects
a non-empty output buffer. The readfile_accel() function directly manipulates the
output buffers, so calling it from within PHPUnit triggers an error like "Test code
or tested code closed output buffers other than its own".

As a workaround, the test runs a CLI script in a separate process, allowing buffer
behaviour to be isolated and debugging output to be captured for assertions.
2025-07-07 18:59:25 +10:00
Matt Rice a442938279 MDL-72582 core_files: Update readfile_accel error handling
Correct the error handling in readfile_accel to properly log errors when
working on a stored_file, rather than hiding the true error behind the
incorrect "Object of class stored_file could not be converted to
string."

Co-authored-by: Simey Lameze <simey@moodle.com>
Co-authored-by: Trisha Milan <trishamilan@catalyst-au.net>
2025-07-07 18:59:19 +10:00
Laurent David 067138aab4 MDL-81702 core_message: Add focustrap and backdrop
* Add focustrap and backdrop to message drawer.
2025-07-07 07:09:16 +02:00
Laurent David e41473d9ff MDL-81702 theme_boost: Add focus lock to drawers
* Add focus lock to drawers for small screens
2025-07-07 07:09:16 +02:00
Laurent David 97aa3dd1f9 MDL-81702 theme_boost: Remove site home link from drawers
* The site-home-link was added to all menu drawers and should
only be added to the main menu drawer (mobile version)
2025-07-07 07:09:16 +02:00
Mihail Geshoski 2fce831627 weekly release 4.5.5+ 2025-07-06 09:26:27 +08:00
Mihail Geshoski 6fe2fb1f0f NOBUG: Add upgrade notes 2025-07-06 09:26:27 +08:00
Mihail Geshoski 396a02396e Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-07-06 09:26:13 +08:00
Mihail Geshoski cb9bebdc8e Merge branch 'MDL-85350_405' of https://github.com/PhilippImhof/moodle into MOODLE_405_STABLE 2025-07-05 19:57:51 +08:00
Mihail Geshoski 9a28c68655 Merge branch 'MDL-85563-m405' of https://github.com/NeillM/moodle into MOODLE_405_STABLE 2025-07-05 19:57:51 +08:00
Paul Holden 98329e1d71 MDL-85037 block_html: correct access checks for plugin file serving. 2025-07-04 08:55:58 +08:00
Huong Nguyen 046a9c4905 Merge branch 'MDL-76342-405' of https://github.com/yusufwib01/moodle into MOODLE_405_STABLE 2025-07-03 09:07:59 +07:00
Huong Nguyen b37969c4f9 Merge branch 'MDL-85769-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-07-03 09:05:24 +07:00
Mihail Geshoski cc2d6b276d Merge branch 'patch/MDL-85666-405' of https://github.com/skodak/moodle into MOODLE_405_STABLE 2025-07-03 09:54:33 +08:00
Petr Skoda 6a4b730dfd MDL-85666 phpunit: add general plugin tests
This defines new group which can be used
to limit execution of these tests to one plugin only.

For example to execute all tests for Label module use:

phpunit --testsuite=mod_label_testsuite
phpunit --group=plugin_checks --filter=mod_label

or

phpunit --filter=mod_label
2025-07-02 07:12:13 +02:00
AMOS bot 9fa2846df4 Automatically generated installer lang files 2025-07-02 00:09:53 +00:00
Mark Johnson e721309453 MDL-85721 qtype_numerical: Prevent duplication on restore
If question_numerical record for a question has been deleted, when its
options are loaded its answers will not have a tolerance property. This
can lead to duplication.

Also, older questions may not have a question_numerical_options record.

To avoid this, we use 0 as a default tolerance for all answers if there
is no matching record, and do the same when reading the question
structure from backups. We also generate default values for the rest of
the options.
2025-07-01 11:58:59 +01:00
Mark Johnson 3101c07a97 MDL-85721 qtype: Cope with missing options records
If we restore a question (or any other) which has had its
qtype_xxx_options record deleted, we get a notification output when we
try to build the options.

This may be called from an AJAX request (such as when we duplicate a
quiz), and outputting the notification breaks the AJAX response.
Returning false also means we don't get the answers attached to the
questiondata options, so the structure doesn't match the restored data,
and we get duplication.

This emits the errors via debugging instead, which allows it to be
supressed or logged, and allows get_question_options() to continue
running.
2025-07-01 11:58:58 +01:00
Mark Johnson 8c9d16e605 MDL-85721 qtype_multianswer: Clean up duplicate subquestions
This adds an ad-hoc task to clean up duplicate subquestions created by
the bug.

When the upgrade is run, it will run a query to check if any
subquestions have been duplicated (if there are multiple questions with
the same parent, text and stamp), and queue the cleanup task if there
are.

For each stamp identified, the task will find instances of the question
that are not referred to in their parent's sequence field, confirm that
they have 0 usages, and delete them.
2025-07-01 11:58:58 +01:00
Mark Johnson d3d2d67c8e MDL-85721 qtype_multichoice: Generate default options on restore
qtype_multichoice::get_question_options() will create a default options
object if no qtype_multichoice_options record exists. This means if we
restore a backup containing a multichoice question without any options
(see previous commit), it will always create a duplicate.

This change generates a default set of options for the backupdata if
none exists, so the identity hash will match if the same question exists
in the database without options, and we dont get duplicates.
2025-07-01 11:54:50 +01:00
Mark Johnson 7c0600ae16 MDL-85721 qtype_multianswer: Don't delete qtype data for subquestions
Historically, multianswer would re-use question IDs from subquestions,
so it was necessary to delete qtype-specific data if the qtype changed.
Since versioning was introduced, editing creates new versions of the
qtype and subquestions. Deleting the data means the original versions of
the subquestions cannot function correctly, so we shouldn't do that
anymore.
2025-07-01 11:54:49 +01:00
Andrew Nicols b6f3972fad Merge branch 'MOODLE_405_STABLE' of git.in.moodle.com:moodle/integration; branch 'MDL-84531-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-07-01 17:36:47 +08:00
Neill Magill 76275dadf5 MDL-85563 phpunit: Clock API should always use Moodle system time
When using `clock::now()` the frozen cloxk and incrementing clock will now
always return a `DateTimeImmutable` that uses the configured Moodle system
time. In unit tests this will be Australia/Perth.

Before this change, it would sometimes be UCT.
2025-06-30 11:43:46 +01:00
Huong Nguyen c36274a15a weekly release 4.5.5+ 2025-06-29 16:18:49 +07:00
meirzamoodle c080b4bf58 MDL-85769 AI: Trap focus within AI drawer on smaller screens
Co-authored-by: Laurent David <laurent.david@moodle.com>
2025-06-28 10:59:41 +07:00
Paul Holden be23488e54 MDL-85855 calendar: format course shortname attribute correctly. 2025-06-26 21:47:12 +08:00
Mihail Geshoski c8116a0dbe Merge branch 'MDL-85665-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-06-26 10:44:07 +08:00
Huong Nguyen 2ed1dd557c Merge branch 'MDL-83752-M405' of https://github.com/ziegenberg/moodle into MOODLE_405_STABLE 2025-06-26 09:19:43 +07:00
Huong Nguyen fc34abe738 Merge branch 'MDL-76414-405' of https://github.com/yusufwib01/moodle into MOODLE_405_STABLE 2025-06-26 08:29:47 +07:00
Huong Nguyen c477dcd640 Merge branch 'MDL-85734-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2025-06-26 08:25:57 +07:00
Huong Nguyen c4e40860e4 Merge branch 'MDL-85466-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2025-06-26 08:22:29 +07:00
Huong Nguyen 91530e92ee Merge branch 'MDL-82109-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-26 08:19:58 +07:00
Jonathon Fowler f7b694d15f MDL-60799 enrol: update_instance() needs separate objects passed
Passing the same object means enrol_cohort does not recognise a change
in role when an edit or batch course upload operation is done.

 * enrol/editinstance.php was modifying $instance before passing it to
   enrol_plugin::update_instance() so the latter never sees a difference
   versus $data. This is redundant since update_instance() is doing the
   same thing a second time.
 * admin/tool/uploadcourse/classes/course.php is passing the same object
   as both arguments to enrol_plugin::update_instance().

There is an expectation that update_enrol_plugin_data() is to mutate its
$instance argument and then return it based on how derived classes in
enrol_guest and enrol_self behave, so cloning $instance within
update_enrol_plugin_data() before mutating it isn't an option.
2025-06-25 09:43:10 +10:00
Daniel Ziegenberg 471a73e98c MDL-83752 workshop: Handle empty feedbackreviewer
Causes PHP warnings when null on PHP 8.1.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2025-06-24 12:41:17 +02:00
andelacruz 651af33600 MDL-85665 mod_quiz: Behat to build quiz in single activity format course 2025-06-24 17:58:32 +08:00
Huong Nguyen 002398450f Merge branch 'MDL-85683-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-24 09:21:22 +07:00
Huong Nguyen 7f708151eb Merge branch 'MDL-85407-45' of https://github.com/durenadev/moodle into MOODLE_405_STABLE 2025-06-24 09:17:03 +07:00
Paul Holden 1263027e0f MDL-85596 output: update "More" sub-menus ARIA expanded attribute. 2025-06-20 21:10:29 +01:00
Luca Bösch 90ce0974bd MDL-85734 calendar: support multilang group names. 2025-06-20 16:47:45 +02:00
Luca Bösch 23dc4c7ca4 MDL-85466 course: space between number and course icon. 2025-06-20 16:47:16 +02:00
Huong Nguyen 97ed6b7083 weekly release 4.5.5+ 2025-06-20 15:14:38 +07:00
Huong Nguyen 499f6f3688 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-06-20 15:14:26 +07:00
Sara Arjona 5a22bfc175 Merge branch 'MDL-75947-integration-405-fix' of https://github.com/mihailges/moodle into MOODLE_405_STABLE 2025-06-19 17:22:08 +02:00
Mihail Geshoski 66bf9156b3 MDL-75947 ltiservice_gradebookservices: Fix unit test
Fixes the test_sequential_score_posts() unit test in lineitem_test
by removing dynamic class property assignments, which were triggering
deprecation notices.
2025-06-19 16:15:36 +08:00
yusufwib01 a14b77ec1c MDL-76414 navigation: Show 'Calendar' link in primary nav to guests 2025-06-19 13:13:58 +07:00
Huong Nguyen 8d6e21135c Merge branch 'MDL-85223-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-19 11:26:20 +07:00
Mihail Geshoski 9d661d516e Merge branch 'MDL-75947-405' of https://github.com/Jayce0808/moodle into MOODLE_405_STABLE 2025-06-19 12:18:15 +08:00
Huong Nguyen 8369f19a64 Merge branch 'MDL-85678-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-06-19 11:07:48 +07:00
Mihail Geshoski 1338ddaa3f Merge branch 'MDL-83487-405' of https://github.com/muhammadarnaldo/moodle into MOODLE_405_STABLE 2025-06-19 11:31:24 +08:00
Huong Nguyen 67827bf0fa Merge branch 'MDL-85159-405' of https://github.com/stevandoMoodle/moodle into MOODLE_405_STABLE 2025-06-19 10:03:51 +07:00
yusufwib01 7479f88d22 MDL-76342 core_output: Wrap buttons below heading on small screens 2025-06-19 10:01:33 +07:00
Mihail Geshoski 0e70433873 Merge branch 'MDL-85514-405' of https://github.com/snake/moodle into MOODLE_405_STABLE 2025-06-19 10:58:38 +08:00
Jake Dallimore d54a04197a MDL-85514 core_form: support 'in' rule for multiselects via subset of
The 'in' rule currently behaves the same way that 'eq' does when used
with multi-selects, which is not correct. It should be modelled by
checking whether the selected values are a subset of the rule values
(i.e. selected values are 'in' the rule values). This patch implements
that for core form rules as well as for the admin settings show/hide.
Several behat features are updated as well, because these were verifying
the incorrect behaviour for multi-select in rules.
2025-06-19 09:58:30 +08:00
Mihail Geshoski f6497cbe1f Merge branch 'MDL-42263-405' of https://github.com/Jayce0808/moodle into MOODLE_405_STABLE 2025-06-18 16:17:06 +08:00
Jayce Birrell 693d89cbdb MDL-73003 core_grades: Don't use 'scale' to determine grading method.
When a forum activity used a rubrics with a scale for grading, it was not treated as an advanced grading method, causing
the code to mishandle the grading object and not return any grades.
2025-06-18 16:51:20 +09:30
Huong Nguyen ccc6b2ee89 Merge branch 'MDL-84832-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-06-18 09:50:58 +07:00
Paul Holden 5d7c70c21e Merge branch 'MDL-85773-405' of https://github.com/sebastsg/moodle into MOODLE_405_STABLE 2025-06-17 11:08:46 +01:00
Sebastian Gundersen d2e1d0e76e MDL-85773 forms: Read-only selects must have static labels
This is to prevent labels with an invalid for attribute, referencing non-existing elements.
2025-06-17 11:44:35 +02:00
Tasio fc21f64863 MDL-78233 accesslib: remove unreliable test
Co-authored-by: Marina Glancy <marina.glancy@gmail.com>
2025-06-17 10:37:57 +02:00
Mihail Geshoski b5fd491b73 Merge branch 'MDL-84978-405' of https://github.com/olivabigyo/moodle into MOODLE_405_STABLE 2025-06-17 15:15:30 +08:00
Mihail Geshoski e8ac6e2fec Merge branch 'MDL-82797_405' of https://github.com/cwarwicker/moodle into MOODLE_405_STABLE 2025-06-17 14:59:52 +08:00
Paul Holden 10aece9d65 MDL-85609 tool_mfa: fix user counting for factors in use table. 2025-06-16 13:03:43 +01:00
Jun Pataleta b419fd08fc MDL-85678 mod_feedback: a11y Behat coverage for Manage templates page 2025-06-16 13:50:25 +08:00
Jun Pataleta 5c3e474160 MDL-85678 mod_feedback: Fix a11y issues in the Manage templates page
- Fix the heading hierarchy.
- Add a visually-hidden column header for the actions column.
2025-06-16 13:50:25 +08:00
Jake Dallimore 1bf62c2e46 MDL-75947 ltiservice_gradebookservices: score->timestamp as dategraded
If this is not passed in to grade_update(), then it's not passed on to
update_raw_grade(), resulting in time() being used instead, which isn't
correct. The grade timemodified value should be set to the timestamp
provided by the tool in the score post JSON, not the time of the score
post itself.

Co-authored-by: Jayce Birrell <jayce.birrell@moodle.com>
2025-06-16 14:43:46 +09:30
Jake Dallimore 036f61da49 MDL-75947 ltiservice_gradebookservices: test sequential score posting
This tests highlights a problem with the score handling logic and
will currently fail. On score post, the current time is used for
grade->timemodified instead of the score->timestamp provided by the
tool in the POST JSON.
2025-06-16 14:43:46 +09:30
aya-saad1 e6894fcf11 MDL-42263 assign: Force language of email sent to graders
Co-authored-by: Jayce Birrell <jayce.birrell@moodle.com>
2025-06-16 11:01:18 +09:30
AMOS bot 4fceaed909 Automatically generated installer lang files 2025-06-15 00:09:52 +00:00
Mihail Geshoski 95518023c6 weekly release 4.5.5+ 2025-06-13 14:43:42 +08:00
Mihail Geshoski fe0d7c9b0a NOBUG: Add upgrade notes 2025-06-13 14:43:42 +08:00
Paul Holden 56801cdf3b MDL-84531 core: default deprecated attribute $replacement to null. 2025-06-12 14:50:56 +01:00
Huong Nguyen 9691e4d4c6 MDL-85316 dml: Revert DB vendor changes 2025-06-12 17:11:26 +07:00
Jun Pataleta d2711e792f Merge branch 'MDL-84752-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-12 17:15:43 +08:00
Paul Holden 102621f53d MDL-84752 qtype_essay: create accessible min/max words form elements.
Because of historical requirements involving fieldsets in question
type forms (see 958e7671), we should use ARIA label attribute on
grouped elements rather than normal labels in order to make them
accessible.

Co-authored-by: Jun Pataleta <jun@moodle.com>
2025-06-12 10:11:48 +01:00
Jun Pataleta 44fc7bd927 Merge branch 'MDL-85700-405' of https://github.com/roland04/moodle into MOODLE_405_STABLE 2025-06-12 17:06:40 +08:00
Huong Nguyen 18b20273fd MDL-72123 message: Add upgrade note 2025-06-12 17:06:40 +08:00
Huong Nguyen 49729e14a4 Merge branch 'MDL-72123-405' of https://github.com/yusufwib01/moodle into MOODLE_405_STABLE 2025-06-12 17:06:39 +08:00
Huong Nguyen 97ccd815f9 Merge branch 'MDL-84611-405' of https://github.com/sh-csg/moodle into MOODLE_405_STABLE 2025-06-12 08:37:34 +07:00
Mikel Martín abdf765a28 MDL-85700 theme_boost: Fix singleselect spacing
- Fix single_select template form layout.
2025-06-11 13:53:03 +02:00
Justin Hunt bd54d58d8a MDL-82797 question engine: gift import fix 2025-06-11 11:58:23 +01:00
Stefan Hanauska 172277eae4 MDL-84611 blocks: Respect instance_allow_multiple() 2025-06-11 11:22:05 +02:00
Stefan Hanauska 110e4f7aed MDL-84611 block_html: Change tests to respect capabilities 2025-06-11 11:22:05 +02:00
Huong Nguyen 8061a3cdc8 Merge branch 'MDL-77964-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-11 14:08:50 +07:00
Huong Nguyen 60c73f7ff7 Merge branch 'MDL-85316-405-mysql-version' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-06-11 13:33:49 +07:00
Huong Nguyen d83b08f92c Merge branch 'MDL-85274-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2025-06-11 13:30:18 +07:00
David Woloszyn 5dd77e0022 MDL-85274 calendar: Duration limits added to forms 2025-06-11 14:30:11 +10:00
meirzamoodle cc7efbf977 MDL-85316 admin: Add environment check for AWS Aurora database 2025-06-11 10:44:12 +07:00
Philipp Imhof cd11b9533f MDL-85350 questions: skip restore test for certain 3rd party plugins
The test_restore_course_with_same_stamp_questions() test assumes
that all question types using answers will also use the table
"question_answers" to store said answers. However, some 3rd party
qtypes might use custom tables and for those, the test would fail.
2025-06-06 15:22:19 +02:00
Mihail Geshoski 812ef23c00 Moodle release 4.5.5 2025-06-06 12:32:23 +08:00
Mihail Geshoski 59d4d28e84 NOBUG: Add upgrade notes 2025-06-06 12:32:23 +08:00
Rajneel Totaram 436c8070e2 MDL-84976 tool_policy: noclean param was not set 2025-06-06 15:14:40 +12:00
Paul Holden 4e1feb2c4e MDL-85683 enrol: use formatted course name for notification context. 2025-06-06 00:22:13 +01:00
yusufwib01 8c96b52f08 MDL-72123 message: Hide add to contacts button if user not allowed 2025-06-06 01:09:29 +07:00
Szymon Karolczuk dd639a9516 MDL-85573 tool_brickfield: fix uninstall code 2025-06-05 19:16:20 +02:00
Sara Arjona 4b87c45497 weekly release 4.5.4+ 2025-06-05 16:43:39 +02:00
Sara Arjona 19baebf67d NOBUG: Add upgrade notes 2025-06-05 16:43:39 +02:00
Michael Hawkins 4ecfbc393d MDL-83762 core_files: Bind resolve IPs and ports to cURL calls 2025-06-05 12:09:50 +07:00
Michael Hawkins ac62ce580c Merge branch 'MDL-85571-405' of https://github.com/HuongNV13/moodle into MOODLE_405_STABLE 2025-06-05 12:35:12 +08:00
Vincent Schneider ab5d693113 MDL-84518 course: improved course visibility state handling 2025-06-05 11:22:29 +07:00
Michael Hawkins 74aa57d9cd Merge branch 'MDL-80380-405' of https://github.com/HuongNV13/moodle into MOODLE_405_STABLE 2025-06-05 12:20:23 +08:00
Jun Pataleta a86500fe34 Merge branch 'MDL-85450-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-06-05 12:15:52 +08:00
Huong Nguyen 2225c55acc MDL-80380 core_auth: Add upgrade note 2025-06-05 11:14:52 +07:00
Huong Nguyen 6abea88dac MDL-80380 admin: Support Microsoft XOAUTH2 for outgoing email 2025-06-05 11:14:51 +07:00
Mihail Geshoski 484b07cc5c Merge branch 'MDL-69765-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2025-06-05 12:11:21 +08:00
Jun Pataleta 0dd92929b4 Merge branch 'MDL-84941-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-05 12:08:44 +08:00
Mihail Geshoski 0319bb49a7 Merge branch 'MDL-85072-405' of https://github.com/olivabigyo/moodle into MOODLE_405_STABLE 2025-06-05 11:01:17 +07:00
Mihail Geshoski 58b92a238e Merge branch 'MDL-83654-405-5' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-06-05 11:01:17 +07:00
Mihail Geshoski 84dfd5459e Merge branch 'MDL-85369_405' of https://github.com/agaranin/moodle into MOODLE_405_STABLE 2025-06-05 11:01:17 +07:00
Mark Johnson 5abbfe4fd7 MDL-85323 core: Don't cache the login page 2025-06-05 11:01:04 +07:00
meirzamoodle 07cd48917c MDL-85375 libraries: Escaping a query parameter on pg_insert_id() 2025-06-05 01:30:20 +00:00
Vincent Schneider 8c5fad91df MDL-84706 bigbluebuttonbn: improved authorization and mitigate CSRF risks 2025-06-05 01:30:20 +00:00
Huong Nguyen c827a17f27 MDL-79993 course: Fix PHPUnit failure 2025-06-05 01:30:20 +00:00
raortegar b4011745cd MDL-79993 course: Improve user access to recent courses service 2025-06-05 01:30:20 +00:00
Vincent Schneider 47ba1b63f7 MDL-84497 badges: fix missing action sesskey checks. 2025-06-05 01:30:20 +00:00
Jun Pataleta 55abeaa7d4 Merge branch 'MDL-85239-405' of https://github.com/NashTechOpenUniversity/moodle into MOODLE_405_STABLE 2025-06-05 09:22:54 +08:00
Jun Pataleta e3271c38b5 Merge branch 'MDL-84804-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-05 08:12:44 +08:00
Sara Arjona a949faf7fc Merge branch 'MDL-82069-405' of https://github.com/aanabit/moodle into MOODLE_405_STABLE 2025-06-04 15:37:04 +02:00
Paul Holden c14a3786b4 MDL-84804 output: amend page title when navigating dynamic tabs.
Prepend the current tab name to the page title, to ensure we can
easily identify the current page/tab and that it is both unique
and accessible.
2025-06-04 14:09:55 +01:00
Paul Holden 6e0e718a39 MDL-84804 javascript: new module for manipulating the page title. 2025-06-04 14:07:28 +01:00
Jun Pataleta e9613e37e2 Merge branch 'MDL-85041-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-06-04 17:48:24 +08:00
Jun Pataleta cb990d2c07 MDL-85041 core: Make methods calling announceChanges async as well 2025-06-04 16:22:25 +08:00
Mihail Geshoski 1201e7b61a Merge branch 'MDL-85469-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-06-04 14:12:52 +08:00
Huong Nguyen 3272b7d6a1 MDL-85571 mod_assign: Improve PHPUnit tests 2025-06-04 12:50:39 +07:00
raortegar 8f8fb98cfd MDL-85571 mod_assign: Add visibility check to due digest notification 2025-06-04 12:50:39 +07:00
Jun Pataleta 3d9610fed5 Merge branch 'MDL-85507-405-enfix' of https://github.com/mudrd8mz/moodle into MOODLE_405_STABLE 2025-06-04 11:58:52 +08:00
Huong Nguyen beb8034e21 Merge branch 'MDL-84732-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2025-06-04 10:53:52 +07:00
Mihail Geshoski 1e79fe439a Merge branch 'MDL-84432-405' of https://github.com/HuongNV13/moodle into MOODLE_405_STABLE 2025-06-04 10:47:49 +08:00
Huong Nguyen 3c3b1f9aa7 MDL-84432 core: Use discovery endpoint for Microsoft OAuth2 service
- Instead of creating the endpoints manually, use the OpenId
configuration endpoint to auto-configure endpoints
- Updates user field mappings so they map the new OpenId userinfo fields
2025-06-04 08:41:39 +07:00
Amaia Anabitarte c535d469fb Merge branch 'MDL-85471-405' of https://github.com/junpataleta/moodle into MOODLE_405_STABLE 2025-06-03 16:19:29 +02:00
cescobedo 8cd1f17819 Merge branch 'MDL-85398-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-03 15:51:59 +02:00
Amaia Anabitarte b38113be6e Merge branch 'MDL-85327-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-06-03 13:37:53 +02:00
Jun Pataleta bb4cf1e151 Merge branch 'MDL-85467-405' of https://github.com/yusufwib01/moodle into MOODLE_405_STABLE 2025-06-03 17:28:39 +08:00
Rajneel Totaram d2646aee84 MDL-85450 block_calendar_upcoming: Fix heading level 2025-06-03 09:40:48 +12:00
Amaia Anabitarte b65fe2d786 Merge branch 'MDL-85412-405' of https://github.com/aanabit/moodle into MOODLE_405_STABLE 2025-06-02 13:24:42 +02:00
yusufwib01 e2aa6e03c6 MDL-85467 core: Replace orphaned label with span for accessibility
This commit replaces orphaned labels with spans for improved
accessibility. It also updates the XPATH partial named selector
for select_menu fields to target span elements.
2025-06-02 13:46:11 +07:00
hieuvu fb036fe8aa MDL-85239 mod_quiz: Add caption for Attempt tables. 2025-06-02 13:38:05 +07:00
meirzamoodle bff7dffe16 MDL-85041 core: Improve autocomplete/tag a11y for assistive tech
- Updated autocomplete behavior to announce dynamic changes
via ARIA live regions
- Fixed focus management for keyboard and screen reader navigation
- Added proper role/aria tags for interactive tag components
2025-06-02 10:38:29 +07:00
Luca Bösch 39e627ecc5 MDL-69765 qtype_essay: Create temporary draft file area only one time. 2025-05-31 12:58:24 +02:00
Jun Pataleta b469c13132 MDL-83654 qtype_match: Only add the question text to the first field
In order to avoid repetition of the question text as the user navigates
to each answer field in a matching question (e.g. by tabbing).
2025-05-31 09:24:45 +08:00
Jun Pataleta c8501791c4 MDL-83654 qtype_match: Add presentation role to table-related elements
The question and answer are displayed on a layout table and
does not really help with accessibility. We need to set a
presentation role for the table-related elements.
2025-05-31 09:24:44 +08:00
Jun Pataleta 5d6b8b0080 MDL-83654 qtype_match: Provide better information to answer fields
* In order to provide better context for screen reader users about the
answer fields in matching questions, the question text and the
corresponding item to be matched are included to the answer fields via
the aria-describedby attribute.
2025-05-31 09:24:44 +08:00
Amaia Anabitarte 98ba1909f2 MDL-85412 course: adding and removing elements feedback message 2025-05-30 16:44:01 +02:00
vlad.kidanov a9b8b52a16 MDL-85132 mod_glossary: Add missing end div for entrybox element. 2025-05-30 10:30:06 +01:00
Jun Pataleta 3f16708b55 MDL-84832 tiny_media: Announce when alt text maxlength is reached
Co-authored-by: Meirza <meirza.arson@moodle.com>
2025-05-30 17:08:18 +08:00
Michael Hawkins 7acd85a1aa weekly release 4.5.4+ 2025-05-30 16:29:22 +08:00
Michael Hawkins e12aa38444 NOBUG: Add upgrade notes 2025-05-30 16:29:21 +08:00
Michael Hawkins 03da88b840 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-05-30 16:28:54 +08:00
Artem Garanin 1a655e88db MDL-85369 question: fix tag collection ID in legacy‑filter upgrade.
Use the actual tag collection for the 'question' tag area instead of
the default collection.
2025-05-29 14:13:34 -04:00
Paul Holden 586ead512c MDL-85223 reportbuilder: initialize user entity filters just once. 2025-05-29 15:32:30 +01:00
Paul Holden 1e5ad34897 MDL-77964 availability: avoid JS console errors when closing modal. 2025-05-29 10:15:31 +01:00
Michael Hawkins dc3c3ad7bb Merge branch 'MDL-84824-405' of https://github.com/stevandoMoodle/moodle into MOODLE_405_STABLE 2025-05-29 12:27:43 +08:00
Michael Hawkins 9c26cc5eaa Merge branch 'MDL-83448-405' of https://github.com/stevandoMoodle/moodle into MOODLE_405_STABLE 2025-05-29 12:18:50 +08:00
Michael Hawkins eb3a479362 Merge branch 'MDL-84996-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-05-29 12:10:33 +08:00
Michael Hawkins f67dc4491f Merge branch 'MDL-85437-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-05-29 11:53:10 +08:00
Stevani Andolo 447b50e660 MDL-84824 core_message: Fixed popup accessibility issue 2025-05-29 11:49:25 +08:00
Huong Nguyen fe1125a335 Merge branch 'MDL-83044-405' of https://github.com/catalyst/moodle into MOODLE_405_STABLE 2025-05-29 10:27:27 +07:00
Huong Nguyen c26b7d63b8 Merge branch 'MDL-85525-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-05-29 09:51:52 +07:00
Huong Nguyen 5e847a50d7 Merge branch 'MDL-85400-405' of https://github.com/lameze/moodle into MOODLE_405_STABLE 2025-05-29 08:59:53 +07:00
Huong Nguyen 7a804a5eea Merge branch 'MDL-85389-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-05-29 08:52:47 +07:00
AMOS bot c17c801ca2 Automatically generated installer lang files 2025-05-29 00:07:56 +00:00
andelacruz 83103830ad MDL-85525 mod_quiz: Behat test for quiz attempt page block display 2025-05-28 16:49:55 +08:00
andelacruz 8e89733cb0 MDL-85389 mod_lesson: Behat for filtering lesson reports/essays by group 2025-05-28 15:19:47 +08:00
sam marshall 4b14b73977 MDL-85400 PHPunit: Hard to test code that uses encryption
This change stops the encryption code setting created key files to
read-only during PHPunit runs, which means they will be safely
deleted when the system resets after a test.
2025-05-28 12:59:17 +08:00
meirzamoodle 8e77499d4f MDL-85437 AI: Move focus to the AI drawer 2025-05-28 11:31:30 +07:00
Jun Pataleta ecf7cede8c Merge branch 'MDL-84806-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2025-05-27 15:37:12 +08:00
Huong Nguyen c740028db4 Merge branch 'MDL-85169-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-05-27 09:16:15 +07:00
Alexander Van der Bellen 5fff8ff000 MDL-83044 core_block: Add return value check on form submission 2025-05-26 23:03:47 +08:00
Sara Arjona 636c0905dd Merge branch 'MDL-85034-MOODLE_405_STABLE' of https://github.com/phmemmel/moodle into MOODLE_405_STABLE 2025-05-26 15:26:01 +02:00
ferran 0eb18e5231 Merge branch 'MDL-84304-405' of https://github.com/laurentdavid/moodle into MOODLE_405_STABLE 2025-05-26 13:50:14 +02:00
Helen Foster 06e37a266b MDL-85507 lang: Import fixed English strings (en_fix) 2025-05-25 09:03:07 +02:00
sam marshall e20e01038f MDL-84732 Accessibility: Focus issue after closing nested modal 2025-05-23 15:46:57 +01:00
Mikel Martín 4d08038681 MDL-85469 mod_feedback: Refactor editor drag and drop
- Remove YUI drag and drop.
- Add new 'mod_feedback\external\questions\reorder' web service.
- Use SortableList JS component to refactor drag and drop, using
  the new webservice.
- Update new SCSS styles
- Fix and create Behat scenarios
2025-05-23 16:29:09 +08:00
Mikel Martín 79dec70789 MDL-85469 mod_feedback: Refactor edit amd module 2025-05-23 16:29:09 +08:00
Huong Nguyen 7f5234ab13 weekly release 4.5.4+ 2025-05-23 11:03:56 +07:00
Huong Nguyen 1e03f058ec Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-05-23 11:03:49 +07:00
David Woloszyn c421dce7bf MDL-84806 tiny_aiplacement: Remove unused div and css 2025-05-23 12:47:55 +10:00
David Woloszyn a55c0e0067 MDL-84806 tiny_aiplacement: Announce action results for accessibility
The generatetext.js and associated templates have been adjusted to
match more closely with the generate image files. The generate image
way of displaying content was better suited to aria.
2025-05-23 12:47:47 +10:00
Stevani Andolo c5cc10836f MDL-83448 core_hub: Fixed registration check 2025-05-22 13:44:01 +08:00
Huong Nguyen 20c233697f Merge branch 'MDL-84899-405' of https://github.com/laurentdavid/moodle into MOODLE_405_STABLE 2025-05-22 11:01:10 +07:00
Huong Nguyen b358c4ccc9 Merge branch 'MDL-84793-m405' of https://github.com/sammarshallou/moodle into MOODLE_405_STABLE 2025-05-22 10:48:33 +07:00
Huong Nguyen 1f43870066 Merge branch 'MDL-84918-405' of https://github.com/HuongNV13/moodle into MOODLE_405_STABLE 2025-05-22 10:34:40 +07:00
David Woloszyn 3823915d80 MDL-84918 core: Add zend.exception_ignore_args environment check 2025-05-22 10:10:36 +07:00
Huong Nguyen 69809efd38 MDL-84918 core: Add initial environment requirements for Moodle 5.1 2025-05-22 10:10:36 +07:00
Huong Nguyen 2486cd3f48 Merge branch 'MDL-74900-405' of https://github.com/raortegar/moodle into MOODLE_405_STABLE 2025-05-22 09:37:26 +07:00
Katalin Lukacs Toth 9a23fc37fb MDL-84978 mod_forum: Fix latest/earliest post id lookup in a discussion
This properly fixes the problems that commit 0f5a96f in MDL-80848 tried
to address.
2025-05-21 11:04:19 +02:00
Katalin Lukacs Toth 6c3703e7f5 MDL-85072 qtype_ordering: Fix XML export
Option fields should not be left empty.
2025-05-21 10:54:15 +02:00
Huong Nguyen a04e96ae82 Merge branch 'MDL-84274-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2025-05-21 13:36:09 +07:00
raortegar 26e5baae62 MDL-74900 core_course: Exception in module deletion if missing instance 2025-05-21 08:27:29 +02:00
Huong Nguyen 01a8018de4 Merge branch 'MDL-84296-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2025-05-21 10:00:27 +07:00
Huong Nguyen 2e7075d121 Merge branch 'MDL-85374-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2025-05-21 09:56:06 +07:00
AMOS bot 13b626da79 Automatically generated installer lang files 2025-05-21 00:07:53 +00:00
Paul Holden bf3c210d82 MDL-82109 notes: include link to add site note if user has capability. 2025-05-20 13:18:37 +01:00
Andrew Nicols 60ff3ef255 MDL-85374 report_competency: Create custom step for setting autocomplete
The autocompletes used in the competency report have been bastardised to
redirect on selection. Unfortunately this also applies when when making
null-op changes like deleting the initial "Please select a value"
option.

The autocomplete code removes all current options before creating an
option, and because of this redirect the browser is redirecting before
the new value can be entered, but we retain a reference to the field as
`$this->field`, which is now stale.
2025-05-20 12:42:20 +08:00
Amaia Anabitarte 73969986d9 Merge branch 'MDL-85397-405' of https://github.com/tasiobg/moodle into MOODLE_405_STABLE 2025-05-19 12:43:45 +02:00
Laurent David 5ebb301598 MDL-84304 core_courseformat: Remove COMPLETION_COMPLETE_FAIL test
* Because we removed this status in mod_scorm, we cannot test it
anymore against any module as no module has custom_rules that leads
to COMPLETION_COMPLETE_FAIL
2025-05-19 11:56:46 +02:00
Laurent David c5b189382b MDL-84304 mod_scorm: Remove completion failed from behat test
* Now that we removed the COMPLETION_COMPLETE_FAIL status for scorm
behat tests needs to be updated
2025-05-19 11:56:46 +02:00
Magnus Samuelsson 84908f78b9 MDL-84304 mod_scorm: Remove the COMPLETION_COMPLETE_FAIL status 2025-05-19 11:56:46 +02:00
Amaia Anabitarte 98513288b7 MDL-82069 core_completion: Improve errors for multiple grading items 2025-05-19 09:33:38 +02:00
Muhammad Arnaldo 14c33bf2a8 MDL-83487 mod_forum: retain upcoming posts in user digests 2025-05-16 15:35:14 +07:00
Jun Pataleta 9c4fb88800 MDL-85471 theme_boost: Dismiss tooltips on escape 2025-05-16 14:21:00 +08:00
Mihail Geshoski 4aefa6b85d weekly release 4.5.4+ 2025-05-16 12:58:58 +08:00
Mihail Geshoski 03a1a221fb Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-05-16 12:58:35 +08:00
toanlamt cbda104d14 MDL-85050 Javascript: core/dropzone Fix link & box click event conflict 2025-05-15 15:11:54 +07:00
sam marshall 6a56158088 MDL-84793 Behat: Allow CLI scripts to run on Behat instance 2025-05-15 08:50:49 +01:00
Stevani Andolo 46272804bf MDL-84296 core_hub: Added detailed AI usage data to registration page 2025-05-15 16:51:18 +10:00
Huong Nguyen d58f4da539 Merge branch 'MDL-83350-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-05-15 12:02:37 +07:00
Huong Nguyen 8603d2939d Merge branch 'MDL-84710-405' of https://github.com/Jayce0808/moodle into MOODLE_405_STABLE 2025-05-15 11:59:08 +07:00
Huong Nguyen f9ea5d052e Merge branch 'MDL-84073-405' of https://github.com/sh-csg/moodle into MOODLE_405_STABLE 2025-05-15 11:57:33 +07:00
Huong Nguyen 16720f9862 Merge branch 'MDL-83943-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-05-15 11:45:38 +07:00
Huong Nguyen 59a4f3a8b3 Merge branch 'MDL-85279-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-05-15 11:42:44 +07:00
Huong Nguyen c7151238c2 Merge branch 'MDL-84009-405' of https://github.com/raortegar/moodle into MOODLE_405_STABLE 2025-05-14 21:52:05 +07:00
Sara Arjona 2f98ab5f1f Merge branch 'MDL-85449-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Sara Arjona 600a4872fd Merge branch 'MDL-81436-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Sara Arjona 75463bb063 Merge branch 'MDL-81842-405' of https://github.com/laurentdavid/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Huong Nguyen 08a285be79 Merge branch 'MDL-84128-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Huong Nguyen b98919b34e Merge branch 'MDL-85363-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Huong Nguyen 408993643f Merge branch 'MDL-84964-405' of https://github.com/Jayce0808/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
ferran 7df327305f Merge branch 'mdl-84520_405' of https://github.com/james-cnz/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Sara Arjona cf3c244d49 Merge branch 'MDL-85248-405' of https://github.com/albertgasset/moodle into MOODLE_405_STABLE 2025-05-14 21:42:47 +07:00
Tasio 0b5d418a49 MDL-85397 theme: update reports to use container queries
With container queries, responsive design is no longer limited to the full browser width. For example, we can now display
the report in a compact side panel, and it will automatically adapt its styling to suit smaller spaces.
2025-05-14 15:55:07 +02:00
raortegar 502bcbfb01 MDL-84009 factor_webauthn: Add additional security keys 2025-05-14 11:20:54 +02:00
raortegar ef1b8d05f6 MDL-84009 tool_mfa: Additional factor instances support 2025-05-14 11:20:51 +02:00
Paul Holden ff3a757421 MDL-84996 enrol_manual: ensure externally supplied users are valid. 2025-05-14 09:55:53 +01:00
andelacruz b80477a8c6 MDL-85279 mod_assign: Renamed behat test to a more specific name 2025-05-14 15:13:35 +08:00
andelacruz bb275f31d6 MDL-85279 mod_page: Fix behat to match the expected behaviour 2025-05-14 15:12:49 +08:00
Stevani Andolo 0b719c3951 MDL-85159 editor_tiny: Fix language list and track srclang a11y issue 2025-05-14 09:22:05 +08:00
Rajneel Totaram d0a76a67d7 MDL-81436 theme: Fix scope of showmore button selector
Co-authored-by: Mikel Martín <mikel@moodle.com>
2025-05-13 17:39:49 +12:00
meirzamoodle fbca55fa27 MDL-83350 files: Avoid cacheing user and file repo files
Set the lifetime to zero for files referenced in
the local/internal repository (private files and file system),
because they should not be cached.

Add `no-store` to the cache-control to ensure resources are
never cached, always fetching the latest version.
2025-05-13 09:37:46 +07:00
Jun Pataleta 8df0f78659 Merge branch 'MDL-84817-405' of https://github.com/davewoloszyn/moodle into MOODLE_405_STABLE 2025-05-12 12:44:42 +08:00
Laurent David 8500a67d21 MDL-81842 formlibs: Change display in sticky footer
* Make sure that form elements that are inserted in the
sticky footer are not wrapped
2025-05-12 06:23:55 +02:00
Jayce Birrell d271d670aa MDL-84710 theme_boost: do not apply popper css rules to rtl dropdowns 2025-05-12 11:05:52 +09:30
Paul Holden f0d973cfaa MDL-85449 block_myoverview: preserve documentation language params.
Fixes the link to Moodle docs from zero state.
2025-05-11 19:27:46 +01:00
AMOS bot d82078046a Automatically generated installer lang files 2025-05-10 00:07:55 +00:00
Paul Holden 4f551a8628 MDL-85398 blocks: constrain width of block controls dropdown menu. 2025-05-09 12:52:52 +01:00
Laurent David f5b15b044e MDL-84899 mod_forum: Fix summary report form change checker
* The forum summary report was not removing the right form
from the list of forms to check for changes.
2025-05-09 08:43:54 +02:00
Laurent David 5c2095cb12 MDL-84899 core_form: Fix unWatchForm in FormChangeChecker
* The unWatchForm as it stood was not removing the form from the list.
2025-05-09 08:43:54 +02:00
meirzamoodle 686011ef42 MDL-83943 core_tag: Fix the broken user tag pagination 2025-05-09 12:49:56 +07:00
Philipp Memmel 27c4ebdace MDL-85034 core_course: Add index to course_sections for mod_subsection
This is a backport of MDL-84844.
2025-05-09 07:25:20 +02:00
meirzamoodle 376d76979d MDL-84128 core: Flip the image according to its orientation in PHP GD 2025-05-09 11:17:36 +07:00
Huong Nguyen 6dd1f61866 weekly release 4.5.4+ 2025-05-09 09:50:26 +07:00
Huong Nguyen 6679d9acb7 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-05-09 09:50:19 +07:00
Stefan Hanauska cec5aa80d1 MDL-84073 blocks: Load invisible blocks 2025-05-08 14:37:47 +02:00
Daniel Ureña 5d640c4b5c MDL-85407 mod_data: Fix unclosed HTML in list view 2025-05-08 11:15:49 +02:00
Luca Bösch 22779cc577 MDL-85363 quiz: style the question number inplace editable nicely. 2025-05-08 11:08:05 +02:00
David Woloszyn 20fe68e173 MDL-84817 core_message: Fix display issues in drawer at 400% 2025-05-08 17:09:01 +10:00
Huong Nguyen 3ac90327fc Merge branch 'MDL-85341-405' of https://github.com/snake/moodle into MOODLE_405_STABLE 2025-05-08 10:52:43 +07:00
Huong Nguyen 5f317f31a0 Merge branch 'MDL-84708-405' of https://github.com/danghieu1407/moodle into MOODLE_405_STABLE 2025-05-08 09:48:19 +07:00
Huong Nguyen c987a7a82e Merge branch 'MDL-84677-405' of https://github.com/lucaboesch/moodle into MOODLE_405_STABLE 2025-05-08 09:28:25 +07:00
Huong Nguyen 01b016b2cb Merge branch 'MDL-84597-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-05-08 09:05:20 +07:00
Huong Nguyen 4c400a892b Merge branch 'MDL-85220-405' of https://github.com/rjnl/moodle into MOODLE_405_STABLE 2025-05-08 08:59:14 +07:00
Huong Nguyen edb250f91d Merge branch 'MDL-84654-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-05-08 08:44:25 +07:00
Amaia Anabitarte 7ec2f412d0 Merge branch 'MDL-85361-405' of https://github.com/sarjona/moodle into MOODLE_405_STABLE 2025-05-07 14:02:17 +02:00
Sara Arjona ac2a24ec08 Merge branch 'MDL-83422-405' of https://github.com/meirzamoodle/moodle into MOODLE_405_STABLE 2025-05-07 13:50:22 +02:00
AMOS bot f9936a93b1 Automatically generated installer lang files 2025-05-07 00:07:49 +00:00
Jake Dallimore e2b6ee0e3b MDL-85341 core: remove unnecessary sesskey from module controlmenu items
This impacts the following controls:
- edit (sesskey removed from link)
All other controls should remain unchanged in terms of their use of
sesskey, supporting action handling for non-js course home (see non-js
behat tests move_activities.feature).
2025-05-06 13:54:31 +08:00
Angelia Dela Cruz 99ad02ac3f MDL-84654 mod_assign: Assignment additional files can be hidden 2025-05-06 12:53:48 +08:00
Huong Nguyen cfbb912f11 Merge branch 'MDL-85310-405' of https://github.com/andelacruz/moodle into MOODLE_405_STABLE 2025-05-06 10:32:13 +07:00
Sara Arjona 6a49c34b5c MDL-85361 block_social_activity: Fix inline editing text field 2025-05-05 08:16:59 +02:00
Paul Holden 71ae1110ff MDL-85169 forms: focus grouped fields element based on parent data.
This fixes the previous attempt at focusing the first field within
grouped elements (aec60788) which inadvertently introduced duplicate
IDs.
2025-05-02 13:47:22 +01:00
meirzamoodle 0e9f389e74 MDL-83422 tiny_media: Fix modal footer layout
Co-authored-by: Mikel Martín <mikel@moodle.com>
2025-05-02 19:46:41 +07:00
Luca Bösch 75842dcd42 MDL-84677 backup: Filter course shortnames in copy progress viewer. 2025-05-02 08:51:37 +02:00
Huong Nguyen a57387fe2d weekly release 4.5.4+ 2025-05-02 09:16:23 +07:00
Huong Nguyen c22c1099d8 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-05-02 09:16:16 +07:00
Paul Holden c60d7ed620 MDL-85327 admin: observe show/hide settings on category page.
Co-authored-by: Carlos Castillo <carlos.castillo@moodle.com>
2025-05-01 10:55:30 +01:00
AMOS bot d696c58951 Automatically generated installer lang files 2025-05-01 00:07:56 +00:00
Angelia Dela Cruz c4e085aae9 MDL-85310 qtype: Renamed duplicate scenario names to fix warning 2025-04-30 13:31:21 +08:00
Sara Arjona 3674b609cc Merge branch 'MDL-84805-405' of https://github.com/aanabit/moodle into MOODLE_405_STABLE 2025-04-29 15:31:56 +02:00
Amaia Anabitarte dc8e94eef8 MDL-84805 badges: Titles must be unique 2025-04-29 11:14:07 +02:00
Rajneel Totaram 4a6e86b652 MDL-85220 block_recentlyaccesseditems: Fix heading level 2025-04-29 10:13:23 +12:00
Sara Arjona 8b4beeb09a Merge branch 'MDL-84192-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-28 11:25:24 +02:00
Huong Nguyen 5387945514 Merge branch 'MDL-84983-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-28 10:56:34 +07:00
Huong Nguyen b0d338fd10 Merge branch 'MDL-84539-405' of https://github.com/andrewgos/moodle into MOODLE_405_STABLE 2025-04-28 08:59:40 +07:00
Huong Nguyen b355ffc504 Merge branch 'MDL-84421-405' of https://github.com/andrewnicols/moodle into MOODLE_405_STABLE 2025-04-25 09:10:23 +07:00
Huong Nguyen b50db3fa11 weekly release 4.5.4+ 2025-04-24 22:06:01 +07:00
Huong Nguyen 290d65e03e NOBUG: Add upgrade notes 2025-04-24 22:06:00 +07:00
Huong Nguyen af4a65c408 Merge branch 'install_405_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_405_STABLE 2025-04-24 22:05:46 +07:00
Paul Holden 8b14e5b9d8 MDL-84192 course: update course information page language string.
The previous version used an incorrectly deprecated summary string.
2025-04-24 11:53:38 +01:00
Huong Nguyen 3facc7677f Merge branch 'MDL-84480-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-24 07:34:46 +02:00
Sara Arjona 3d7dd31dda Merge branch 'MDL-84233_MOODLE_405_STABLE' of https://github.com/catalyst/moodle into MOODLE_405_STABLE 2025-04-24 07:34:46 +02:00
Huong Nguyen 9c4646b41e Merge branch 'MDL-83563_405' of https://github.com/larsbonczek/moodle into MOODLE_405_STABLE 2025-04-24 07:34:44 +02:00
Huong Nguyen e5b973ee85 Merge branch 'MDL-84442-metadata-task-logs-MOODLE_405_STABLE' of https://github.com/bwalkerl/moodle into MOODLE_405_STABLE 2025-04-24 07:32:48 +02:00
David Woloszyn ff28aadff1 MDL-84274 tool_policy: Policy acceptance pages use secure layout 2025-04-24 12:27:23 +10:00
David Woloszyn 9fd50c9771 MDL-84274 tool_mfa: Prevent tool_policy pages from redirecting 2025-04-24 12:27:23 +10:00
Jayce fb236380ee MDL-84964 mod_glossary: min width only apply for large device 2025-04-23 10:01:50 +09:30
AMOS bot ef92f5e441 Automatically generated installer lang files 2025-04-23 00:07:54 +00:00
Albert Gasset 35d0df6f9b MDL-85248 qtype_ddimageortext: Revert MDL-66584
This reverts commit 729e4eb792.
2025-04-22 16:50:58 +02:00
Sara Arjona e48855458e Merge branch 'MDL-82658-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-22 16:46:37 +02:00
Huong Nguyen aaf1c1671a Merge branch 'MDL-84070-user-pref-race-bug-v2-MOODLE_405_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_405_STABLE 2025-04-22 08:39:33 +07:00
Benjamin Walker b037708523 MDL-84442 core_task: Add finalise log param to task failers 2025-04-22 09:29:50 +10:00
Brendan Heywood 90a5527e4c MDL-84070 core: Fix race conditions setting user preferences 2025-04-21 21:41:58 +10:00
Huong Nguyen 9924495afc Merge branch 'mdl-83262_405' of https://github.com/james-cnz/moodle into MOODLE_405_STABLE 2025-04-21 09:12:59 +07:00
AMOS bot a3542e68cf Automatically generated installer lang files 2025-04-20 00:08:16 +00:00
AMOS bot 6c35478d6e Automatically generated installer lang files 2025-04-19 00:07:53 +00:00
Stefan Hanauska b9144ae56a MDL-83111 tool_recyclebin: Avoid null value 2025-04-18 07:15:10 +02:00
AMOS bot 0d0bc14482 Automatically generated installer lang files 2025-04-18 00:07:55 +00:00
Sara Arjona 2ddab5548f weekly release 4.5.4+ 2025-04-17 14:30:05 +02:00
Sara Arjona 8f67081b7b NOBUG: Add upgrade notes 2025-04-17 14:30:05 +02:00
Huong Nguyen 940e7adf84 Merge branch 'MDL-84298-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-17 10:53:34 +07:00
Huong Nguyen 21d77474b1 Merge branch 'MDL-84625-M405_close-recordset-in-core_analytics-model-add_prediction_ids' of https://github.com/ziegenberg/moodle into MOODLE_405_STABLE 2025-04-17 10:28:01 +07:00
Huong Nguyen 37de4caecd Merge branch '83713-javascript-error-xml-grades-import-405' of https://github.com/DSI-Universite-Rennes2/moodle into MOODLE_405_STABLE 2025-04-17 10:12:17 +07:00
Huong Nguyen d87b86d997 Merge branch 'MDL-84232-405-avoid_recover_quiz_grades' of https://github.com/drobayo/moodle into MOODLE_405_STABLE 2025-04-17 08:39:32 +07:00
James C b0af55a8b8 MDL-83262 course: Refresh all-sections toggler on section delete 2025-04-17 12:46:09 +12:00
Julien Boulen ad40295e90 MDL-83713 form: Fix javascript selector on file picker
Co-authored-by: Meirza <meirza.arson@moodle.com>
2025-04-16 16:46:38 +02:00
Sara Arjona f36cc666f7 Merge branch 'MDL-84820-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-16 15:24:39 +02:00
Sara Arjona 5c8bb7bf12 Merge branch 'MDL-85170-405' of https://github.com/aanabit/moodle into MOODLE_405_STABLE 2025-04-16 15:12:20 +02:00
Sara Arjona 83d42d8a92 Merge branch 'MDL-82132-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-16 14:55:10 +02:00
Huong Nguyen eb264c78a4 Merge branch 'MDL-83195-releaseanongradev2-405' of https://github.com/leonstr/moodle into MOODLE_405_STABLE 2025-04-16 09:40:04 +07:00
Paul Holden f09a2fc6ec MDL-82132 user: less restrictive returning first/lastname details.
The `viewfullnames` capability check was overeager in restricting
the inclusion of user first and lastname properties in the returned
structure. Especially given that the same data was almost always
present in the fullname property of the same structure.
2025-04-15 16:00:49 +01:00
Paul Holden d6b81786ee MDL-82132 user: re-factor code for generating dummy user fullname. 2025-04-15 16:00:49 +01:00
Sara Arjona e1ef9e9561 Merge branch 'MDL-84149-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 16:45:04 +02:00
Sara Arjona cb989eebd6 Merge branch 'MDL-84140-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 16:31:20 +02:00
Sara Arjona 8e97eb9d34 Merge branch 'MDL-83990-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 16:18:12 +02:00
Sara Arjona a56c8bace8 Merge branch 'MDL-83537-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 16:09:28 +02:00
Jun Pataleta 10f4326ec6 Merge branch 'MDL-83979-url-always-proxy-MOODLE_405_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_405_STABLE 2025-04-15 20:38:36 +08:00
Sara Arjona 99d87938cd Merge branch 'MDL-55034-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 13:36:53 +02:00
Sara Arjona 10c6c279b2 Merge branch 'MDL-78381-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 11:36:56 +02:00
Sara Arjona dc7e34360d Merge branch 'MDL-80337-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-15 11:30:36 +02:00
Sara Arjona c9bd62995d Merge branch 'MDL-62230-405' of https://github.com/paulholden/moodle into MOODLE_405_STABLE 2025-04-14 18:57:06 +02:00
Sara Arjona b352601cd3 Merge branch 'MDL-81454-405' of https://github.com/daniil-berg/moodle into MOODLE_405_STABLE 2025-04-14 18:46:28 +02:00
Sara Arjona 1f4cd6c253 Merge branch 'MDL-83550-405' of https://github.com/andrewgos/moodle into MOODLE_405_STABLE 2025-04-14 17:54:26 +02:00
Sara Arjona 94adaf65fd Merge branch 'MDL-78886-405' of https://github.com/mwehr/moodle into MOODLE_405_STABLE 2025-04-14 17:50:21 +02:00
Sara Arjona a0b1820dcd Merge branch 'MDL-66584-405' of https://github.com/danghieu1407/moodle into MOODLE_405_STABLE 2025-04-14 17:47:40 +02:00
Wehr Mario abbf245371 MDL-78886 assignfeedback_editpdf: Fix broken next page button in PDFView
Credits go to Cédric Gerbault cdgerbault@gmail.com for providing the fix.
2025-04-14 17:39:36 +02:00
Sara Arjona fd0d72cce6 Merge branch 'MDL-84833-405' of https://github.com/ferranrecio/moodle into MOODLE_405_STABLE 2025-04-14 17:11:09 +02:00
Sara Arjona e746c166e2 Merge branch 'MDL-79464-405' of https://github.com/mihailges/moodle into MOODLE_405_STABLE 2025-04-14 17:08:31 +02:00
Daniel Ziegenberg e7825c649e MDL-84625 analytics: close recordset when it's not needed anymore
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2025-04-14 10:02:34 +02:00
James C f517047fc1 MDL-84520 course: CM anchor scrolls to specified CM 2025-04-14 12:16:10 +12:00
Amaia Anabitarte c81c68eb0b MDL-85170 mod_choice: Remove the unnecessary ul closing tag 2025-04-11 17:16:22 +02:00
Alec Gullon 5ba4291ffd MDL-79464 mod_assign: Limit user navigation if grading fails validation 2025-04-10 16:27:51 +08:00
Daniil Fajnberg b6665be054 MDL-81454 core: Remove incorrect @property-read annotation 2025-04-09 09:01:07 +02:00
Brendan Heywood a627b10f0c MDL-83979 repository_url: Always use the proxy for url downloads 2025-04-09 14:44:54 +10:00
Paul Holden ec6067ab03 MDL-82658 mod_forum: calculate maxbytes correctly in reply handler. 2025-04-07 09:38:33 +01:00
Paul Holden 2b60a7fcb9 MDL-84149 gradereport_grader: better support for collapse preferences.
The privacy provider is now resilient against missing courses, and also
supports retrieving preferences from multiple courses for the user.
2025-04-07 09:37:38 +01:00
Paul Holden 91c04146cb MDL-55034 blog: update external blog deletion to not leak sesskey. 2025-03-31 14:04:13 +01:00
ferran e82b8ab95e MDL-84833 course: completion feedback messages 2025-03-31 09:39:21 +02:00
Paul Holden 9f60cb0ae5 MDL-84140 course: more resilient check for activity footer component. 2025-03-27 08:32:57 +00:00
Dagoberto Robayo d2acaccee8 MDL-84232 mod_quiz: Avoid recover grades in quiz view page
- If Recover grades default is not enabled, quiz grades should not be recover.
2025-03-25 09:14:30 -05:00
danghieu1407 729e4eb792 MDL-66584 qtype_ddimageortext: Move JSON data to data-attribute 2025-03-25 16:44:50 +07:00
Paul Holden ecf19e63a0 MDL-84983 core: account for invalid locales in intl extension.
Recent PHP versions are now stricter on the `$locale` value passed
to `IntlDateFormatter` class and will throw exceptions for invalid
values (some of which may be present in our language packs).

See: https://github.com/php/php-src/issues/12912
2025-03-24 15:29:48 +00:00
Paul Holden e4c81e3f5f MDL-84941 course: fix activity button label on end of section.
Where the button is rendered after all section content, we should
fix the ARIA label attribute to refer to the current section rather
than non-existing subsequent activity.
2025-03-19 19:41:51 +00:00
Paul Holden a955ef2bca MDL-84820 moodlenet: correct activity modal icon size/alignment. 2025-03-19 10:25:55 +00:00
Andrew Gosali 4fe75e75cb MDL-84539 report_participation: use capability viewanonymousevents 2025-03-18 11:32:12 +07:00
Andrew Gosali 3d7656d713 MDL-83550 gradingform_rubric: fix submit no grade when remark disabled 2025-03-17 14:50:27 +07:00
Paul Holden a82df2e07a MDL-80337 availability: more robust checking for plugin class presence.
Co-authored-by: Dustin Brisebois <dustin.brisebois@lambdasolutions.net>
2025-03-16 19:27:29 +00:00
Paul Holden d767936052 MDL-83990 course: ensure course start/end dates set in external call. 2025-03-13 17:53:46 +00:00
Paul Holden c4fc0978b1 MDL-83537 check: confirm presence of instance action link. 2025-03-13 17:52:42 +00:00
danghieu1407 66ebd7a55a MDL-84708 question: Fixing layout answer box issue causing images 2025-03-13 10:28:55 +07:00
Paul Holden 8c178a1acb MDL-78381 course: observe default "showactivitydates" in external call. 2025-03-11 17:33:26 +00:00
Paul Holden 1c4b98c2d2 MDL-84787 calendar: restore course-specific management page parameter. 2025-03-11 13:32:52 +00:00
Lars Bonczek dd633f1691 MDL-83563 form: Fix hideIf and disabledIf dependent on multiselects 2025-03-11 12:14:11 +01:00
Paul Holden b64ef9cb84 MDL-84480 files: correct text formatting params when filtering files. 2025-03-11 10:30:05 +00:00
Nathan Nguyen d1bb4b21e7 MDL-84233 core_user: fix unit test 2025-03-07 16:49:00 +11:00
Paul Holden f417f99261 MDL-62230 mod_feedback: define exporter format for name/presentation. 2025-03-04 14:13:02 +00:00
Paul Holden 254e94d4d3 MDL-84298 mod_assign: target only first label for grade popout button. 2025-02-24 22:22:09 +00:00
Paul Holden 8c35c29b06 MDL-84597 blog: confirm blogs enabled prior to settings nav access. 2025-02-24 12:53:33 +00:00
Leon Stringer 9d45e32f78 MDL-83195 mod_assign: Individual grade release
Fix pushing individual grades into the gradebook (as opposed to the
batch release of grades) when "Allow partial release of grades while
marking anonymously" is enabled.

This change reworks MDL-73626's fix for the same issue for releasing
multiple grades in a batch operation.
2025-02-14 12:15:52 +00:00
Andrew Nicols 8b3d6c3259 MDL-84421 tool_uploadcourse: Stop MUC caching enrol instances
We should not normally cache instances of a class. This can lead to poor
design to work around the limitations of PHP Serialization, and could
theoretically cause issues with PHP versions changing within a Moodle
version.
2025-02-04 22:14:09 +08:00
1223 changed files with 12215 additions and 4406 deletions
+3 -3
View File
@@ -19,7 +19,7 @@ env:
jobs:
Grunt:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checking out code
@@ -61,12 +61,12 @@ jobs:
matrix:
include:
# MySQL builds always run with the lowest PHP supported version.
- os: ubuntu-22.04
- os: ubuntu-24.04
php: 8.1
extensions:
db: mysqli
# PostgreSQL builds always run with the highest PHP supported version.
- os: ubuntu-22.04
- os: ubuntu-24.04
php: 8.3
db: pgsql
+66
View File
@@ -6,6 +6,72 @@ 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.6
### core
#### Added
- Add a new method has_valid_group in \core\report_helper that will return true or false depending if the user has a valid group. This is mainly false in case the user is not in any group in SEPARATEGROUPS. Used in report_log and report_loglive
For more information see [MDL-84464](https://tracker.moodle.org/browse/MDL-84464)
#### Changed
- The `\core\attribute\deprecated` attribute constructor `$replacement` parameter now defaults to null, and can be omitted
For more information see [MDL-84531](https://tracker.moodle.org/browse/MDL-84531)
- Added a new `\core\deprecation::emit_deprecation()` method which should be used in places where a deprecation is known to occur. This method will throw debugging if no deprecation notice was found, for example:
```php
public function deprecated_method(): void {
\core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
}
```
For more information see [MDL-85897](https://tracker.moodle.org/browse/MDL-85897)
### core_message
#### Added
- The web service `core_message_get_member_info` additionally returns `cancreatecontact` which is a boolean value for a user's permission to add a contact.
For more information see [MDL-72123](https://tracker.moodle.org/browse/MDL-72123)
## 4.5.5
### core
#### Added
- - Added is_site_registered_in_hub method in lib/classes/hub/api.php to
check if the site is registered or not.
- Added get_secret method in lib/classes/hub/registration.php to get site's secret.
For more information see [MDL-83448](https://tracker.moodle.org/browse/MDL-83448)
- Added a new optional param to adhoc_task_failed and scheduled_task_failed to allow skipping log finalisation when called from a separate task.
For more information see [MDL-84442](https://tracker.moodle.org/browse/MDL-84442)
- There is a new `core/page_title` Javascript module for manipulating the current page title
For more information see [MDL-84804](https://tracker.moodle.org/browse/MDL-84804)
### core_auth
#### Added
- A new method called `get_additional_upgrade_token_parameters` has been added to `oauth2_client` class. This will allow custom clients to override this one and add their extra parameters for upgrade token request.
For more information see [MDL-80380](https://tracker.moodle.org/browse/MDL-80380)
### core_user
#### Added
- New method `\core_user::get_dummy_fullname(...)` for returning dummy user fullname comprised of configured name fields only
For more information see [MDL-82132](https://tracker.moodle.org/browse/MDL-82132)
## 4.5.4
### core
+4
View File
@@ -118,6 +118,10 @@ foreach ($settingspage->children as $childpage) {
}
$outputhtml .= html_writer::tag('div', '<!-- -->', array('class' => 'clearer'));
$outputhtml .= $setting->output_html($data);
if ($childpage->has_dependencies()) {
$opts = ['dependencies' => $childpage->get_dependencies_for_javascript()];
$PAGE->requires->js_call_amd('core/showhidesettings', 'init', [$opts]);
}
}
$outputhtml .= html_writer::end_tag('fieldset');
}
+1
View File
@@ -24,6 +24,7 @@
*/
define('CLI_SCRIPT', true);
define('IGNORE_COMPONENT_CACHE', true);
require(__DIR__.'/../../config.php');
require_once($CFG->libdir.'/clilib.php');
+203
View File
@@ -4716,6 +4716,7 @@
<VENDOR name="mysql" version="8.4" />
<VENDOR name="postgres" version="14" />
<VENDOR name="mssql" version="14.0" />
<VENDOR name="auroramysql" version="8.0" />
</DATABASE>
<PHP version="8.2.0" level="required">
</PHP>
@@ -4895,6 +4896,208 @@
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_aurora_version" level="optional">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="5.1" 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="15" />
<VENDOR name="mssql" version="14.0" />
<VENDOR name="auroramysql" version="8.0" />
</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_SETTING name="zend.exception_ignore_args" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingzendexceptionignoreargs" />
</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_async_backup" level="recommended">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_aurora_version" level="optional">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+2
View File
@@ -23,6 +23,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('IGNORE_COMPONENT_CACHE', true);
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
+7 -5
View File
@@ -34,8 +34,10 @@ admin_externalpage_setup('registrationmoodleorg');
$unregistration = optional_param('unregistration', false, PARAM_BOOL);
$confirm = optional_param('confirm', false, PARAM_BOOL);
// Consider the site 'registered' if records exist locally and at the hub.
$siteisregistered = \core\hub\registration::is_registered() && core\hub\api::is_site_registered_in_hub();
if ($unregistration && \core\hub\registration::is_registered()) {
if ($unregistration && $siteisregistered) {
if ($confirm) {
require_sesskey();
\core\hub\registration::unregister(false, false);
@@ -60,7 +62,7 @@ if (!$returnurl = optional_param('returnurl', null, PARAM_LOCALURL)) {
$returnurl = $isinitialregistration ? '/admin/index.php' : '/admin/registration/index.php';
}
$siteregistrationform = new \core\hub\site_registration_form();
$siteregistrationform = new \core\hub\site_registration_form(null, ['registered' => $siteisregistered]);
$siteregistrationform->set_data(['returnurl' => $returnurl]);
if ($fromform = $siteregistrationform->get_data()) {
@@ -86,7 +88,7 @@ echo $OUTPUT->header();
// Current status of registration.
$notificationtype = \core\output\notification::NOTIFY_ERROR;
if (\core\hub\registration::is_registered()) {
if ($siteisregistered) {
$lastupdated = \core\hub\registration::get_last_updated();
if ($lastupdated == 0) {
$registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
@@ -104,7 +106,7 @@ if (\core\hub\registration::is_registered()) {
}
// Heading.
if (\core\hub\registration::is_registered()) {
if ($siteisregistered) {
echo $OUTPUT->heading(get_string('registerwithmoodleorgupdate', 'core_hub'));
} else if ($isinitialregistration) {
echo $OUTPUT->heading(get_string('registerwithmoodleorgcomplete', 'core_hub'));
@@ -117,7 +119,7 @@ echo $renderer->moodleorg_registration_message();
$siteregistrationform->display();
if (\core\hub\registration::is_registered()) {
if ($siteisregistered) {
// Unregister link.
$unregisterhuburl = new moodle_url("/admin/registration/index.php", ['unregistration' => 1]);
echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister mt-2');
+4
View File
@@ -36,6 +36,10 @@ if (function_exists('opcache_reset')) {
define('CLI_SCRIPT', true);
define('CACHE_DISABLE_ALL', true);
// It makes no sense to use BEHAT_CLI for this script (the Behat launch scripts expect to start
// from the normal environment), so in case user has set tne environment variable, disable it.
putenv('BEHAT_CLI=0');
// Basic functions.
require_once(__DIR__ . '/../../../../lib/clilib.php');
require_once(__DIR__ . '/../../../../lib/behat/lib.php');
+4
View File
@@ -31,6 +31,10 @@ define('ABORT_AFTER_CONFIG', true);
define('CACHE_DISABLE_ALL', true);
define('NO_OUTPUT_BUFFERING', true);
// It makes no sense to use BEHAT_CLI for this script (the Behat launch scripts expect to start
// from the normal environment), so in case user has set tne environment variable, disable it.
putenv('BEHAT_CLI=0');
require_once(__DIR__ .'/../../../../config.php');
require_once(__DIR__.'/../../../../lib/clilib.php');
require_once(__DIR__.'/../../../../lib/behat/lib.php');
+4
View File
@@ -39,6 +39,10 @@ define('NO_OUTPUT_BUFFERING', true);
define('IGNORE_COMPONENT_CACHE', true);
define('ABORT_AFTER_CONFIG', true);
// It makes no sense to use BEHAT_CLI for this script (the Behat launch scripts expect to start
// from the normal environment), so in case user has set tne environment variable, disable it.
putenv('BEHAT_CLI=0');
require_once(__DIR__ . '/../../../../lib/clilib.php');
// CLI options.
+4
View File
@@ -33,6 +33,10 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
die(); // No access from web!.
}
// It makes no sense to use BEHAT_CLI for this script (the Behat launch scripts expect to start
// from the normal environment), so in case user has set tne environment variable, disable it.
putenv('BEHAT_CLI=0');
// Basic functions.
require_once(__DIR__ . '/../../../../lib/clilib.php');
require_once(__DIR__ . '/../../../../lib/behat/lib.php');
+11 -2
View File
@@ -24,5 +24,14 @@
defined('MOODLE_INTERNAL') || die;
// Remove the 'enableaccessibilitytools' configuration setting in case of reinstall.
unset_config('enableaccessibilitytools');
/**
* Plugin uninstall code.
*
* @return true
*/
function xmldb_tool_brickfield_uninstall(): bool {
// Remove the 'enableaccessibilitytools' configuration setting in case of reinstall.
unset_config('enableaccessibilitytools');
return true;
}
@@ -0,0 +1,70 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
namespace tool_capability;
// phpcs:disable moodle.PHPUnit.TestCaseProvider.dataProviderSyntaxMethodNotFound
/**
* Detect common problems in capability definitions of plugins.
*
* @group plugin_checks
* @package tool_capability
* @copyright 2025 Petr Skoda
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class plugin_checks_test extends \core\tests\plugin_checks_testcase {
/**
* Verify contents of plugin db/access.php file.
*
* @dataProvider all_plugins_provider
* @coversNothing
*
* @param string $component
* @param string $plugintype
* @param string $pluginname
* @param string $dir
*/
public function test_db_access_file(string $component, string $plugintype, string $pluginname, string $dir): void {
global $CFG;
$stringmanager = get_string_manager();
$corerolefile = "$CFG->dirroot/lang/en/role.php";
$langfile = "$dir/lang/en/$component.php";
$file = "$dir/db/access.php";
$capabilities = $this->fetch_array_from_file($file, 'capabilities');
if (!$capabilities) {
$this->expectNotToPerformAssertions();
return;
}
foreach ($capabilities as $capname => $capability) {
if ($plugintype === 'qbank' && str_starts_with($capname, 'moodle/question:')) {
// Question bank capabilities are irregular.
$strname = explode('/', $capname, 2)[1];
$this->assertTrue($stringmanager->string_exists($strname, 'core_role'),
"Missing capability name string '$strname' in $corerolefile");
continue;
}
$this->assertMatchesRegularExpression("|^$plugintype/$pluginname:[a-z0-9_]+$|", $capname);
$strname = substr($capname, strlen($plugintype) + 1);
$this->assertTrue($stringmanager->string_exists($strname, $component),
"Missing capability name string '$strname' in $langfile");
$this->assertSame($capname, clean_param($capname, PARAM_CAPABILITY));
}
}
}
@@ -46,11 +46,11 @@ Feature: See the competencies for an activity on the course competencies page.
When I follow "Competencies"
Then I should see "Test-Comp1"
And I should see "Test-Comp2"
And I set the field "Filter competencies by resource or activity" to "PageName1"
And I set the competency filter "Filter competencies by resource or activity" to "PageName1"
And I press the enter key
And I should see "Test-Comp1"
And I should not see "Test-Comp2"
And I set the field "Filter competencies by resource or activity" to "PageName2"
And I set the competency filter "Filter competencies by resource or activity" to "PageName2"
And I press the enter key
And I should not see "Test-Comp1"
And I should not see "Test-Comp2"
+11
View File
@@ -169,6 +169,17 @@ switch ($action) {
echo $OUTPUT->heading(get_string('managefactor', 'factor_' . $factorobject->name));
echo $OUTPUT->active_factors($factor);
echo $OUTPUT->single_button($returnurl, get_string('back'));
// Displays a setup additional button in case it is needed.
if ($factorobject->show_additional_setup_button()) {
echo $OUTPUT->single_button(
url: new \moodle_url('action.php', ['action' => 'setup', 'factor' => $factor]),
label: $factorobject->get_additional_setup_string(),
method: 'post',
options: ['type' => 'primary'],
);
}
// JS for modal confirming replace and revoke actions.
$PAGE->requires->js_call_amd('tool_mfa/confirmation_modal', 'init', [$context->id]);
@@ -421,6 +421,18 @@ abstract class object_factor_base implements object_factor {
return $this->has_setup();
}
/**
* Returns true if a button should be shown to add factors of the same kind on the preferences page.
* For example, give user's the ability to set up multiple security keys.
*
* Override in child class if necessary.
*
* @return bool
*/
public function show_additional_setup_button(): bool {
return false;
}
/**
* Returns true if a factor requires input from the user to verify.
*
@@ -578,6 +590,18 @@ abstract class object_factor_base implements object_factor {
return get_string('setupfactor', 'tool_mfa');
}
/**
* Gets the string for additional setup button on preferences page.
* If the user has the ability to set up multiple security keys.
*
* Override in child class if necessary.
*
* @return string
*/
public function get_additional_setup_string(): string {
return get_string('setupfactorbuttonadditional', 'tool_mfa');
}
/**
* Gets the string for manage button on preferences page.
*
+7
View File
@@ -530,6 +530,13 @@ class manager {
}
}
// Site policies from tool_policy.
$policyviewurl = new \moodle_url('/admin/tool/policy/view.php');
$policyindexurl = new \moodle_url('/admin/tool/policy/index.php');
if ($policyviewurl->compare($url, URL_MATCH_BASE) || $policyindexurl->compare($url, URL_MATCH_BASE)) {
return self::NO_REDIRECT;
}
// WS/AJAX check.
if (WS_SERVER || AJAX_SCRIPT) {
if (isset($SESSION->mfa_pending) && !empty($SESSION->mfa_pending)) {
+10 -10
View File
@@ -379,7 +379,7 @@ class renderer extends \plugin_renderer_base {
WHERE deleted = 0
AND suspended = 0
GROUP BY auth";
$allusersinfo = $DB->get_records_sql($alluserssql, []);
$allusersinfo = $DB->get_records_sql_menu($alluserssql);
$noncompletesql = "SELECT u.auth, COUNT(u.id)
FROM {user} u
@@ -388,7 +388,7 @@ class renderer extends \plugin_renderer_base {
AND (mfaa.lastverified < ?
OR mfaa.lastverified IS NULL)
GROUP BY u.auth";
$noncompleteinfo = $DB->get_records_sql($noncompletesql, [$lookback, $lookback]);
$noncompleteinfo = $DB->get_records_sql_menu($noncompletesql, [$lookback, $lookback]);
$nologinsql = "SELECT auth, COUNT(id)
FROM {user}
@@ -396,7 +396,7 @@ class renderer extends \plugin_renderer_base {
AND suspended = 0
AND lastlogin < ?
GROUP BY auth";
$nologininfo = $DB->get_records_sql($nologinsql, [$lookback]);
$nologininfo = $DB->get_records_sql_menu($nologinsql, [$lookback]);
$mfauserssql = "SELECT auth,
COUNT(DISTINCT tm.userid)
@@ -406,7 +406,7 @@ class renderer extends \plugin_renderer_base {
AND u.deleted = 0
AND u.suspended = 0
GROUP BY u.auth";
$mfausersinfo = $DB->get_records_sql($mfauserssql, [$lookback]);
$mfausersinfo = $DB->get_records_sql_menu($mfauserssql, [$lookback]);
$factorsusedsql = "SELECT CONCAT(u.auth, '_', tm.factor) as id,
COUNT(*)
@@ -417,7 +417,7 @@ class renderer extends \plugin_renderer_base {
AND u.suspended = 0
AND (tm.revoked = 0 OR (tm.revoked = 1 AND tm.timemodified > ?))
GROUP BY CONCAT(u.auth, '_', tm.factor)";
$factorsusedinfo = $DB->get_records_sql($factorsusedsql, [$lookback, $lookback]);
$factorsusedinfo = $DB->get_records_sql_menu($factorsusedsql, [$lookback, $lookback]);
// Auth rows.
$authtypes = get_enabled_auth_plugins(true);
@@ -426,10 +426,10 @@ class renderer extends \plugin_renderer_base {
$row[] = \html_writer::tag('b', $authtype);
// Setup the overall totals columns.
$row[] = $allusersinfo[$authtype]->count ?? '-';
$row[] = $mfausersinfo[$authtype]->count ?? '-';
$row[] = $noncompleteinfo[$authtype]->count ?? '-';
$row[] = $nologininfo[$authtype]->count ?? '-';
$row[] = $allusersinfo[$authtype] ?? '-';
$row[] = $mfausersinfo[$authtype] ?? '-';
$row[] = $noncompleteinfo[$authtype] ?? '-';
$row[] = $nologininfo[$authtype] ?? '-';
// Create a running counter for the total.
$authtotal = 0;
@@ -439,7 +439,7 @@ class renderer extends \plugin_renderer_base {
if (!empty($column)) {
// Get the information from the data key.
$key = $authtype . '_' . $column;
$count = $factorsusedinfo[$key]->count ?? 0;
$count = $factorsusedinfo[$key] ?? 0;
$authtotal += $count;
$row[] = $count ? format_float($count, 0) : '-';
@@ -71,7 +71,7 @@ $string['setupfactor:instructionsverification'] = '3. Enter the verification cod
$string['setupfactor:intro'] = 'To set up this method, you need to have a device with an authenticator app. If you don\'t have an app, you can download one. For example, <a href="https://2fas.com/" target="_blank">2FAS Auth</a>, <a href="https://freeotp.github.io/" target="_blank">FreeOTP</a>, Google Authenticator, Microsoft Authenticator or Twilio Authy.';
$string['setupfactor:key'] = 'Secret key: ';
$string['setupfactor:link'] = 'Or enter details manually.';
$string['setupfactor:link_help'] = 'If you are on a mobile device and already have an authenticator app installed this link may work. Note that using TOTP on the same device as you login on can weaken the benefits of MFA.';
$string['setupfactor:link_help'] = 'If you are on a mobile device and already have an authenticator app installed this link may work. Note that using TOTP on the same device as you log in on can weaken the benefits of MFA.';
$string['setupfactor:linklabel'] = 'Open app already installed on this device';
$string['setupfactor:mode'] = 'Mode:';
$string['setupfactor:mode:timebased'] = 'Time-based';
@@ -115,6 +115,15 @@ class factor extends object_factor_base {
return true;
}
/**
* Returns true if an additional setup button should be shown on the preferences page.
*
* @return bool
*/
public function show_additional_setup_button(): bool {
return true;
}
/**
* WebAuthn factor implementation.
*
@@ -155,6 +164,15 @@ class factor extends object_factor_base {
return get_string('setupfactorbutton', 'factor_webauthn');
}
/**
* Gets the string for additional setup button on preferences page.
*
* @return string
*/
public function get_additional_setup_string(): string {
return get_string('setupfactorbuttonadditional', 'factor_webauthn');
}
/**
* Gets the string for manage button on preferences page.
*
@@ -51,6 +51,7 @@ $string['settings:userverification'] = 'User verification';
$string['settings:userverification_help'] = 'Serves to ensure the person authenticating is in fact who they say they are. User verification can take various forms, such as password, PIN, fingerprint, etc.';
$string['setupfactor'] = 'Set up security key';
$string['setupfactorbutton'] = 'Set up';
$string['setupfactorbuttonadditional'] = 'Add security key';
$string['setupfactor:instructionsregistersecuritykey'] = '2. Register a security key.';
$string['setupfactor:instructionssecuritykeyname'] = '1. Give your key a name.';
$string['setupfactor:intro'] = 'A security key is a physical device that you can use to authenticate yourself. Security keys can be USB tokens, Bluetooth devices, or event built-in fingerprint scanners on your phone or computer.';
+1
View File
@@ -151,6 +151,7 @@ $string['settings:redir_exclusions_help'] = 'Each new line is a relative URL fro
$string['settings:weight'] = 'Factor weight';
$string['settings:weight_help'] = 'The weight of this factor if passed. A user needs at least 100 points to log in.';
$string['setupfactor'] = 'Set up factor';
$string['setupfactorbuttonadditional'] = 'Add additional factor';
$string['setuprequired'] = 'User setup';
$string['state:fail'] = 'Fail';
$string['state:locked'] = 'Locked';
@@ -32,6 +32,7 @@ Feature: Set up and manage user factors
And I click on "Cancel" "button"
And I click on "Manage security key" "button"
And I should see "Manage security key"
And I should see "Add security key"
@javascript
Scenario: I can revoke a factor only when there is more than one active factor
@@ -76,3 +77,15 @@ Feature: Set up and manage user factors
And I click on "Replace" "button" in the "MacBook" "table_row"
When I click on "Yes, replace" "button" in the "Replace 'MacBook' security key?" "dialogue"
Then I should see "Replace security key"
Scenario: I can add a new factor instance on the manage factor page
Given the following config values are set as admin:
| enabled | 1 | factor_webauthn |
And the following "tool_mfa > User factors" exist:
| username | factor | label |
| admin | webauthn | MacBook |
And I follow "Preferences" in the user menu
And I click on "Multi-factor authentication preferences" "link"
And I click on "Manage security key" "button"
When I click on "Add security key" "button"
Then I should see "Set up security key"
@@ -129,6 +129,7 @@ class issuer extends persistent {
\core\oauth2\issuer::EVERYWHERE => get_string('issueruseineverywhere', 'tool_oauth2'),
\core\oauth2\issuer::LOGINONLY => get_string('issueruseinloginonly', 'tool_oauth2'),
\core\oauth2\issuer::SERVICEONLY => get_string('issueruseininternalonly', 'tool_oauth2'),
\core\oauth2\issuer::SMTPWITHXOAUTH2 => get_string('issueruseinsmtpwithoauth', 'tool_oauth2'),
];
$mform->addElement('select', 'showonloginpage', get_string('issuerusein', 'tool_oauth2'), $options);
$mform->addHelpButton('showonloginpage', 'issuerusein', 'tool_oauth2');
@@ -138,6 +139,13 @@ class issuer extends persistent {
$mform->addRule('loginpagename', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
$mform->addHelpButton('loginpagename', 'issuerloginpagename', 'tool_oauth2');
$mform->hideIf('loginpagename', 'showonloginpage', 'eq', \core\oauth2\issuer::SERVICEONLY);
$mform->hideIf('loginpagename', 'showonloginpage', 'eq', \core\oauth2\issuer::SMTPWITHXOAUTH2);
// Connected email for XOAUTH2.
$mform->addElement('text', 'systememail', get_string('issuersmtpsystememail', 'tool_oauth2'));
$mform->setType('systememail', PARAM_EMAIL);
$mform->addHelpButton('systememail', 'issuersmtpsystememail', 'tool_oauth2');
$mform->hideIf('systememail', 'showonloginpage', 'ne', \core\oauth2\issuer::SMTPWITHXOAUTH2);
// Login scopes.
$mform->addElement('text', 'loginscopes', get_string('issuerloginscopes', 'tool_oauth2'));
@@ -86,7 +86,8 @@ class renderer extends plugin_renderer_base {
$namecell->header = true;
// Login issuer.
if ((int)$issuer->get('showonloginpage') == issuer::SERVICEONLY) {
if ((int)$issuer->get('showonloginpage') == issuer::SERVICEONLY ||
(int)$issuer->get('showonloginpage') == issuer::SMTPWITHXOAUTH2) {
$loginissuer = $this->pix_icon('no', get_string('notloginissuer', 'tool_oauth2'), 'tool_oauth2');
$logindisplayas = '';
} else {
+4 -1
View File
@@ -89,13 +89,16 @@ $string['issuershowonloginpage'] = 'Show on login page';
$string['issuerrequireconfirmation_help'] = 'Require that all users verify their email address before they can log in with OAuth. This applies to newly created accounts as part of the login process, or when an existing Moodle account is connected to an OAuth login via matching email addresses.';
$string['issuerrequireconfirmation'] = 'Require email verification';
$string['issuers'] = 'Issuers';
$string['issuersmtpsystememail'] = 'SMTP email';
$string['issuersmtpsystememail_help'] = 'If specified, this email will be used to connect a system account for sending email via SMTP. This is required for some OAuth 2 services (e.g. Microsoft). Please check the documentation for your OAuth 2 service to see if this is required.';
$string['issuersservicesallow'] = 'Allow services';
$string['issuersservicesnotallow'] = 'Do not allow services';
$string['issuerusein'] = 'This service will be used';
$string['issuerusein_help'] = 'OAuth 2 services can be used for internal services, on the login page, or both, if required.';
$string['issuerusein_help'] = 'OAuth 2 services can be used for internal services, on the login page, SMTP with XOAUTH2, or both login page and internal services, if required.';
$string['issueruseineverywhere'] = 'Login page and internal services';
$string['issueruseininternalonly'] = 'Internal services only';
$string['issueruseinloginonly'] = 'Login page only';
$string['issueruseinsmtpwithoauth'] = 'SMTP with XOAUTH2 only';
$string['issuerusedforlogin'] = 'Login';
$string['issuerusedforinternal'] = 'Internal services';
$string['linkedin_service'] = 'LinkedIn';
@@ -54,13 +54,17 @@ Feature: Basic OAuth2 functionality
And I should see "Testing service"
And "Allow login" "icon" should exist in the "Testing service" "table_row"
And "Allow services" "icon" should exist in the "Testing service" "table_row"
And I should see "-" in the "Testing service" "table_row"
And "Service discovery successful" "icon" should exist in the "Testing service" "table_row"
And I click on "Configure endpoints" "link" in the "Testing service" "table_row"
And I should see "authorization_endpoint"
And I should not see "discovery_endpoint"
And I should see "discovery_endpoint"
And I should see "device_authorization_endpoint"
And I navigate to "Server > OAuth 2 services" in site administration
And I click on "Configure user field mappings" "link" in the "Testing service" "table_row"
And I should see "firstname" in the "givenName" "table_row"
And I should see "firstname" in the "givenname" "table_row"
And I should see "idnumber" in the "sub" "table_row"
And I should see "email" in the "email" "table_row"
And I should see "lang" in the "locale" "table_row"
And I navigate to "Server > OAuth 2 services" in site administration
And I click on "Edit" "link" in the "Testing service" "table_row"
And I set the following fields to these values:
+4
View File
@@ -34,6 +34,10 @@ if (function_exists('opcache_reset')) {
define('IGNORE_COMPONENT_CACHE', true);
// It makes no sense to use BEHAT_CLI for this script (you cannot initialise PHPunit starting from
// the Behat environment), so in case user has set tne environment variable, disable it.
putenv('BEHAT_CLI=0');
require_once(__DIR__.'/../../../../lib/clilib.php');
require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php');
require_once(__DIR__.'/../../../../lib/testing/lib.php');
+4
View File
@@ -30,6 +30,10 @@ if (isset($_SERVER['REMOTE_ADDR'])) {
define('IGNORE_COMPONENT_CACHE', true);
// It makes no sense to use BEHAT_CLI for this script (you cannot initialise PHPunit starting from
// the Behat environment), so in case user has set tne environment variable, disable it.
putenv('BEHAT_CLI=0');
require_once(__DIR__.'/../../../../lib/clilib.php');
require_once(__DIR__.'/../../../../lib/phpunit/bootstraplib.php');
require_once(__DIR__.'/../../../../lib/testing/lib.php');
+2
View File
@@ -590,6 +590,7 @@ class api {
'subdirs' => false,
'maxfiles' => -1,
'context' => context_system::instance(),
'noclean' => true,
];
}
@@ -606,6 +607,7 @@ class api {
'subdirs' => false,
'maxfiles' => -1,
'context' => context_system::instance(),
'noclean' => true,
];
}
+1 -1
View File
@@ -58,7 +58,7 @@ $agreedocs = array_values(array_unique($agreedocs));
$declinedocs = array_values(array_unique($declinedocs));
$PAGE->set_context(context_system::instance());
$PAGE->set_pagelayout('standard');
$PAGE->set_pagelayout('secure');
$PAGE->set_url('/admin/tool/policy/index.php');
$PAGE->set_popup_notification_allowed(false);
@@ -304,3 +304,14 @@ Feature: Viewing acceptances reports and accepting on behalf of other users
And I log out
When I log in as "user1"
Then I should see "Calendar"
Scenario: Policy acceptance is prioritised when MFA is enabled
Given the following config values are set as admin:
| enabled | 1 | tool_mfa |
And the following config values are set as admin:
| enabled | 1 | factor_email |
And I log in as "user1"
And I press "Next"
And I set the field "I agree to the This site policy" to "1"
When I press "Next"
Then I should see "2-step verification"
@@ -290,9 +290,6 @@ Feature: User must accept policy managed by this plugin when logging in and sign
And I set the field "I agree to the This privacy policy." to "0"
Then I should see "Please agree to the following policies:"
And I should see "Before continuing you need to acknowledge all these policies."
# Confirm that user can not browse the site (edit their profile).
When I follow "Profile" in the user menu
Then I should see "Please agree to the following policies:"
Scenario: Accept policy on login, accept all policies
Given the following config values are set as admin:
+1 -1
View File
@@ -47,7 +47,7 @@ $numpolicy = optional_param('numpolicy', null, PARAM_INT);
$totalpolicies = optional_param('totalpolicies', null, PARAM_INT);
$PAGE->set_context(context_system::instance());
$PAGE->set_pagelayout('standard');
$PAGE->set_pagelayout('secure');
$viewpage = new page_viewdoc($policyid, $versionid, $returnurl, $behalfid, $manage, $numpolicy, $totalpolicies);
+1 -1
View File
@@ -254,7 +254,7 @@ class course_bin extends base_bin {
// This hack will be removed once recycle bin switches to use its own backup mode, with
// own preferences and 100% separate from MOODLE_AUTOMATED.
// TODO: Remove this as part of MDL-65228.
$forcedrestoresettings = $CFG->forced_plugin_settings['restore'] ?? null;
$forcedrestoresettings = $CFG->forced_plugin_settings['restore'] ?? [];
$CFG->forced_plugin_settings['restore']['restore_general_users'] = 1;
$CFG->forced_plugin_settings['restore']['restore_general_groups'] = 1;
+1 -1
View File
@@ -274,7 +274,7 @@ class tool_task_renderer extends plugin_renderer_base {
$nextruntime = $task->get_next_run_time();
$due = $nextruntime < $now;
if ($task->get_attempts_available() > 0) {
$nextrun = $due ? userdate($nextruntime) : get_string('asap', 'tool_task');
$nextrun = $due ? get_string('asap', 'tool_task') : userdate($nextruntime);
} else {
$nextrun = get_string('never', 'admin');
}
@@ -0,0 +1,23 @@
@tool @tool_task @javascript
Feature: Manage adhoc task
In order to manage adhoc tasks
As an admin
I need to be able to view adhoc tasks
Scenario Outline: View adhoc tasks next run time
Given the following "tool_task > adhoc tasks" exist:
| classname | seconds | hostname | pid | nextruntime |
| \core\task\asynchronous_backup_task | 0 | c69335460f7f | 1915 | <nextruntime> |
When I log in as "admin"
And I navigate to "Server > Tasks > Ad hoc tasks" in site administration
Then the following should exist in the "Ad hoc tasks" table:
| Component / Class name | Next run |
| asynchronous_backup_task | <nextruntimestr> |
And I click on "asynchronous_backup_task" "link" in the "Ad hoc tasks" "table"
And the following should exist in the "\core\task\asynchronous_backup_task Ad hoc tasks" table:
| Next run |
| <nextruntimestr> |
Examples:
| nextruntime | nextruntimestr |
| ##yesterday## | ASAP |
| ##tomorrow noon## | ##tomorrow noon##%A, %d %B %Y, %I:%M## |
+3 -3
View File
@@ -43,7 +43,7 @@ class tool_task_generator extends testing_module_generator {
global $DB;
$conditions = ['classname' => $data['classname']];
$record = $DB->get_record('task_scheduled', $conditions, '*', MUST_EXIST);
$record->timestarted = time() - $data['seconds'];
$record->timestarted = $data['seconds'] > 0 ? time() - $data['seconds'] : 0;
$record->hostname = $data['hostname'];
$record->pid = $data['pid'];
$DB->update_record('task_scheduled', $record);
@@ -59,8 +59,8 @@ class tool_task_generator extends testing_module_generator {
global $DB;
$adhoctask = (object)[
'classname' => $data['classname'],
'nextruntime' => 0,
'timestarted' => time() - $data['seconds'],
'nextruntime' => $data['nextruntime'] ?? 0,
'timestarted' => $data['seconds'] > 0 ? time() - $data['seconds'] : 0,
'hostname' => $data['hostname'],
'pid' => $data['pid'],
];
+1 -1
View File
@@ -1146,7 +1146,7 @@ class tool_uploadcourse_course {
// Now update values.
// Sort out plugin specific fields.
$modifiedinstance = $plugin->update_enrol_plugin_data($course->id, $method, $instance);
$modifiedinstance = $plugin->update_enrol_plugin_data($course->id, $method, clone $instance);
$plugin->update_instance($instance, $modifiedinstance);
} else {
foreach ($errors as $key => $message) {
+1 -6
View File
@@ -177,12 +177,7 @@ class tool_uploadcourse_helper {
* @return enrol_plugin[]
*/
public static function get_enrolment_plugins() {
$cache = cache::make('tool_uploadcourse', 'helper');
if (($enrol = $cache->get('enrol')) === false) {
$enrol = enrol_get_plugins(false);
$cache->set('enrol', $enrol);
}
return $enrol;
return enrol_get_plugins(false);
}
/**
@@ -126,3 +126,19 @@ Feature: An admin can create courses with cohort enrolments using a CSV file
And I press "Cancel"
And I click on "Edit" "link" in the "Cohort 4" "table_row"
And the field "Assign role" matches value "Non-editing teacher"
@javascript
Scenario: Uploading a cohort enrolment method with a non-default role applies only the specified role
Given the following "users" exist:
| username | firstname | lastname | email |
| t1 | Teacher | 1 | s1@example.com |
And the following "cohort members" exist:
| user | cohort |
| t1 | CV4 |
And I upload "admin/tool/uploadcourse/tests/fixtures/enrolment_cohort_multiple.csv" file to "File" filemanager
And I click on "Preview" "button"
And I click on "Upload courses" "button"
When I am on the "Course 1" "course" page
And I navigate to course participants
Then I should see "Non-editing teacher" in the "Teacher 1" "table_row"
And I should not see "Student" in the "Teacher 1" "table_row"
@@ -1,12 +0,0 @@
@tool @tool_xmldb
Feature: The Reconcile XMLDB files report works and all the files are ok
In order to ensure that all the XMLDB Editor xml files are generated properly
As a developer
I need to be able to run the Reconcile XMLDB files report and verify that everything is ok
Scenario: The Reconcile XMLDB files reports that all files are ok
Given I log in as "admin"
And I navigate to "Development > XMLDB editor" in site administration
When I follow "[Reconcile XMLDB files]"
Then I should see "Look for XMLDB files needing reconciling"
And I should see "All files are OK. No reconciling is needed."
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+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:'.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}));
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"]',JUMPTO:'.ai-course-summarise-controls [data-region="jumpto"]',AIDRAWER_CLOSE:"#ai-drawer-close"},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: '.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"}
{"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 JUMPTO: '.ai-course-summarise-controls [data-region=\"jumpto\"]',\n AIDRAWER_CLOSE: '#ai-drawer-close',\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","JUMPTO","AIDRAWER_CLOSE","ACTIONS","SUMMARY","RETRY","DECLINE","ACCEPT","REGENERATE","CANCEL"],"mappings":"oLAsBe,CACXA,SAAU,CACNC,SAAU,aACVC,cAAe,6BACfC,KAAM,QACNC,YAAa,gBACbC,OAAQ,uDACRC,eAAgB,oBAEpBC,QAAS,CACLC,QAAS,mCACTC,MAAO,yCACPC,QAAS,2CACTC,OAAQ,0CACRC,WAAY,8CACZC,OAAQ"}
+44 -25
View File
@@ -31,6 +31,8 @@ import AIHelper from 'core_ai/helper';
import DrawerEvents from 'core/drawer_events';
import {subscribe} from 'core/pubsub';
import * as MessageDrawerHelper from 'core_message/message_drawer_helper';
import * as FocusLock from 'core/local/aria/focuslock';
import {isSmall} from "core/pagehelpers";
const AICourseAssist = class {
@@ -57,6 +59,10 @@ const AICourseAssist = class {
this.aiDrawerElement = document.querySelector(Selectors.ELEMENTS.AIDRAWER);
this.aiDrawerBodyElement = document.querySelector(Selectors.ELEMENTS.AIDRAWER_BODY);
this.pageElement = document.querySelector(Selectors.ELEMENTS.PAGE);
this.jumpToElement = document.querySelector(Selectors.ELEMENTS.JUMPTO);
this.summaryActionElement = document.querySelector(Selectors.ACTIONS.SUMMARY);
this.aiDrawerCloseElement = this.aiDrawerElement.querySelector(Selectors.ELEMENTS.AIDRAWER_CLOSE);
this.isDrawerFocusLocked = false;
this.registerEventListeners();
}
@@ -70,6 +76,7 @@ const AICourseAssist = class {
if (summariseAction) {
e.preventDefault();
this.toggleAIDrawer();
this.summaryActionElement.focus();
const isPolicyAccepted = await this.isPolicyAccepted();
if (!isPolicyAccepted) {
// Display policy.
@@ -81,12 +88,28 @@ const AICourseAssist = class {
}
});
document.addEventListener('keydown', e => {
if (this.isAIDrawerOpen() && e.key === 'Escape') {
this.closeAIDrawer();
}
});
// Close AI drawer if message drawer is shown.
subscribe(DrawerEvents.DRAWER_SHOWN, () => {
if (this.isAIDrawerOpen()) {
this.closeAIDrawer();
}
});
// Focus on the AI drawer's close button when the jump-to element is focused.
this.jumpToElement.addEventListener('focus', () => {
this.aiDrawerCloseElement.focus();
});
// Focus on the summary action element when the AI drawer is focused.
this.aiDrawerElement.addEventListener('focus', () => {
this.summaryActionElement.focus();
});
}
/**
@@ -177,25 +200,42 @@ const AICourseAssist = class {
// Close message drawer if it is shown.
MessageDrawerHelper.hide();
this.aiDrawerElement.classList.add('show');
this.aiDrawerElement.setAttribute('tabindex', '0');
this.aiDrawerBodyElement.setAttribute('aria-live', 'polite');
if (!this.pageElement.classList.contains('show-drawer-right')) {
this.addPadding();
}
// Disable the summary button.
this.disableSummaryButton();
this.jumpToElement.setAttribute('tabindex', 0);
this.jumpToElement.focus();
// If the AI drawer is opened on a small screen, we need to trap the focus tab within the AI drawer.
if (isSmall()) {
FocusLock.trapFocus(this.aiDrawerElement);
this.aiDrawerElement.setAttribute('aria-modal', 'true');
this.aiDrawerElement.setAttribute('role', 'dialog');
this.isDrawerFocusLocked = true;
}
}
/**
* Close the AI drawer.
*/
closeAIDrawer() {
// Untrap focus if it was locked.
if (this.isDrawerFocusLocked) {
FocusLock.untrapFocus();
this.aiDrawerElement.removeAttribute('aria-modal');
this.aiDrawerElement.setAttribute('role', 'region');
}
this.aiDrawerElement.classList.remove('show');
this.aiDrawerElement.setAttribute('tabindex', '-1');
this.aiDrawerBodyElement.removeAttribute('aria-live');
if (this.pageElement.classList.contains('show-drawer-right') && this.aiDrawerBodyElement.dataset.removepadding === '1') {
this.removePadding();
}
// Enable the summary button.
this.enableSummaryButton();
this.jumpToElement.setAttribute('tabindex', -1);
this.summaryActionElement.focus();
}
/**
@@ -225,27 +265,6 @@ const AICourseAssist = class {
this.aiDrawerBodyElement.dataset.removepadding = '0';
}
/**
* Disable the summary button.
*/
disableSummaryButton() {
const summaryButton = document.querySelector(Selectors.ACTIONS.SUMMARY);
if (summaryButton) {
summaryButton.setAttribute('disabled', 1);
}
}
/**
* Enable the summary button and focus on it.
*/
enableSummaryButton() {
const summaryButton = document.querySelector(Selectors.ACTIONS.SUMMARY);
if (summaryButton) {
summaryButton.removeAttribute('disabled');
summaryButton.focus();
}
}
/**
* Check if the policy is accepted.
* @return {bool} True if the policy is accepted, false otherwise.
@@ -26,6 +26,8 @@ export default {
AIDRAWER_BODY: '#ai-drawer .ai-drawer-body',
PAGE: '#page',
MAIN_REGION: '[role="main"]',
JUMPTO: '.ai-course-summarise-controls [data-region="jumpto"]',
AIDRAWER_CLOSE: '#ai-drawer-close',
},
ACTIONS: {
SUMMARY: '[data-action="course-summarise"]',
@@ -22,6 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['aidrawerlabel'] = 'AI-generated content drawer';
$string['aisummary'] = 'AI summary';
$string['courseassist:summarise_text'] = 'Summarise text';
$string['copy'] = 'Copy';
@@ -31,7 +31,7 @@
"content": "<p>Content to display</p>"
}
}}
<div class="ai-drawer" id="ai-drawer">
<div class="ai-drawer" id="ai-drawer" aria-label={{#quote}}{{#str}} aidrawerlabel, aiplacement_courseassist {{/str}}{{/quote}} tabindex="-1" role="region">
<div class="ai-drawer-header">
<button id="ai-drawer-close" class="btn ai-drawer-button" type="button" data-action="course-summarise">
{{#pix}} e/cancel, core {{/pix}}
@@ -33,6 +33,7 @@
data-action="course-summarise"
data-toggle="tooltip"
data-html="true"
data-delay="200"
title="{{#str}} summarise_tooltips, aiplacement_courseassist {{/str}}"
>
<span class="ai-course-summarise-sparkles-icon">
@@ -43,4 +44,5 @@
</span>
{{#str}} summarise, aiplacement_courseassist {{/str}}
</button>
{{> core_message/message_jumpto }}
</div>
+1
View File
@@ -1925,6 +1925,7 @@ class model {
$uniqueid = $this->get_time_splitting()->append_rangeindex($dbprediction->sampleid, $dbprediction->rangeindex);
$predictionrecords[$uniqueid]->id = $dbprediction->id;
}
$dbpredictions->close();
}
return $predictionrecords;
+9
View File
@@ -0,0 +1,9 @@
# core_auth (subsystem / plugintype) Upgrade notes
## 4.5.5
### Added
- A new method called `get_additional_upgrade_token_parameters` has been added to `oauth2_client` class. This will allow custom clients to override this one and add their extra parameters for upgrade token request.
For more information see [MDL-80380](https://tracker.moodle.org/browse/MDL-80380)
+1 -1
View File
@@ -87,7 +87,7 @@ Please log in as before, using the link on the login page.
$string['emailpasswordchangeinfosubject'] = '{$a}: Change password information';
$string['info'] = 'External account';
$string['issuer'] = 'OAuth 2 service';
$string['issuernologin'] = 'This issuer can not be used to login';
$string['issuernologin'] = 'This issuer can not be used to log in.';
$string['key'] = 'Key';
$string['linkedlogins'] = 'Linked logins';
$string['linkedloginshelp'] = 'Help with linked logins';
+1 -1
View File
@@ -31,7 +31,7 @@ $string['auth_shib_contact_administrator'] = 'In case you are not associated wit
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth. For set-up details, see the <a href="{$a}">Shibboleth README</a>.';
$string['auth_shibboleth_errormsg'] = 'Please select the organization you are member of!';
$string['auth_shibboleth_login'] = 'Shibboleth login';
$string['auth_shibboleth_login_long'] = 'Login to Moodle via Shibboleth';
$string['auth_shibboleth_login_long'] = 'Log in via Shibboleth';
$string['auth_shibboleth_manual_login'] = 'Manual login';
$string['auth_shibboleth_select_member'] = 'I\'m a member of ...';
$string['auth_shibboleth_select_organization'] = 'For authentication via Shibboleth, please select your organisation from the drop-down menu:';
+5
View File
@@ -117,6 +117,11 @@ abstract class frontend {
foreach ($enabled as $plugin => $info) {
// Create plugin front-end object.
$class = '\availability_' . $plugin . '\frontend';
if (!class_exists($class)) {
continue;
}
/** @var \core_availability\frontend $frontend */
$frontend = new $class();
// Add to array of required YUI modules.
+2 -3
View File
@@ -792,11 +792,10 @@ abstract class info {
// plugin could also rely on the completion plugin.
$pluginmanager = \core_plugin_manager::instance();
$enabled = $pluginmanager->get_enabled_plugins('availability');
$componentparams = new \stdClass();
foreach ($enabled as $plugin => $info) {
// Use the static method.
/** @var \core_availability\condition $class */
$class = '\availability_' . $plugin . '\condition';
if ($class::completion_value_used($course, $cmid)) {
if (class_exists($class) && $class::completion_value_used($course, $cmid)) {
return true;
}
}
+2 -2
View File
@@ -220,9 +220,9 @@ class tree extends tree_node {
// First see if it's a condition. These have a defined type.
if (isset($child->type)) {
// Look for a plugin of this type.
/** @var \core_availability\condition $classname */
$classname = '\availability_' . $child->type . '\condition';
if (!array_key_exists($child->type, $enabled)) {
if (!array_key_exists($child->type, $enabled) || !class_exists($classname)) {
if ($lax) {
// On load of existing settings, ignore if class
// doesn't exist.
+1 -1
View File
@@ -31,6 +31,6 @@ class core_availability_renderer extends plugin_renderer_base {
*/
#[\core\attribute\deprecated(availability_info::class, since: '4.0', mdl: 'MDL-71691', final: true)]
public function render_core_availability_multiple_messages(): void {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
\core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
}
}
@@ -764,7 +764,7 @@ M.core_availability.List.prototype.clickAdd = function() {
dialogRef.dialog = new M.core.dialogue(config);
dialogRef.dialog.show();
cancel.on('click', function() {
dialogRef.dialog.destroy();
dialogRef.dialog.hide();
// Focus the button they clicked originally.
this.inner.one('> .availability-button').one('button').focus();
}, this);
@@ -801,7 +801,7 @@ M.core_availability.List.prototype.getAddHandler = function(type, dialogRef) {
M.core_availability.form.rootList.renumber();
this.updateHtml();
// Hide dialog.
dialogRef.dialog.destroy();
dialogRef.dialog.hide();
newItem.focusAfterAdd();
};
};
File diff suppressed because one or more lines are too long
@@ -764,7 +764,7 @@ M.core_availability.List.prototype.clickAdd = function() {
dialogRef.dialog = new M.core.dialogue(config);
dialogRef.dialog.show();
cancel.on('click', function() {
dialogRef.dialog.destroy();
dialogRef.dialog.hide();
// Focus the button they clicked originally.
this.inner.one('> .availability-button').one('button').focus();
}, this);
@@ -801,7 +801,7 @@ M.core_availability.List.prototype.getAddHandler = function(type, dialogRef) {
M.core_availability.form.rootList.renumber();
this.updateHtml();
// Hide dialog.
dialogRef.dialog.destroy();
dialogRef.dialog.hide();
newItem.focusAfterAdd();
};
};
+2 -2
View File
@@ -762,7 +762,7 @@ M.core_availability.List.prototype.clickAdd = function() {
dialogRef.dialog = new M.core.dialogue(config);
dialogRef.dialog.show();
cancel.on('click', function() {
dialogRef.dialog.destroy();
dialogRef.dialog.hide();
// Focus the button they clicked originally.
this.inner.one('> .availability-button').one('button').focus();
}, this);
@@ -799,7 +799,7 @@ M.core_availability.List.prototype.getAddHandler = function(type, dialogRef) {
M.core_availability.form.rootList.renumber();
this.updateHtml();
// Hide dialog.
dialogRef.dialog.destroy();
dialogRef.dialog.hide();
newItem.focusAfterAdd();
};
};
+2 -2
View File
@@ -111,7 +111,7 @@ abstract class base_controller extends backup implements loggable {
*/
#[\core\attribute\deprecated(since: '4.1', mdl: 'MDL-74548', final: true)]
public function set_copy(): void {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
\core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
}
/**
@@ -119,6 +119,6 @@ abstract class base_controller extends backup implements loggable {
*/
#[\core\attribute\deprecated('restore_controller::get_copy()', since: '4.1', mdl: 'MDL-74548', final: true)]
public function get_copy() {
\core\deprecation::emit_deprecation_if_present([self::class, __FUNCTION__]);
\core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
}
}
+3 -2
View File
@@ -1093,8 +1093,9 @@ class core_backup_renderer extends plugin_renderer_base {
$sourceurl = new \moodle_url('/course/view.php', array('id' => $copy->sourceid));
$tablerow = array(
html_writer::link($sourceurl, $copy->source),
$copy->destination,
html_writer::link($sourceurl, format_string($copy->source, true,
['context' => context_course::instance($copy->sourceid)])),
format_string($copy->destination, true, ['context' => context_course::instance($copy->sourceid)]),
userdate($copy->timecreated),
get_string($copy->operation),
$this->get_status_display($copy->status, $copy->backupid, $copy->restoreid, $copy->operation)
+3 -1
View File
@@ -37,6 +37,7 @@ if (empty($CFG->enablebadges)) {
}
$badge = new badge($badgeid);
$context = $badge->get_context();
$title = [get_string('alignment', 'badges'), $badge->name];
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:configuredetails', $context);
@@ -47,6 +48,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
navigation_node::override_active_url($navurl);
@@ -60,7 +62,7 @@ $currenturl = new moodle_url('/badges/alignment.php', array('id' => $badge->id))
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name);
$output = $PAGE->get_renderer('core', 'badges');
+113 -59
View File
@@ -60,6 +60,7 @@ if (!empty($issuedbadge->recipient->id)) {
$assertionid = $assertion->get_assertion_hash();
$assertionentityid = $assertiondata['id'];
$badgeadded = false;
$issuerexists = false;
if (badges_open_badges_backpack_api() == OPEN_BADGES_V2) {
$sitebackpack = badges_get_site_primary_backpack();
$api = new \core_badges\backpack_api($sitebackpack);
@@ -71,62 +72,75 @@ if (!empty($issuedbadge->recipient->id)) {
$issuer = $assertion->get_issuer();
if (!($issuerentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ISSUER, $issuer['email']))) {
$response = $api->put_issuer($issuer);
if (!$response) {
throw new moodle_exception('invalidrequest', 'error');
if ($response) {
$issuerexists = true;
$issuerentityid = $response->id;
badges_external_create_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_ISSUER,
$issuer['email'],
$issuerentityid,
);
}
$issuerentityid = $response->id;
badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ISSUER, $issuer['email'],
$issuerentityid);
}
// Create badge.
$badge = $assertion->get_badge_class(false);
$badgeid = $assertion->get_badge_id();
if (!($badgeentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid))) {
$response = $api->put_badgeclass($issuerentityid, $badge);
if (!$response) {
throw new moodle_exception('invalidrequest', 'error');
if ($issuerexists) {
// Create badge.
$badge = $assertion->get_badge_class(false);
$badgeid = $assertion->get_badge_id();
if (!($badgeentityid = badges_external_get_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid))) {
$response = $api->put_badgeclass($issuerentityid, $badge);
if ($response) {
$badgeentityid = $response->id;
badges_external_create_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_BADGE,
$badgeid,
$badgeentityid,
);
}
}
$badgeentityid = $response->id;
badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_BADGE, $badgeid,
$badgeentityid);
}
// Create assertion (Award the badge!).
$assertionentityid = badges_external_get_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionid
);
if ($assertionentityid && strpos($sitebackpack->backpackapiurl, 'badgr')) {
$assertionentityid = badges_generate_badgr_open_url(
$sitebackpack,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionentityid
);
}
// Create an assertion for the recipient in the issuer's account.
if (!$assertionentityid) {
$response = $api->put_badgeclass_assertion($badgeentityid, $assertiondata);
if (!$response) {
throw new moodle_exception('invalidrequest', 'error');
}
$assertionentityid = badges_generate_badgr_open_url($sitebackpack, OPEN_BADGES_V2_TYPE_ASSERTION, $response->id);
$badgeadded = true;
badges_external_create_mapping($sitebackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid,
$response->id);
} else {
// An assertion already exists. Make sure it's up to date.
$internalid = badges_external_get_mapping(
// Create assertion (Award the badge!).
$assertionentityid = badges_external_get_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionid,
'externalid'
$assertionid
);
$response = $api->update_assertion($internalid, $assertiondata);
if (!$response) {
throw new moodle_exception('invalidrequest', 'error');
if ($assertionentityid && strpos($sitebackpack->backpackapiurl, 'badgr')) {
$assertionentityid = badges_generate_badgr_open_url(
$sitebackpack,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionentityid
);
}
// Create an assertion for the recipient in the issuer's account.
if (!$assertionentityid) {
$response = $api->put_badgeclass_assertion($badgeentityid, $assertiondata);
if ($response) {
$assertionentityid = badges_generate_badgr_open_url(
$sitebackpack,
OPEN_BADGES_V2_TYPE_ASSERTION,
$response->id,
);
$badgeadded = true;
badges_external_create_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionid,
$response->id,
);
}
} else {
// An assertion already exists. Make sure it's up to date.
$internalid = badges_external_get_mapping(
$sitebackpack->id,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionid,
'externalid'
);
$response = $api->update_assertion($internalid, $assertiondata);
}
}
}
@@ -136,21 +150,61 @@ if (!empty($issuedbadge->recipient->id)) {
// - If a user and site backpack have the same provider we can skip this as Badgr automatically maps recipients
// based on email address.
// - This is only needed when the backpacks are from different regions.
if ($assertionentityid && !badges_external_get_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid)) {
if (
$assertionentityid
&& (!$issuerexists || !badges_external_get_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid))
) {
$userapi = new \core_badges\backpack_api($userbackpack, $backpack);
$userapi->authenticate();
$response = $userapi->import_badge_assertion($assertionentityid);
if (!$response) {
throw new moodle_exception('invalidrequest', 'error');
if ($response) {
$assertionentityid = $response->id;
$badgeadded = true;
badges_external_create_mapping(
$userbackpack->id,
OPEN_BADGES_V2_TYPE_ASSERTION,
$assertionid,
$assertionentityid,
);
}
$assertionentityid = $response->id;
$badgeadded = true;
badges_external_create_mapping($userbackpack->id, OPEN_BADGES_V2_TYPE_ASSERTION, $assertionid,
$assertionentityid);
}
$response = $badgeadded ? ['success' => 'addedtobackpack'] : ['warning' => 'existsinbackpack'];
redirect(new moodle_url('/badges/mybadges.php', $response));
if ($badgeadded) {
$message = get_string('addedtobackpack', 'badges');
$messagetype = \core\output\notification::NOTIFY_SUCCESS;
} else {
if (isset($userapi) && !empty($userapi->get_errors())) {
// If the api used to import the badge to the backpack has errors, show them to inform the user.
if (array_filter($userapi->get_errors(), fn($element) => str_contains($element, "DUPLICATE_BADGE"))) {
// Duplicated badges are displayed as a warning.
$message = get_string('existsinbackpack', 'badges');
$messagetype = \core\output\notification::NOTIFY_WARNING;
} else {
// If the userapi has any other errors, we will use those to inform the user.
$message = get_string(
'error:cannotsendtobackpack',
'badges',
implode($userapi->get_errors()),
);
$messagetype = \core\output\notification::NOTIFY_ERROR;
}
} else if (isset($api) && !empty($api->get_errors())) {
// If the api used to create/update the issuer has errors, show them to inform the user.
$errors = $api->get_errors() ?? [get_string('invalidrequest', 'error')];
$message = get_string(
'error:cannotsendtobackpack',
'badges',
implode($errors),
);
$messagetype = \core\output\notification::NOTIFY_ERROR;
}
}
redirect(
url: new \core\url('/badges/mybadges.php'),
message: $message,
messagetype: $messagetype,
);
} else {
redirect(new moodle_url('/badges/mybadges.php'));
redirect(new \core\url('/badges/mybadges.php'));
}
+1 -1
View File
@@ -56,7 +56,7 @@ if ($action == 'delete' && $confirm && confirm_sesskey()) {
} else {
$msg = get_string('sitebackpacknotdeleted', 'badges');
}
} else if ($action == 'moveup' || $action == 'movedown') {
} else if (($action == 'moveup' || $action == 'movedown') && confirm_sesskey()) {
// If no backpack has been selected, there isn't anything to move.
if (empty($id)) {
redirect($url);
+14
View File
@@ -512,6 +512,20 @@ class backpack_api {
return backpack_api_mapping::get_authentication_error();
}
/**
* List all errors occurred during the requests to the backpack.
*
* @return array The list of errors.
*/
public function get_errors(): array {
$errors = [];
foreach ($this->mappings as $mapping) {
$errors = array_merge($errors, $mapping->get_errors());
}
return $errors;
}
/**
* Get the list of badges in a collection.
*
+40
View File
@@ -81,6 +81,9 @@ class backpack_api_mapping {
/** @var int OpenBadges version. */
protected $backpackapiversion;
/** @var array Errors encountered during the request. */
protected $errors = [];
/**
* Create a mapping.
*
@@ -146,6 +149,26 @@ class backpack_api_mapping {
return self::$authenticationerror;
}
/**
* Get the errors encountered during the request.
*
* @return array The list of errors.
*/
public function get_errors() {
return $this->errors;
}
/**
* Add an error to the list of errors.
*
* @param string $error The error message.
* @return self This instance for method chaining.
*/
public function add_error(string $error): self {
$this->errors[] = $error;
return $this;
}
/**
* Does the action match this mapping?
*
@@ -342,6 +365,23 @@ class backpack_api_mapping {
$response = $curl->put($url, $post, $options);
}
$response = json_decode($response);
if ($response === null) {
$this->add_error(get_string('invalidrequest', 'error'));
return null;
}
if (isset($response->status) && isset($response->status->success) && $response->status->success != true) {
// If the response wasn't successful, store the errors and return null.
if (isset($response->validationErrors)) {
$error = implode(', ', $response->validationErrors);
} else if (isset($response->status->description)) {
$error = $response->status->description;
} else {
$error = get_string('invalidrequest', 'error');
}
$this->add_error($error);
return null;
}
if (isset($response->result)) {
$response = $response->result;
}
@@ -130,6 +130,38 @@ class badge extends base {
return html_writer::link($url, $row->name);
});
// Name with image and link.
$columns[] = (new column(
'namewithimagelink',
new lang_string('namewithimagelink', 'core_badges'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->add_join("LEFT JOIN {context} {$contextalias}
ON {$contextalias}.contextlevel = " . CONTEXT_COURSE . "
AND {$contextalias}.instanceid = {$badgealias}.courseid")
->add_fields(
"{$badgealias}.name, {$badgealias}.id, {$badgealias}.type, {$badgealias}.courseid"
)
->add_field($DB->sql_cast_to_char("{$badgealias}.imagecaption"), 'imagecaption')
->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
->set_is_sortable(true)
->add_callback(static function ($value, stdClass $badge): string {
if ($badge->id === null) {
return '';
}
if ($badge->type == BADGE_TYPE_SITE) {
$context = context_system::instance();
} else {
context_helper::preload_from_record($badge);
$context = context_course::instance($badge->courseid);
}
$badgeimage = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f2');
$url = new moodle_url('/badges/overview.php', ['id' => $badge->id]);
return html_writer::img($badgeimage, $badge->imagecaption) . ' ' . html_writer::link($url, $badge->name);
});
// Description (note, this column contains plaintext so requires no post-processing).
$descriptionfieldsql = "{$badgealias}.description";
if ($DB->get_dbfamily() === 'oracle') {
@@ -94,8 +94,6 @@ class badges extends system_report {
$this->add_filters();
$this->add_actions();
// Set initial sorting by name.
$this->set_initial_sort_column('badge:namewithlink', SORT_ASC);
$this->set_default_no_results_notice(new lang_string('nomatchingbadges', 'core_badges'));
// Set if report can be downloaded.
@@ -129,8 +127,7 @@ class badges extends system_report {
*/
public function add_columns(string $badgeissuedalias): void {
$columns = [
'badge:image',
'badge:namewithlink',
'badge:namewithimagelink',
'badge:status',
'badge:criteria',
];
@@ -138,15 +135,12 @@ class badges extends system_report {
$canviewdraftbadges = $this->can_view_draft_badges();
if (!$canviewdraftbadges) {
// Remove status and recipients column.
unset($columns[2]);
unset($columns[1]);
}
$this->add_columns_from_entities($columns);
// Remove title from image column.
$this->get_column('badge:image')->set_title(null);
// Change title from namewithlink column.
$this->get_column('badge:namewithlink')->set_title(new lang_string('name'));
// Change title of the `namewithimagelink` column to 'Name'.
$this->get_column('badge:namewithimagelink')->set_title(new lang_string('name'));
// Recipients column.
if ($canviewdraftbadges) {
@@ -193,7 +187,7 @@ class badges extends system_report {
return $OUTPUT->action_icon($badgeurl, $icon, null, null, true);
});
$this->set_initial_sort_column('badge:namewithlink', SORT_ASC);
$this->set_initial_sort_column('badge:namewithimagelink', SORT_ASC);
}
/**
@@ -51,7 +51,7 @@ class course_badges extends system_report {
*/
#[\core\attribute\deprecated('course_badges::initialise', since: '4.5', mdl: 'MDL-82503')]
protected function initialise(): void {
\core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
\core\deprecation::emit_deprecation([$this, __FUNCTION__]);
global $USER;
// Our main entity, it contains all of the column definitions that we need.
$badgeentity = new badge();
@@ -103,7 +103,7 @@ class course_badges extends system_report {
*/
#[\core\attribute\deprecated('course_badges::can_view', since: '4.5', mdl: 'MDL-82503')]
protected function can_view(): bool {
\core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
\core\deprecation::emit_deprecation([$this, __FUNCTION__]);
return has_capability('moodle/badges:viewbadges', $this->get_context());
}
@@ -118,7 +118,7 @@ class course_badges extends system_report {
*/
#[\core\attribute\deprecated('course_badges::add_columns', since: '4.5', mdl: 'MDL-82503')]
protected function add_columns(): void {
\core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
\core\deprecation::emit_deprecation([$this, __FUNCTION__]);
$badgeissuedalias = $this->get_entity('badge_issued')->get_table_alias('badge_issued');
$this->add_columns_from_entities([
@@ -156,7 +156,7 @@ class course_badges extends system_report {
*/
#[\core\attribute\deprecated('course_badges::add_filters', since: '4.5', mdl: 'MDL-82503')]
protected function add_filters(): void {
\core\deprecation::emit_deprecation_if_present([$this, __FUNCTION__]);
\core\deprecation::emit_deprecation([$this, __FUNCTION__]);
$this->add_filters_from_entities([
'badge:name',
'badge_issued:issued',
+3 -1
View File
@@ -38,6 +38,7 @@ if (empty($CFG->enablebadges)) {
$badge = new badge($badgeid);
$context = $badge->get_context();
$title = [get_string('bcriteria', 'badges'), $badge->name];
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:configurecriteria', $context);
@@ -49,6 +50,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
navigation_node::override_active_url($navurl);
@@ -63,7 +65,7 @@ $currenturl = new moodle_url('/badges/criteria.php', array('id' => $badge->id));
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name, $currenturl);
$output = $PAGE->get_renderer('core', 'badges');
+4 -2
View File
@@ -41,6 +41,7 @@ require_login();
$return = new moodle_url('/badges/criteria.php', array('id' => $badgeid));
$badge = new badge($badgeid);
$title = [get_string('addcriterion', 'badges'), $badge->name];
$context = $badge->get_context();
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
@@ -65,6 +66,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
navigation_node::override_active_url($navurl);
@@ -78,7 +80,7 @@ $urlparams = array('badgeid' => $badgeid, 'edit' => $edit, 'type' => $type, 'cri
$PAGE->set_context($context);
$PAGE->set_url('/badges/criteria_settings.php', $urlparams);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name, new moodle_url('overview.php', array('id' => $badge->id)))
->add(get_string('bcriteria', 'badges'), new moodle_url('criteria.php', ['id' => $badge->id]))
->add(get_string('criteria_' . $type, 'badges'));
@@ -119,4 +121,4 @@ if (!empty($addcourse)) {
echo $OUTPUT->header();
$mform->display();
echo $OUTPUT->footer();
echo $OUTPUT->footer();
+5 -1
View File
@@ -56,8 +56,10 @@ if (!empty($badgeid)) {
// Check capabilities.
$context = $badge->get_context();
if ($action == 'message') {
$title = [get_string('configuremessage', 'badges'), $badge->name];
require_capability('moodle/badges:configuremessages', $context);
} else {
$title = [get_string('badgedetails', 'badges'), $badge->name];
require_capability('moodle/badges:configuredetails', $context);
}
@@ -78,6 +80,7 @@ if (!empty($badgeid)) {
$params = ['courseid' => $courseid];
$badgename = get_string('create', 'badges');
$title = [$badgename];
// Check capabilities.
require_capability('moodle/badges:createbadge', $context);
@@ -94,6 +97,7 @@ $navurl = new moodle_url('/badges/index.php', ['type' => $badge->type]);
if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', ['type' => $badge->type, 'id' => $badge->courseid]);
$PAGE->set_pagelayout('incourse');
navigation_node::override_active_url($navurl);
@@ -108,7 +112,7 @@ $currenturl = new moodle_url('/badges/edit.php', $params);
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badgename);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->add_body_class('limitedwidth');
$PAGE->navbar->add($badgename);
+3 -1
View File
@@ -36,6 +36,7 @@ if (empty($CFG->enablebadges)) {
$badge = new badge($badgeid);
$context = $badge->get_context();
$title = [get_string('bendorsement', 'badges'), $badge->name];
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:configuredetails', $context);
@@ -46,6 +47,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
navigation_node::override_active_url($navurl);
@@ -59,7 +61,7 @@ $currenturl = new moodle_url('/badges/endorsement.php', array('id' => $badgeid))
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name);
$output = $PAGE->get_renderer('core', 'badges');
+3 -1
View File
@@ -39,6 +39,7 @@ if (empty($CFG->enablebadges)) {
$badge = new badge($badgeid);
$context = $badge->get_context();
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
$title = [$badge->name];
if ($badge->type == BADGE_TYPE_COURSE) {
if (empty($CFG->badges_allowcoursebadges)) {
@@ -47,6 +48,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
@@ -62,7 +64,7 @@ $currenturl = new moodle_url('/badges/overview.php', array('id' => $badge->id));
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name);
require_capability('moodle/badges:viewbadges', $context);
+3 -1
View File
@@ -40,6 +40,7 @@ if (empty($CFG->enablebadges)) {
$badge = new badge($badgeid);
$context = $badge->get_context();
$title = [get_string('awards', 'badges'), $badge->name];
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:viewawarded', $context);
@@ -51,6 +52,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
navigation_node::override_active_url($navurl);
@@ -63,7 +65,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
$PAGE->set_context($context);
$PAGE->set_url('/badges/recipients.php', ['id' => $badgeid]);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name);
/** @var core_badges_renderer $output */
+3 -1
View File
@@ -40,6 +40,7 @@ if (empty($CFG->enablebadges)) {
$badge = new badge($badgeid);
$context = $badge->get_context();
$title = [get_string('relatedbages', 'badges'), $badge->name];
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type));
require_capability('moodle/badges:configuredetails', $context);
@@ -50,6 +51,7 @@ if ($badge->type == BADGE_TYPE_COURSE) {
require_login($badge->courseid);
$course = get_course($badge->courseid);
$heading = format_string($course->fullname, true, ['context' => $context]);
$title[] = $heading;
$navurl = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
$PAGE->set_pagelayout('standard');
@@ -64,7 +66,7 @@ $currenturl = new moodle_url('/badges/related.php', array('id' => $badge->id));
$PAGE->set_context($context);
$PAGE->set_url($currenturl);
$PAGE->set_heading($heading);
$PAGE->set_title($badge->name);
$PAGE->set_title(implode(\moodle_page::TITLE_SEPARATOR, $title));
$PAGE->navbar->add($badge->name);
$output = $PAGE->get_renderer('core', 'badges');
$msg = optional_param('msg', '', PARAM_TEXT);
@@ -56,13 +56,13 @@
<td> {{{backpackweburl}}} </td>
<td>
{{#canmoveup}}
<a href="{{baseurl}}?id={{id}}&action=moveup">{{#pix}}t/up, core,{{#str}}moveup{{/str}}{{/pix}}</a>
<a href="{{baseurl}}?id={{id}}&sesskey={{sesskey}}&action=moveup">{{#pix}}t/up, core,{{#str}}moveup{{/str}}{{/pix}}</a>
{{/canmoveup}}
{{^canmoveup}}
{{#pix}}spacer, moodle{{/pix}}
{{/canmoveup}}
{{#canmovedown}}
<a href="{{baseurl}}?id={{id}}&action=movedown">{{#pix}}t/down, core,{{#str}}movedown{{/str}}{{/pix}}</a>
<a href="{{baseurl}}?id={{id}}&sesskey={{sesskey}}&action=movedown">{{#pix}}t/down, core,{{#str}}movedown{{/str}}{{/pix}}</a>
{{/canmovedown}}
{{^canmovedown}}
{{#pix}}spacer, moodle{{/pix}}
+2
View File
@@ -118,6 +118,7 @@ Feature: Manage badges
| Admin User |
| User One |
@accessibility
Scenario: View list of badges with recipients
Given the following "users" exist:
| username | firstname | lastname |
@@ -139,6 +140,7 @@ Feature: Manage badges
| Badge #1 | Not available | 2 |
| Badge #2 | Available | 1 |
| Badge #3 | Available | 0 |
And the "Badges" "table" should meet accessibility standards with "best-practice" extra tests
@_file_upload
Scenario: Badge names are not unique anymore
@@ -125,6 +125,7 @@ final class badges_test extends core_reportbuilder_testcase {
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:fullname', 'sortenabled' => 1]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'badge:namewithlink']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'badge:namewithimagelink']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'badge:criteria']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'badge:image']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'badge:language']);
@@ -146,11 +147,12 @@ final class badges_test extends core_reportbuilder_testcase {
['id' => $badgeone->id]), ($badgeone->name));
// First badge, issued to user one.
[$badgename, $fullname, $namewithlink, $criteria, $image, $language, $version, $status, $expiry, $tag, $expires,
$visible, $coursename] = array_values($content[0]);
[$badgename, $fullname, $namewithlink, $namewithimagelink, $criteria, $image, $language, $version, $status, $expiry, $tag,
$expires, $visible, $coursename] = array_values($content[0]);
$this->assertEquals($badgeone->name, $badgename);
$this->assertEquals(fullname($user1), $fullname);
$this->assertEquals($expectedbadgeonelink, $namewithlink);
$this->assertEquals($image . ' ' . $expectedbadgeonelink, $namewithimagelink);
$this->assertStringContainsString('Awarded by: Manager', $criteria);
$this->assertStringContainsString('Image caption', $image);
$this->assertEquals('German', $language);
@@ -163,11 +165,12 @@ final class badges_test extends core_reportbuilder_testcase {
$this->assertEquals('PHPUnit test site', $coursename);
// First badge, issued to user two.
[$badgename, $fullname, $namewithlink, $criteria, $image, $language, $version, $status, $expiry, $tag, $expires,
$visible, $coursename] = array_values($content[1]);
[$badgename, $fullname, $namewithlink, $namewithimagelink, $criteria, $image, $language, $version, $status, $expiry, $tag,
$expires, $visible, $coursename] = array_values($content[1]);
$this->assertEquals($badgeone->name, $badgename);
$this->assertEquals(fullname($user2), $fullname);
$this->assertEquals($expectedbadgeonelink, $namewithlink);
$this->assertEquals($image . ' ' . $expectedbadgeonelink, $namewithimagelink);
$this->assertStringContainsString('Awarded by: Manager', $criteria);
$this->assertStringContainsString('Image caption', $image);
$this->assertEquals('German', $language);
@@ -183,11 +186,12 @@ final class badges_test extends core_reportbuilder_testcase {
['id' => $badgetwo->id]), ($badgetwo->name));
// Course badge, not issues to any users.
[$badgename, $fullname, $namewithlink, $criteria, $image, $language, $version, $status, $expiry, $tag, $expires,
$visible, $coursename] = array_values($content[2]);
[$badgename, $fullname, $namewithlink, $namewithimagelink, $criteria, $image, $language, $version, $status, $expiry, $tag,
$expires, $visible, $coursename] = array_values($content[2]);
$this->assertEquals($badgetwo->name, $badgename);
$this->assertEmpty($fullname);
$this->assertEquals($expectedbadgetwolink, $namewithlink);
$this->assertEquals($image . ' ' . $expectedbadgetwolink, $namewithimagelink);
$this->assertEquals('Criteria for this badge have not been set up yet.', $criteria);
$this->assertStringContainsString('Image caption', $image);
$this->assertEquals('English', $language);
+1 -1
View File
@@ -95,7 +95,7 @@ class fetch_addable_blocks extends external_api {
}
// Firstly, we need to load all currently existing page blocks to later determine which blocks are addable.
$page->blocks->load_blocks(false);
$page->blocks->load_blocks(true);
$page->blocks->create_all_block_instances();
$addableblocks = $page->blocks->get_addable_blocks();
+5
View File
@@ -441,6 +441,11 @@ class block_edit_form extends \core_form\dynamic_form {
$blockregion = $this->optional_param('blockregion', null, PARAM_TEXT);
$newblock = $this->page->blocks->add_block_at_end_of_default_region($this->block->name(),
empty($blockregion) ? null : $blockregion);
if (empty($newblock)) {
return;
}
$this->page->blocks->load_blocks();
$newblock = $this->page->blocks->find_instance($newblock->instance->id);
$newdata = $this->prepare_defaults($newblock->instance);
+9 -4
View File
@@ -32,7 +32,9 @@
* @todo MDL-36050 improve capability check on stick blocks, so we can check user capability before sending images.
*/
function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
global $DB, $CFG, $USER;
global $CFG;
require_once("{$CFG->dirroot}/user/lib.php");
if ($context->contextlevel != CONTEXT_BLOCK) {
send_file_not_found();
@@ -51,9 +53,12 @@ function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $a
if (!core_course_category::get($parentcontext->instanceid, IGNORE_MISSING)) {
send_file_not_found();
}
} else if ($parentcontext->contextlevel === CONTEXT_USER && $parentcontext->instanceid != $USER->id) {
// The block is in the context of a user, it is only visible to the user who it belongs to.
send_file_not_found();
} else if ($parentcontext->contextlevel === CONTEXT_USER) {
$user = core_user::get_user($parentcontext->instanceid, '*', MUST_EXIST);
$extracaps = block_method_result('html', 'get_extra_capabilities');
if (!user_can_view_profile($user, null, $parentcontext) || !has_any_capability($extracaps, $context)) {
send_file_not_found();
}
}
// At this point there is no way to check SYSTEM context, so ignoring it.
}
@@ -297,6 +297,7 @@ final class provider_test extends \core_privacy\tests\provider_testcase {
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$this->setUser($user);
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher');
$block = $this->create_course_block($course, $title, $content, $format);
$context = \context_block::instance($block->instance->id);
@@ -324,6 +325,7 @@ final class provider_test extends \core_privacy\tests\provider_testcase {
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$this->setUser($user);
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'editingteacher');
$block = $this->create_course_block($course, $title, $content, $format);
$context = \context_block::instance($block->instance->id);
@@ -369,6 +371,7 @@ final class provider_test extends \core_privacy\tests\provider_testcase {
$this->setUser($user2);
$course = $this->getDataGenerator()->create_course();
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
$courseblock = $this->create_course_block($course, $title, $content, $blockformat);
$coursecontext = \context_block::instance($courseblock->instance->id);
+1 -1
View File
@@ -591,7 +591,7 @@ class main implements renderable, templatable {
if ($CFG->coursecreationguide) {
// Add quickstart guide link.
$quickstart = new \moodle_url($CFG->coursecreationguide, ['lang' => current_language()]);
$docparams = [
$docparams += [
'quickhref' => $quickstart->out(),
'quicktitle' => get_string('viewquickstart', 'block_myoverview'),
'quicktarget' => '_blank',
@@ -24,8 +24,6 @@
}}
<div id="block-myoverview-{{uniqid}}" class="block-myoverview block-cards" data-region="myoverview" role="navigation">
<hr class="mt-0"/>
<div role="search" data-region="filter" class="d-flex align-items-center my-2" aria-label="{{#str}} aria:controls, block_myoverview {{/str}}">
<div class="row g-0">
{{> block_myoverview/nav-grouping-selector }}
@@ -51,7 +51,7 @@
{{{icon}}}
</div>
<div class="w-100 line-height-3 text-truncate ms-2">
<h6 class="mb-0 text-truncate"><span class="clickable">{{{name}}}</span></h6>
<h4 class="mb-0 text-truncate h6"><span class="clickable">{{{name}}}</span></h4>
<small class="text-truncate mb-0">{{{coursename}}}</small>
</div>
</div>
+4
View File
@@ -13,3 +13,7 @@
.block_social_activities .instancename {
word-break: break-all;
}
.block_social_activities .inplaceeditable.inplaceeditingon input {
width: 100%;
}
+6
View File
@@ -44,6 +44,7 @@ final class externallib_test extends externallib_advanced_testcase {
global $DB, $FULLME;
$this->resetAfterTest(true);
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
@@ -77,6 +78,7 @@ final class externallib_test extends externallib_advanced_testcase {
global $DB, $FULLME;
$this->resetAfterTest(true);
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
@@ -141,6 +143,7 @@ final class externallib_test extends externallib_advanced_testcase {
global $DB, $FULLME;
$this->resetAfterTest(true);
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
@@ -237,6 +240,7 @@ final class externallib_test extends externallib_advanced_testcase {
global $DB, $CFG;
$this->resetAfterTest(true);
$this->setAdminUser();
// Enable MathJax filter in content and headings.
$this->configure_filters([
@@ -362,6 +366,7 @@ final class externallib_test extends externallib_advanced_testcase {
public function test_get_dashboard_blocks_default_dashboard_including_sticky_block(): void {
global $PAGE, $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
@@ -410,6 +415,7 @@ final class externallib_test extends externallib_advanced_testcase {
public function test_get_dashboard_blocks_custom_user_dashboard(): void {
global $PAGE, $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$PAGE->set_url('/my/index.php'); // Need this because some internal API calls require the $PAGE url to be set.
+8 -8
View File
@@ -62,13 +62,6 @@ if ($id) {
$sitecontext = context_system::instance();
$usercontext = context_user::instance($userid);
if ($modid) {
$PAGE->set_context($sitecontext);
} else {
$PAGE->set_context($usercontext);
$blognode = $PAGE->settingsnav->find('blogadd', null);
$blognode->make_active();
}
require_login($courseid);
@@ -80,8 +73,15 @@ if (isguestuser()) {
throw new \moodle_exception('noguest');
}
$returnurl = new moodle_url('/blog/index.php');
if ($modid) {
$PAGE->set_context($sitecontext);
} else {
$PAGE->set_context($usercontext);
$blognode = $PAGE->settingsnav->find('blogadd', null);
$blognode->make_active();
}
$returnurl = new moodle_url('/blog/index.php');
if (!empty($courseid) && empty($modid)) {
$returnurl->param('courseid', $courseid);
}
+26 -17
View File
@@ -34,15 +34,21 @@ $PAGE->set_url(new moodle_url('/blog/external_blogs.php'));
require_capability('moodle/blog:manageexternal', $context);
$delete = optional_param('delete', null, PARAM_INT);
$confirm = optional_param('confirm', false, PARAM_BOOL);
$strexternalblogs = get_string('externalblogs', 'blog');
$straddnewexternalblog = get_string('addnewexternalblog', 'blog');
$strblogs = get_string('blogs', 'blog');
$message = null;
if ($delete && confirm_sesskey()) {
$externalblog = $DB->get_record('blog_external', array('id' => $delete));
if ($externalblog->userid == $USER->id) {
$PAGE->set_title("{$strblogs}: {$strexternalblogs}");
$PAGE->set_pagelayout('standard');
if ($delete) {
$externalblog = $DB->get_record('blog_external', ['id' => $delete, 'userid' => $USER->id], '*', MUST_EXIST);
if ($confirm) {
require_sesskey();
// Delete the external blog.
$DB->delete_records('blog_external', array('id' => $delete));
@@ -60,23 +66,28 @@ if ($delete && confirm_sesskey()) {
$event = \core\event\blog_external_removed::create($eventparms);
$event->add_record_snapshot('blog_external', $externalblog);
$event->trigger();
$message = get_string('externalblogdeleted', 'blog');
redirect($PAGE->url, get_string('externalblogdeleted', 'blog'));
} else {
echo $OUTPUT->header();
echo $OUTPUT->heading("{$strexternalblogs}: " . s($externalblog->name), 2);
echo $OUTPUT->confirm(
get_string('deleteexternalblog', 'blog'),
new moodle_url($PAGE->url->out_omit_querystring(), ['delete' => $delete, 'confirm' => 1]),
$PAGE->url,
);
echo $OUTPUT->footer();
die;
}
}
$blogs = $DB->get_records('blog_external', array('userid' => $USER->id));
$PAGE->set_heading(fullname($USER));
$PAGE->set_title("$strblogs: $strexternalblogs");
$PAGE->set_pagelayout('standard');
echo $OUTPUT->header();
echo $OUTPUT->heading($strexternalblogs, 2);
if (!empty($message)) {
echo $OUTPUT->notification($message);
}
echo $OUTPUT->box_start('generalbox boxaligncenter');
if (!empty($blogs)) {
@@ -99,10 +110,8 @@ if (!empty($blogs)) {
$editurl = new moodle_url('/blog/external_blog_edit.php', array('id' => $blog->id));
$editicon = $OUTPUT->action_icon($editurl, new pix_icon('t/edit', get_string('editexternalblog', 'blog')));
$deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey' => sesskey()));
$action = new confirm_action(get_string('externalblogdeleteconfirm', 'blog'));
$deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')),
$action);
$deletelink = new moodle_url('/blog/external_blogs.php', ['delete' => $blog->id]);
$deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')));
$table->data[] = new html_table_row(array($blog->name,
$blog->url,
+1 -1
View File
@@ -74,7 +74,7 @@ class footer_options_exporter extends exporter {
*/
protected function get_manage_subscriptions_link(): ?string {
if (calendar_user_can_add_event($this->calendar->course)) {
$managesubscriptionurl = new moodle_url('/calendar/managesubscriptions.php');
$managesubscriptionurl = new moodle_url('/calendar/managesubscriptions.php', ['course' => $this->calendar->courseid]);
return $managesubscriptionurl->out(true);
}
return null;
@@ -213,7 +213,8 @@ class create extends \moodleform {
$group[] = $mform->createElement('radio', 'duration', null, get_string('durationuntil', 'calendar'), 1);
$group[] = $mform->createElement('date_time_selector', 'timedurationuntil', '');
$group[] = $mform->createElement('radio', 'duration', null, get_string('durationminutes', 'calendar'), 2);
$group[] = $mform->createElement('text', 'timedurationminutes', get_string('durationminutes', 'calendar'));
$group[] = $mform->createElement('text', 'timedurationminutes',
get_string('durationminutes', 'calendar'), 'maxlength="7" size="7"');
$mform->addGroup($group, 'durationgroup', get_string('eventduration', 'calendar'), '<br />', false);
$mform->setAdvanced('durationgroup');
@@ -227,6 +228,9 @@ class create extends \moodleform {
$mform->setType('timedurationminutes', PARAM_INT);
$mform->disabledIf('timedurationminutes', 'duration', 'noteq', 2);
$mform->addGroupRule('durationgroup', [
'timedurationminutes' => [[get_string('maximumchars', '', 7), 'maxlength', 7, 'server']],
]);
$mform->setDefault('duration', 0);
}
@@ -238,11 +242,12 @@ class create extends \moodleform {
*/
protected function add_event_repeat_elements($mform) {
$mform->addElement('checkbox', 'repeat', get_string('repeatevent', 'calendar'), null);
$mform->addElement('text', 'repeats', get_string('repeatweeksl', 'calendar'), 'maxlength="10" size="10"');
$mform->addElement('text', 'repeats', get_string('repeatweeksl', 'calendar'), 'maxlength="3" size="3"');
$mform->setType('repeats', PARAM_INT);
$mform->setDefault('repeats', 1);
$mform->disabledIf('repeats', 'repeat', 'notchecked');
$mform->setAdvanced('repeat');
$mform->setAdvanced('repeats');
$mform->addRule('repeats', get_string('maximumchars', '', 3), 'maxlength', 3, 'server');
}
}
+7 -2
View File
@@ -121,7 +121,8 @@ class event_form extends moodleform {
$group[] =& $mform->createElement('radio', 'duration', null, get_string('durationuntil', 'calendar'), 1);
$group[] =& $mform->createElement('date_time_selector', 'timedurationuntil', '');
$group[] =& $mform->createElement('radio', 'duration', null, get_string('durationminutes', 'calendar'), 2);
$group[] =& $mform->createElement('text', 'timedurationminutes', get_string('durationminutes', 'calendar'));
$group[] =& $mform->createElement('text', 'timedurationminutes',
get_string('durationminutes', 'calendar'), 'maxlength="7" size="7"');
$mform->addGroup($group, 'durationgroup', '', '<br />', false);
@@ -134,6 +135,9 @@ class event_form extends moodleform {
$mform->setType('timedurationminutes', PARAM_INT);
$mform->disabledIf('timedurationminutes','duration','noteq', 2);
$mform->addGroupRule('durationgroup', [
'timedurationminutes' => [[get_string('maximumchars', '', 7), 'maxlength', 7, 'server']],
]);
$mform->setDefault('duration', ($hasduration)?1:0);
@@ -141,10 +145,11 @@ class event_form extends moodleform {
$mform->addElement('header', 'repeatevents', get_string('repeatedevents', 'calendar'));
$mform->addElement('checkbox', 'repeat', get_string('repeatevent', 'calendar'), null);
$mform->addElement('text', 'repeats', get_string('repeatweeksl', 'calendar'), 'maxlength="10" size="10"');
$mform->addElement('text', 'repeats', get_string('repeatweeksl', 'calendar'), 'maxlength="3" size="3"');
$mform->setType('repeats', PARAM_INT);
$mform->setDefault('repeats', 1);
$mform->disabledIf('repeats','repeat','notchecked');
$mform->addRule('repeats', get_string('maximumchars', '', 3), 'maxlength', 3, 'server');
} else if ($repeatedevents) {
+2 -2
View File
@@ -3642,7 +3642,7 @@ function calendar_output_fragment_event_form($args) {
$groupcoursedata = groups_get_course_data($courseid);
$formoptions['groups'] = [];
foreach ($groupcoursedata->groups as $groupid => $groupdata) {
$formoptions['groups'][$groupid] = $groupdata->name;
$formoptions['groups'][$groupid] = format_string($groupdata->name, false, ['context' => $context]);
}
}
@@ -3686,7 +3686,7 @@ function calendar_output_fragment_event_form($args) {
$groupcoursedata = groups_get_course_data($event->courseid);
$formoptions['groups'] = [];
foreach ($groupcoursedata->groups as $groupid => $groupdata) {
$formoptions['groups'][$groupid] = $groupdata->name;
$formoptions['groups'][$groupid] = format_string($groupdata->name, false, ['context' => $context]);
}
}
+2 -2
View File
@@ -55,7 +55,7 @@
{{/icon}}
</div>
<div class="overflow-auto">
<h6 class="d-flex mb-1">
<h4 class="d-flex mb-1 h6">
<a{{!
}} class="text-truncate"{{!
}} data-type="event"{{!
@@ -64,7 +64,7 @@
}} href="{{viewurl}}"{{!
}} title="{{name}}"{{!
}}>{{{name}}}</a>
</h6>
</h4>
<div class="date small">{{{formattedtime}}}</div>
</div>
</div>
+14 -5
View File
@@ -27,8 +27,8 @@ Feature: Perform basic calendar functionality
| teacher1 | C1 | teacher |
| admin | C1 | editingteacher |
And the following "groups" exist:
| name | course | idnumber |
| Group 1 | C1 | G1 |
| name | course | idnumber |
| <span lang="en" class="multilang">Group</span><span lang="es" class="multilang">Grupo</span> 1 | C1 | G1 |
And the following "group members" exist:
| user | group |
| student1 | G1 |
@@ -75,7 +75,9 @@ Feature: Perform basic calendar functionality
@javascript
Scenario: Create a group event
Given I log in as "teacher1"
Given the "multilang" filter is "on"
And the "multilang" filter applies to "content and headings"
And I log in as "teacher1"
And I follow "Full calendar"
And I set the field "course" to "Course 1"
And I create a calendar event:
@@ -322,18 +324,23 @@ Feature: Perform basic calendar functionality
@javascript
Scenario: Changing the event type should clear previous data
Given I am on the "Course 1" course page logged in as admin
Given the "multilang" filter is "on"
And the "multilang" filter applies to "content and headings"
And I am on the "Course 1" course page logged in as admin
And I follow "Course calendar"
And I press "New event"
And I set the following fields to these values:
| Event title | Group 1 event |
| Type of event | Group |
And I should see "Group 1"
And I should not see "GroupGrupo 1"
And I press "Save"
And I am on "Course 1" course homepage
And I follow "Course calendar"
And I click on "Group 1 event" "link"
And I should see "Group event"
And I should see "Group 1"
And I should not see "GroupGrupo 1"
When I click on "Edit" "button" in the "Group 1 event" "dialogue"
And I set the following fields to these values:
| Event title | My own user event |
@@ -369,7 +376,9 @@ Feature: Perform basic calendar functionality
@javascript
Scenario: Changing the event type from user to anything else should work
Given I log in as "teacher1"
Given the "multilang" filter is "on"
And the "multilang" filter applies to "content and headings"
And I log in as "teacher1"
# We need this so we can see the groups.
And the following "course enrolments" exist:
| user | course | role |

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