Compare commits

..

391 Commits

Author SHA1 Message Date
Jun Pataleta f810374a0e Moodle release 4.3.2 2023-12-22 10:00:26 +08:00
Sara Arjona 6c73be6e8e weekly release 4.3.1+ 2023-12-21 13:34:17 +01:00
Huong Nguyen 5a7599385f Merge branch 'MDL-80151-403' of https://github.com/lameze/moodle into MOODLE_403_STABLE 2023-12-20 15:39:54 +07:00
Huong Nguyen eae457d10d MDL-80151 behat: Improve viewing site calendar step 2023-12-20 16:32:38 +08:00
Angelia Dela Cruz 56eb910aed MDL-80151 mod_chat: Behat for chat repeat times and past session view 2023-12-20 16:32:38 +08:00
Simey Lameze 11dcef291d MDL-80151 behat: add calendar step to navigate to specific view 2023-12-20 16:32:38 +08:00
Jun Pataleta 42cbafd610 Merge branch 'MDL-68124-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-12-20 15:01:05 +08:00
Jun Pataleta fb1752711e Merge branch 'MDL-80393-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-19 17:25:10 +08:00
Paul Holden 99eb359503 MDL-80393 lang: expose current page language to JS modules.
Since 4be39296 the root HTML element contains the iso6391 language
code of the current language pack. However various JS modules need
access to the original Moodle language pack code, so expose that
in the `M.cfg` structure.
2023-12-19 07:47:22 +00:00
Sara Arjona 6f344ff877 MDL-68124 lesson: Fix random behat error with Oracle
This random error was caused because when reviewing an attempt,
the first pageid to display is calculated based on the timeseen
field in the lesson_attempst table.
In Oracle, sometimes it returned the second pageid (because both
had the same timeseen), so which led to these random failures.

Apart from adding 1-second wait when the attempt is created (to
guarantee the first page is returned properly), a few more
improvements have been also made, like removing manual steps for
setting the lesson activity or adding some extra checks to
confirm the information displayed is expected.
2023-12-18 09:48:48 +01:00
Huong Nguyen 68c20d41fe Merge branch 'MDL-80410-403' of https://github.com/lucaboesch/moodle into MOODLE_403_STABLE 2023-12-18 14:09:47 +07:00
Luca Bösch 4272fc3f28 MDL-80410 resource: File icon without 'nofilter' 2023-12-15 07:01:47 +01:00
Huong Nguyen 1bd5dfe090 weekly release 4.3.1+ 2023-12-15 08:44:19 +07:00
Huong Nguyen f8d0e86350 Merge branch 'install_403_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_403_STABLE 2023-12-15 08:44:13 +07:00
Huong Nguyen e092c75d15 Merge branch 'MDL-79828-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-12-14 10:14:43 +07:00
Huong Nguyen 90b3f5fc26 Merge branch 'MDL-79050-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-12-14 09:56:47 +07:00
Huong Nguyen c77bef3ad7 Merge branch 'MDL-80394-403' of https://github.com/ilyatregubov/moodle into MOODLE_403_STABLE 2023-12-14 09:22:42 +07:00
Ilya Tregubov 260eef0a72 Merge branch 'MDL-79938-m403' of https://github.com/sammarshallou/moodle into MOODLE_403_STABLE 2023-12-14 08:50:54 +08:00
AMOS bot af0fe95d84 Automatically generated installer lang files 2023-12-14 00:11:12 +00:00
Sara Arjona ee0c928f10 Merge branch 'MDL-80233-403' of https://github.com/aanabit/moodle into MOODLE_403_STABLE 2023-12-13 10:22:10 +01:00
Angelia Dela Cruz d1796d1f0e MDL-79050 Behat: Add behat coverage to retake lesson activity 2023-12-13 16:25:13 +08:00
Huong Nguyen ac2acd0072 Merge branch 'MDL-74466-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-13 09:28:57 +07:00
Ilya Tregubov 155abc6945 MDL-80394 core_grades: Revert changes to graded_users_iterator
Third party plugins are using it and change was breaking it
2023-12-13 09:38:14 +08:00
Ilya Tregubov cf0b182dee Merge branch 'MDL-80003_403' of https://github.com/PhilippImhof/moodle into MOODLE_403_STABLE 2023-12-13 09:22:16 +08:00
Sara Arjona f863084cc9 Merge branch 'MDL-77572_403' of https://github.com/santoshndev/moodle into MOODLE_403_STABLE 2023-12-12 17:55:57 +01:00
sam marshall 2ddad8ce7a MDL-79938 Behat: Add steps to support multiple tabs 2023-12-12 16:43:08 +00:00
Santosh Nagargoje 8d45a9f2a2 MDL-77572 Course: Added fix for section,activity visibility capabilities
added fix
2023-12-12 21:38:45 +05:30
Amaia Anabitarte 4b0a34f08a MDL-80233 completion: Use default for empty values 2023-12-12 16:34:11 +01:00
Sara Arjona 3a7f291d38 Merge branch 'MDL-80315-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-12-12 14:19:52 +01:00
Sara Arjona bbfc6312a8 Merge branch 'MDL-79835_403' of https://github.com/timhunt/moodle into MOODLE_403_STABLE 2023-12-12 14:11:41 +01:00
Huong Nguyen fe8d759b17 Moodle release 4.3.1 2023-12-08 09:21:43 +07:00
Philipp Imhof 983921ecff MDL-80003 mod_quiz: watch all instances of tinyMCE 2023-12-07 17:29:58 +01:00
Sara Arjona f72244a8c2 weekly release 4.3+ 2023-12-07 16:22:04 +01:00
Paul Holden d09f737c7d MDL-79980 mod_survey: remove responses link if user cannot access.
Update Behat scenario to match.
2023-12-07 12:08:47 +01:00
Brendan Heywood b654282b18 MDL-80309 tasks: Clean up mtrace logs 2023-12-07 12:08:05 +08:00
Andrew Nicols bdb5a4ba40 Merge branch 'MDL-80257-403' of https://github.com/meirzamoodle/moodle into MOODLE_403_STABLE 2023-12-07 11:43:05 +08:00
Huong Nguyen 419d7f40c3 Merge branch 'MDL-80341_403' of https://github.com/timhunt/moodle into MOODLE_403_STABLE 2023-12-07 10:27:58 +07:00
Paul Holden 7be05aae41 MDL-79839 tool_task: clean task classname parameter prior to use. 2023-12-07 10:54:01 +08:00
Huong Nguyen 04261e8722 Merge branch 'MDL-79061-403-2' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-12-07 09:52:28 +07:00
Jun Pataleta a53121b74a MDL-79061 course: Create a sr-only mutations logger
* Create SRLogger that extends from the default Logger class. This
logger outputs the feedback to a sr-only ARIA live region to allow
screen readers to announce the feedback from mutations.
* Update the course editor to use the SRLogger.
2023-12-07 10:43:13 +08:00
Ferran Recio 6814c42260 MDL-79061 core: Mechanism for logging mutation feedbacks
* Create a mechanism for logging mutation feedbacks.
* The mutation feedbacks are displayed as a toast by default.
* Apply this logging mechanism on the course homepage to provide
feedback for the results of actions performed on course modules and
course sections.
2023-12-07 10:43:13 +08:00
Huong Nguyen 658953e34f Merge branch 'MDL-68652-403-1' of https://github.com/ilyatregubov/moodle into MOODLE_403_STABLE 2023-12-07 09:31:46 +07:00
Jun Pataleta c2c03f203f Merge branch 'MDL-80281_403_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_403_STABLE 2023-12-07 10:16:52 +08:00
Huong Nguyen 9a1a58e593 Merge branch 'MDL-77136-403' of https://github.com/lucaboesch/moodle into MOODLE_403_STABLE 2023-12-07 08:36:35 +07:00
Paul Holden 0f63155d58 MDL-79980 mod_survey: respect activity group mode getting report. 2023-12-07 09:32:11 +08:00
Ilya Tregubov 25e00b5e1f MDL-68652 core_grades: Only return allowed fields.
Grade iterator should check user permissions.
2023-12-07 09:12:39 +08:00
Ilya Tregubov b2bc3b9e7e Merge branch 'MOODLE_403_MDL-73378' of https://github.com/danielneis/moodle into MOODLE_403_STABLE 2023-12-07 09:01:58 +08:00
Jun Pataleta 38ed732727 Merge branch 'MDL-79761-403' of https://github.com/marinaglancy/moodle into MOODLE_403_STABLE 2023-12-07 08:54:00 +08:00
Paul Holden 463f16617e MDL-80239 grade: escape matched data in user search results. 2023-12-07 08:42:38 +08:00
Paul Holden 260924aeb8 MDL-80287 grade: escape current value in search templates. 2023-12-07 08:36:32 +08:00
Tim Hunt d7a1ef5dfa MDL-79835 behat_core_generator: remove misleading error obfuscation 2023-12-06 18:12:20 +00:00
Jun Pataleta b38413afe4 Merge branch 'MDL-80127_403' of https://github.com/timhunt/moodle into MOODLE_403_STABLE 2023-12-06 22:12:17 +08:00
Jun Pataleta 05ab53734b Merge branch 'MDL-80079-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-12-06 21:59:11 +08:00
Luca Bösch 708732ed72 MDL-77136 qtype_randomsamatch: Newest versions for shortanswer questions 2023-12-06 14:14:14 +01:00
Luca Bösch 121d6fb20a MDL-77136 core_question: Newest versions get_questions_from_categories 2023-12-06 14:14:14 +01:00
Tim Hunt e4acb387bb MDL-80127 question engine: prevent fatal errors from old bad data 2023-12-06 11:38:58 +00:00
Tim Hunt ff74bb2682 MDL-80127 question engine: don't convert null to '' before storing 2023-12-06 11:38:58 +00:00
Tim Hunt 17fb4afaab MDL-80341 quiz: unseen descriptions are not unanswered questonis
This was causing confusing in the 'are you sure you want to submit' confirmation pop-up.
2023-12-06 11:13:27 +00:00
Angelia Dela Cruz 0cb2fd1a7f MDL-80315 block_comments: Removed duplicate Behat test
Deleted the duplicated course comments block behat test. The file
blocks/comments/tests/behat/add_comment.feature is deleted as a
result.
2023-12-06 18:18:53 +08:00
Ilya Tregubov 60541d90e5 Merge branch 'MDL-76109-403' of https://github.com/meirzamoodle/moodle into MOODLE_403_STABLE 2023-12-06 15:42:55 +08:00
Huong Nguyen 4b26df011f Merge branch 'MDL-50650-403' of https://github.com/ilyatregubov/moodle into MOODLE_403_STABLE 2023-12-06 14:06:13 +07:00
Stephan Robotta fbecc7132d MDL-41465 reports: In separate group mode, limit to same 2023-12-06 13:52:58 +07:00
Ilya Tregubov bbea6e1d31 MDL-68652 mod_forum: Only include gradable users in grading 2023-12-06 12:45:09 +08:00
David Woloszyn 9e3ca2a866 MDL-79759 repository_url: Limit css imports and remove fragments
There are checks to urls that attempt to limit recurrsion when
parse_file is called. This is problematic for css import urls that
can call an indefinite amount of nested import urls. An import limit
has been introduced to address this. Fragments have also been removed.
2023-12-06 03:54:20 +01:00
Stevani Andolo 40ee4ab3fa MDL-80174 tool_log: ensure "other" data is safely unserialized. 2023-12-06 03:54:20 +01:00
Paul Holden d40fc8708a MDL-80268 badges: require capability to view awarded badges. 2023-12-06 03:54:20 +01:00
Paul Holden 2a60bc604f MDL-79797 backup: ensure block config is safely unserialized. 2023-12-06 03:54:20 +01:00
Ilya Tregubov e8237560d3 Merge branch 'MDL-79692-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-06 10:50:13 +08:00
Huong Nguyen 258783a754 Merge branch 'MDL-80180-403' of https://github.com/jbs1/moodle into MOODLE_403_STABLE 2023-12-06 09:16:28 +07:00
Ilya Tregubov 81de0469c1 Merge branch 'MDL-74248-MOODLE_403_STABLE-fix_mp3_mod_folder' of https://github.com/praxisdigital/moodle into MOODLE_403_STABLE 2023-12-06 10:01:00 +08:00
Sara Arjona 638cbfac93 Merge branch 'MDL-80286-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-05 16:42:14 +01:00
Sara Arjona 85c70539df Merge branch 'MDL-79862-403' of https://github.com/aanabit/moodle into MOODLE_403_STABLE 2023-12-05 16:35:25 +01:00
Sara Arjona 5b442418ad Merge branch 'MDL-79979-403' of https://github.com/aanabit/moodle into MOODLE_403_STABLE 2023-12-05 16:16:47 +01:00
Jun Pataleta 9c641bf38e Merge branch 'MDL-73974-403' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-12-05 23:09:37 +08:00
Karen Holland f9797aca63 MDL-73974 tool_brickfield: Processing alpha fontsizes 2023-12-05 23:07:57 +08:00
Sara Arjona d4b1ecbed4 Merge branch 'MDL-55640-m403' of https://github.com/sammarshallou/moodle into MOODLE_403_STABLE 2023-12-05 16:01:54 +01:00
Sara Arjona d140771110 Merge branch 'MDL-80015-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-12-05 15:51:28 +01:00
Sara Arjona 762df4050c Merge branch 'MDL-80254-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-05 15:45:38 +01:00
Jun Pataleta bee2d552b7 Merge branch 'MDL-79806_403_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_403_STABLE 2023-12-05 12:48:31 +08:00
Huong Nguyen f172248f20 Merge branch 'MDL-71336-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-05 11:19:41 +07:00
Jun Pataleta db71e79e05 Merge branch 'm43-mdl64431' of https://github.com/danmarsden/moodle into MOODLE_403_STABLE 2023-12-05 12:13:40 +08:00
Huong Nguyen 05c9ce4bd8 Merge branch 'MOODLE_403_STABLE' of https://github.com/dragos5436/moodle into MOODLE_403_STABLE 2023-12-05 10:40:29 +07:00
Ilya Tregubov ade9f7177a MDL-68652 core_grades: Refactor grades functions.
get_gradable_users now has extra param to retrieve only active
users. Grade reports hase their own grade_report::get_gradable_users
since they decided whether to inlcude active users from report preferences
2023-12-05 10:52:12 +08:00
Ilya Tregubov 05846ae405 MDL-68652 core_grades: Add a webservice to retrive only gradable users. 2023-12-05 10:52:12 +08:00
Ilya Tregubov e186ad572d Merge branch 'MDL-80043-403' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-12-05 09:11:08 +08:00
Ilya Tregubov 9f636a3de3 Merge branch 'MDL-80131-403' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-12-05 09:00:43 +08:00
Marina Glancy d79ad5de6a MDL-79761 navigation: fix default setting during web installation 2023-12-04 13:06:06 +00:00
Sara Arjona b7c8f7f723 Merge branch 'MDL-80185-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-12-04 11:00:44 +01:00
Paul Holden 46192ca77e MDL-80254 reportbuilder: better handling of deleted users in schedules.
We should verify that schedule and audience users are active accounts,
and that we don't try to send report schedules either from/to them if
they aren't.
2023-12-04 09:48:42 +00:00
meirzamoodle d68ea95f26 MDL-80257 editory_tiny: Implement ui_mode: split
Since version 6.4 and later, TinyMCE had a feature `ui_mode: split`.

It enables support for editors in scrollable containers,
and Moodle has some pages, especially the course pages, that are using the scrollable containers.
Therefore, all workaround that is addressed should be replaced by the feature to avoid future problems
regarding the overflow and the z-index issues.
2023-12-04 16:28:44 +07:00
meirzamoodle 85af2e6a7c MDL-80257 editory_tiny: Remove tox-tinymce-aux z-index
Remove .tox-tinymce-aux from style.css because z-index is already defined in TinyMCE skin.css
2023-12-04 16:28:44 +07:00
Paul Holden 4ac4b93064 MDL-74466 repository: avoid passing around sesskey when not required. 2023-12-04 09:22:32 +00:00
Jun Pataleta 136aef1fe6 Merge branch 'MDL-80221-403-enfix' of https://github.com/mudrd8mz/moodle into MOODLE_403_STABLE 2023-12-04 16:11:30 +08:00
Ilya Tregubov 79ea6a2d22 MDL-50650 core_grades: Validate minimum grade when importing grades
Also add behat test for max and min grade validation.
2023-12-04 16:03:21 +08:00
Kyle Matter e2f5104676 MDL-50650 core_grades: allow grade imports larger than 100 points 2023-12-04 12:53:21 +08:00
Jun Pataleta bc133f6fc3 Merge branch 'MDL-79726-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-12-04 12:09:17 +08:00
Huong Nguyen bea6119692 Merge branch 'MDL-79784-403' of https://github.com/jleyva/moodle into MOODLE_403_STABLE 2023-12-04 09:25:35 +07:00
Jun Pataleta b04fcb4527 MDL-80131 mod_data: Make page titles unique 2023-12-02 07:20:35 +08:00
dragos5436 b4278ca6b0 MDL-60632 mod_quiz: Fix chart rendering fail in quiz report
If a quiz activity has negative grading enabled for incorrect answers,
students can achieve overall negative grades in this quiz. If at least
one student achieves a negative grade, the chart at the bottom of the
quiz 'Results' tab will fail to display. This patch add a search for
negative results, removes them from the band below 0 and adds them to
the 0 band. This will make the chart render correctly again.

Co-authored-by: Susana Leitão <sleitao@uporto.pt>
Co-authored-by: Matthias Opitz <m.opitz@ucl.ac.uk>

Removed whitespace at end of lines
2023-12-01 15:28:24 +00:00
Sara Arjona d20c47f89c Merge branch 'MDL-80209-403' of https://github.com/aanabit/moodle into MOODLE_403_STABLE 2023-12-01 10:56:09 +01:00
Sara Arjona d29433ddc6 MDL-79726 completion: Overall should consider pass/fail states too
In MDL-78744, when the overallcompletion state was added to be displayed
in the activity card, only COMPLETE/INCOMPLETE status were considered.
However, depending on the activity completion settings, there are a
couple of states more that should also be included (COMPLETE_FAIL and
COMPLETE_PASS).

A new method has been added to the cm_completion_details class to
calculate whether a module should be considered or not completed,
based on their completion options and the current value for the
overall complete state.
2023-12-01 09:19:11 +01:00
David Mudrák 0a494aa9f6 MDL-80221 lang: Use fixed strings in the tests, too 2023-12-01 06:28:07 +01:00
Ilya Tregubov a418e9e53a weekly release 4.3+ 2023-12-01 13:12:23 +08:00
Jun Pataleta 3f10ec31b5 MDL-80043 grade: Add upgrade.txt notes 2023-12-01 09:10:53 +08:00
Jun Pataleta 488a653e50 MDL-80043 gradereport_grader: Define editingmode_title lang string 2023-12-01 09:10:53 +08:00
Jun Pataleta 7fa08a0b35 MDL-80043 grade: editingmode_title support for grade report plugins
* Add support for grade report plugins that define an
`editingmode_title` lang string. If the grade report plugin defines this
 language string, it will be used for the page title's unique
 identifying information when editing mode is turned on.
2023-12-01 09:10:53 +08:00
Jun Pataleta 6a89731462 MDL-80043 gradereport_singleview: Improve heading wordings
* Make the headings for the single view easier to read and understand
* When on editing mode, update the heading for the grade and user
screens to convey to the user that the page is currently on editing
mode. This is helpful for screen reader users as they can immediately
know the current display mode of the single view report page when this
gets read via the page title.
2023-12-01 09:10:53 +08:00
Jun Pataleta fd8b7fc730 MDL-80043 grade: Use heading parameter for the page title if provided 2023-12-01 09:10:52 +08:00
sam marshall 006eaeef08 MDL-55640 setuplib: test_localcachedir fails sporadically 2023-11-30 13:57:48 +00:00
Paul Holden 2862cce2a9 MDL-80286 datafield_date: cast field content to real when sorting.
This ensures we don't under/overflow the size of an integer in DB.
2023-11-30 10:05:01 +00:00
Amaia Anabitarte e3d76202cd MDL-80209 mod_scorm: Save minimum score completion 2023-11-30 10:40:17 +01:00
Mark Johnson 6441cca4d1 MDL-79806 quiz_statistics: Queue recalculation on attempt_deleted 2023-11-30 08:53:16 +00:00
Juan Leyva 04892e4707 MDL-79784 tool_mobile: Add missing external::format_text 2023-11-30 09:47:46 +01:00
Huong Nguyen 17282deeea Merge branch 'MDL-79816-403' of https://github.com/rmady/moodle into MOODLE_403_STABLE 2023-11-30 10:40:37 +07:00
Meirza c2e8975523 MDL-76109 core: Don't check password policy for guest user
Besides adding the is_guest() check in the check_password_policy() condition,
I also changed the temporary user ID because the temporary user and
the guest must not share the same ID. Otherwise, it will raise an error.

Co-authored-by: Andrei Bautu <abautu@gmail.com>
2023-11-30 10:35:38 +07:00
Huong Nguyen c5e3ce289e Merge branch 'MDL-74378_403' of https://github.com/PhilippImhof/moodle into MOODLE_403_STABLE 2023-11-30 10:11:45 +07:00
Ilya Tregubov 83e442cc69 Merge branch 'MDL-79890-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-11-30 10:45:01 +08:00
Ilya Tregubov b8f0f87b5f Merge branch 'MDL-78849-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-30 10:38:09 +08:00
Ilya Tregubov 539e5db429 Merge branch 'MDL-79325-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-30 09:34:46 +08:00
Sara Arjona 4c3523d987 Merge branch 'MDL-80205-403' of https://github.com/aanabit/moodle into MOODLE_403_STABLE 2023-11-29 18:42:09 +01:00
Jun Pataleta a0951e25b3 Merge branch 'MDL-79841-403' of https://github.com/laurentdavid/moodle into MOODLE_403_STABLE 2023-11-29 23:48:44 +08:00
Sara Arjona 70a95b8eae Merge branch 'MDL-79610-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-11-29 16:37:08 +01:00
Sara Arjona 5705496179 Merge branch 'MDL-80150-403' of https://github.com/lucaboesch/moodle into MOODLE_403_STABLE 2023-11-29 13:34:40 +01:00
Mikel Martín e77912a7c5 MDL-79610 courseformat: Fix availability restrictions rendering
When duplicating a course module, availability restrictions was not rendering
properly. That happened because 'editing' was not being exported for template
for a single course module. This patch adds 'editing' to the cm exported data.
2023-11-29 13:11:05 +01:00
Paul Holden fb13f6dd01 Merge branch 'MDL-79967-403-fix' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-11-29 12:03:05 +00:00
Jun Pataleta fbeef47a58 MDL-79967 mod_scorm: Use only the required field for the query 2023-11-29 18:32:07 +08:00
Sara Arjona 8fa5a3008d MDL-80150 resource: Reintroduce file icon
The new activity card design, planned for Moodle 4.3, reintroduces
the resource MIME icon that was removed in Moodle 4.0.
This is a backport of MDL-78285.
2023-11-29 09:58:14 +01:00
Jun Pataleta 2c94380acf Merge branch 'MDL-79148-403' of https://github.com/ssj365/moodle into MOODLE_403_STABLE 2023-11-29 15:20:32 +08:00
Jun Pataleta 8cd66034e4 Merge branch 'm43-mdl79967' of https://github.com/danmarsden/moodle into MOODLE_403_STABLE 2023-11-29 12:25:05 +08:00
Huong Nguyen 0bb3a2f20a Merge branch 'v_4_3_0' of https://github.com/dominicchinkh/moodle into MOODLE_403_STABLE 2023-11-29 10:33:21 +07:00
Huong Nguyen 96f06326f8 Merge branch 'm43-mdl80004' of https://github.com/danmarsden/moodle into MOODLE_403_STABLE 2023-11-29 09:52:51 +07:00
Huong Nguyen 8b6d43705e Merge branch 'MDL-80002-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-11-29 09:36:06 +07:00
Huong Nguyen eb0575859b Merge branch 'MDL-79267-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-29 09:17:38 +07:00
Huong Nguyen a6ce3c0758 Merge branch 'MDL-79512-403' of https://github.com/laurentdavid/moodle into MOODLE_403_STABLE 2023-11-29 09:08:38 +07:00
Huong Nguyen a9bfc2075b Merge branch 'MDL-76694-403' of https://github.com/snake/moodle into MOODLE_403_STABLE 2023-11-29 09:01:12 +07:00
Jun Pataleta 6a1644abff Merge branch 'MDL-80181-403' of https://github.com/srobotta/moodle into MOODLE_403_STABLE 2023-11-29 09:37:46 +08:00
Jeremy Schulz 1bbc0425e3 MDL-80180 admin: added readonly support for multicheckbox 2023-11-28 14:34:37 -05:00
Mark Johnson cb18237b5c MDL-80281 session: Don't report long session locks for readonly sessions
Previously, $CFG->sessionlockdebug was reporting long session locks for
all requests, even if they defined READ_ONLY_SESSION. This change
ensures that only sessions with locks are reported.
2023-11-28 16:21:17 +00:00
Shamiso.Jaravaza c898074fd8 MDL-79148 mod_bigbluebuttonbn: fix recording link 2023-11-27 23:54:56 -07:00
Ilya Tregubov 14b5d0694f Merge branch 'MDL-79603-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-11-28 13:53:20 +08:00
Laurent David 54d0894ec3 MDL-79841 theme_boost: Do not remove card borders
* When we are in small screensize we had removed the
left and right borders for cards. This is now restored
2023-11-28 06:37:37 +01:00
Jun Pataleta 0b326e9e72 Merge branch 'MDL-80210_403' of https://github.com/timhunt/moodle into MOODLE_403_STABLE 2023-11-28 10:35:14 +08:00
Amaia Anabitarte eae154a081 MDL-80205 mod_scorm: Remove all Pass grade options from completion 2023-11-27 18:04:30 +01:00
Helen Foster 42022a1d26 MDL-80221 lang: Import fixed English strings (en_fix) 2023-11-24 18:30:16 +01:00
Stephan Robotta c59c0f906b MDL-80181 wiki: fix width of left column in comments 2023-11-24 11:18:07 +01:00
Philipp Imhof e82f1d43c8 MDL-74378 mod_quiz: make sure timer is initialized 2023-11-24 08:52:05 +01:00
Huong Nguyen 6ff6327a6b weekly release 4.3+ 2023-11-24 12:23:15 +07:00
Huong Nguyen 4b34028221 Merge branch 'install_403_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_403_STABLE 2023-11-24 12:23:12 +07:00
Eloy Lafuente (stronk7) edbbe29706 Merge branch 'MDL-79966-m403' of https://github.com/sammarshallou/moodle into MOODLE_403_STABLE 2023-11-23 23:40:50 +01:00
sam marshall fc35bc5876 MDL-79966 core_task: NEVER_RUN_TIME did not fit in 10 digits 2023-11-23 16:23:39 +00:00
Rodrigo Mady 6c5f358ca2 MDL-79816 block_recentlyaccesseditems: Fix modname type in WS 2023-11-23 11:57:22 -03:00
Paul Holden 895189107f MDL-71336 forms: ensure grouped date elements have unique IDs.
Previously they were each taking the ID of their parent group element.
2023-11-23 12:01:28 +00:00
Tim Hunt d8c4a57ce8 MDL-80210 quiz: fix default for reviewmaxmarks when upgrading
It is correct that the database default should be 0, to match
other similar columns, but when sites are upgraded, we need
to set the settings for all existing quizzes to match the previous
behaviour.
2023-11-23 11:03:46 +00:00
Andrew Nicols 3d5c60ad26 Merge branch 'MDL-79966-m403' of https://github.com/sammarshallou/moodle into MOODLE_403_STABLE 2023-11-23 10:30:40 +08:00
Huong Nguyen a2cfa93011 Merge branch 'MDL-78496-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-11-23 09:23:00 +07:00
Ilya Tregubov e40f4e4d83 Merge branch 'MDL-80157_storedfileproblem-403' of https://github.com/leonstr/moodle into MOODLE_403_STABLE 2023-11-23 09:47:03 +08:00
Ilya Tregubov 1f0f185176 Merge branch 'MDL-79185-MOODLE_403_STABLE' of https://github.com/dmitriim/moodle into MOODLE_403_STABLE 2023-11-22 11:48:09 +08:00
Dmitrii Metelkin d5d2c59161 MDL-79185 cache: don't throw exception if cache data is corrupted 2023-11-22 12:49:18 +11:00
Ilya Tregubov c2c357dfb2 Merge branch 'MDL-78670-403' of https://github.com/rmady/moodle into MOODLE_403_STABLE 2023-11-22 09:10:54 +08:00
Paul Holden fccf80c3a3 MDL-80185 lang: use iso6391 language code for HTML lang attributes.
This resolves accessibility issues where Moodle language pack codes
didn't always map to correspondingly named iso6391 codes.

Where this value is defined in the language configuration, it will
now be used.
2023-11-21 22:55:21 +00:00
Mikel Martín ee26c16e90 MDL-80015 course: Fix category 'More' dropdown alignment
Co-authored-by: Stephen Sharpe <stephen.sharpe@synergy-learning.com>
2023-11-21 14:15:39 +01:00
Angelia Dela Cruz 26c5ffd356 MDL-79828 core_badges: Delete already awarded course badges 2023-11-21 16:30:12 +08:00
Amaia Anabitarte d38211efc6 MDL-79979 tool_generator: Use auto-enrol admin in new courses setting 2023-11-21 08:41:57 +01:00
sam marshall dd844035ac MDL-79966 core_task: Scheduled task timing (crontab fields) is wrong 2023-11-20 17:12:27 +00:00
Amaia Anabitarte 778b8f51b1 MDL-79979 tool_generator: Use auto-enrol admin in new courses setting 2023-11-20 17:13:59 +01:00
Juan Olivares 4d28563eeb MDL-74248 mod_folder: Fix mp3 files being unaccessible in chrome
Platform users that host mp3 files within a folder are not able to access them using Chrome. This fix allows them to do so.
2023-11-20 11:30:28 +01:00
Dan Marsden 89f3fced22 MDL-79967 scorm: Fix scorm_insert_track grading calls. 2023-11-20 22:03:10 +13:00
Amaia Anabitarte 1ed0cb2562 MDL-79862 completion: Improve error handling for default completion 2023-11-20 09:52:22 +01:00
Huong Nguyen 7e1589b2ee Merge branch 'MDL-80037-403' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-11-20 14:48:38 +07:00
Huong Nguyen bc5d145dfb Merge branch 'MDL-79783-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-20 14:05:10 +07:00
Huong Nguyen 5aaba2850f Merge branch 'MDL-79604-403' of https://github.com/srobotta/moodle into MOODLE_403_STABLE 2023-11-20 14:01:22 +07:00
Laurent David 3116b46192 MDL-79512 mod_feedback: Add toast dialog when saved
* Add notification to notify the user once the changes have been
successfully saved
2023-11-20 06:55:14 +01:00
Laurent David 3a1aed3578 MDL-79512 mod_feedback: Fix issue with drag and drop
* A teacher can not change the order of the questions in feedback
as the order is not saved.
2023-11-20 06:55:14 +01:00
AMOS bot a2544fd5ca Automatically generated installer lang files 2023-11-20 00:10:44 +00:00
Rodrigo Mady ebab82c9f3 MDL-78670 mod_quiz: Add offline atempt rule for sequential navigation 2023-11-17 20:30:50 -03:00
Mark Johnson 40e56b3adc MDL-79806 mod_quiz: Implement new quiz_attempt_deleted callback 2023-11-17 16:06:58 +00:00
Leon Stringer 0a360e1eb2 MDL-80157 file: Exception message spelling 2023-11-17 14:35:38 +00:00
Paul Holden 59aa25852c MDL-79325 group: consistent name formatting in overview page/export. 2023-11-17 09:48:06 +00:00
Jun Pataleta ba60319c94 MDL-80037 theme: Indicate when $CFG->theme is defined in config.php
* And prevent selection of theme if $CFG->theme is defined in config.php
2023-11-17 09:24:32 +08:00
Dominic Chin ad836b6d4c MDL-80035 theme_boost: Fix fourth argument of single_button constructor 2023-11-17 09:17:27 +11:00
Sara Arjona 72d7395c96 weekly release 4.3+ 2023-11-16 16:22:34 +01:00
Sara Arjona d376741b93 Merge branch 'install_403_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_403_STABLE 2023-11-16 16:22:30 +01:00
Paul Holden ca991dbe29 MDL-78849 user: correct logical operator behaviour for guest button.
Apart from being banned per MDL-74990, it causes a subtle bug here
due to operator precedence.

Co-authored-by: Tom Mayfield <tmayfield@costrack.com>
2023-11-16 11:31:49 +00:00
Huong Nguyen 3a7594c71a Merge branch 'MDL-76457-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-11-16 10:58:12 +07:00
Huong Nguyen 9f88fb2125 Merge branch 'MDL-80066-403' of https://github.com/elza3ym/moodle into MOODLE_403_STABLE 2023-11-16 10:53:03 +07:00
Ilya Tregubov f29c4e36a4 Merge branch 'MDL-80121-403' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-11-16 10:01:03 +08:00
Ilya Tregubov a87db5a60d Merge branch 'MDL-75616-403' of https://github.com/davewoloszyn/moodle into MOODLE_403_STABLE 2023-11-16 09:23:06 +08:00
Mohamed Shehata 07bbe2fa5e MDL-80066 form: fix date picker on small screens 2023-11-15 23:44:09 +02:00
Sara Arjona 1c11297195 Merge branch 'MDL-79981-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-11-15 17:10:10 +01:00
Sara Arjona 5f59e2a61e Merge branch 'MDL-79962-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-15 16:47:39 +01:00
Sara Arjona 7e4119de7e Merge branch 'MDL-79697-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-11-15 16:15:49 +01:00
Andrew Nicols c30c1ca9cd MDL-79697 core: PSR-4 NS can be spread across multiple dirs
The PSR-4 specification does not preclude a single namespaces from
having multiple sources. This is the case for several PSR standards
including standard packagist packages distributed by PSR:

- PSR-7 - HTTP Message Interfaces: \Psr\Http\Message
- PSR-17 - HTTP Factories: \Psr\Http\Message
- PSR-15 - http-server-handler: \Psr\Http\Server
- PSR-15 - http-server-middleware: \Psr\Http\Server
2023-11-15 21:24:52 +08:00
Sara Arjona f50c83ac37 Merge branch 'MDL-80045-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-11-15 13:47:10 +01:00
Sara Arjona c54b573bd0 Merge branch 'MDL-79956-403' of https://github.com/ssj365/moodle into MOODLE_403_STABLE 2023-11-15 13:31:44 +01:00
Jun Pataleta 1f5e140ae9 MDL-80121 gradereport_singleview: Increase zero-state heading level
With the h2 heading not being rendered on the zero-state pages of the
Single view report, we need to increase the heading level of the
"Search for a user to view all their grades" and
"Select a grade item above" headings from h3 to h2.
2023-11-15 19:24:04 +08:00
Jun Pataleta f65d067dec MDL-80121 grade: Trim heading
In order to prevent rendering an empty heading <h2>, we need to make
sure that the $heading parameter passed to print_grade_page_head() is
not an empty string.
2023-11-15 19:24:04 +08:00
Stephan Robotta dbe914883c MDL-79604 mod_data: exception if mandatory checkox list is missing 2023-11-15 12:22:49 +01:00
Ilya Tregubov 783dc4cdb2 Merge branch 'MDL-79996-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-15 15:24:26 +08:00
Dan Marsden 26e91219e8 MDL-64431 assignfeedback_editpdf: Flatten PDF files 2023-11-15 19:28:21 +13:00
Huong Nguyen 15526541b3 Merge branch 'MDL-79648-403' of https://github.com/SergioComeron/moodle into MOODLE_403_STABLE 2023-11-15 09:13:35 +07:00
Huong Nguyen c78364eb73 Merge branch 'MDL-79601-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-11-15 09:09:25 +07:00
Angelia Dela Cruz 0c9bc880c1 MDL-79603 mod_scorm: Behat coverage for Scorm package display options 2023-11-15 09:41:38 +08:00
Andrew Nicols 93f282a345 MDL-78496 phpcs: Moodle 4.3.x supports up to php82 only
At this point, and per our PHP policy, Moodle 4.3 is not expected to
support PHP 8.3.
2023-11-15 09:23:31 +08:00
Andrew Nicols 7d4ba18a65 MDL-79890 core: Stop using get_class() without args
PHP 8.3 deprecates the use of `get_class()` without arguments. The
following alternatives should instead be used as appropriate:

- `get_class($this)` - The equivalent for instance methods
- `self::class` - The current class

Note that the behaviour of `get_class()` in a static method was
equivalent to `self::class` and _not_ `static::class`. That is to say
that the previous behaviour did not respect late static binding.
2023-11-15 09:14:08 +08:00
Andrew Nicols e78cbaa6c4 MDL-79890 core: ReflectionProperties::setValue() should take 2 args
Since PHP 8.3 setValue() must be called with null as the first arg if
called statically.
2023-11-15 09:13:08 +08:00
Mikel Martín 9b401dfc29 MDL-76457 tool_usertours: Fix tour popovers in RTL 2023-11-14 21:27:38 +01:00
Mikel Martín 3e179325e9 MDL-76457 theme_boost: Fix bootstrap popovers in RTL
- Fix the arrow placement for bootstrap popovers in RTL mode.
- Remove unneded css parser workaround for popover arrows.
  After MDL-67386 was integrated those changes were not needed anymore.
2023-11-14 21:27:38 +01:00
Sara Arjona 60727a7cdf MDL-77581 lesson: Fix behat random failures 2023-11-14 16:24:43 +01:00
Andrew Nicols 4d59c788ee MDL-78496 environment: Moodle 4.4 requirements
The only changes to requirements since Moodle 4.3 are increases to:

* the minimum PHP version required; and
* the minimum required Moodle version.
2023-11-14 22:47:55 +08:00
Andrew Nicols d5993fffd4 MDL-80079 core: Correct incorrect arg to format_text::$options 2023-11-14 22:28:55 +08:00
Andrew Nicols 136bd2c4c4 MDL-80079 core: Correct incorrect arg to format_string::$options 2023-11-14 22:28:55 +08:00
Mikel Martín b2d8615725 MDL-80045 block_starredcourses: Fix cards alignment in small screens 2023-11-14 14:36:23 +01:00
Sara Arjona 4e880779f9 Merge branch 'MDL-77581-403' of https://github.com/dpalou/moodle into MOODLE_403_STABLE 2023-11-14 11:52:51 +01:00
Dani Palou e5efe8b6d1 MDL-77581 lesson: Fix generator unit tests in oracle 2023-11-14 11:11:25 +01:00
SergioComeron da4a2d6191 MDL-79648 core_course: 29 October repeating day 2023-11-13 18:37:23 +01:00
Sara Arjona 84ec153634 Merge branch 'MDL-77581-403' of https://github.com/dpalou/moodle into MOODLE_403_STABLE 2023-11-13 17:19:41 +01:00
Paul Holden b69c42db5d MDL-79692 enrol_meta: check for group validity when adding members. 2023-11-13 10:23:14 +00:00
Huong Nguyen 55d5f7756d Merge branch 'MDL-74129-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-11-13 10:43:18 +07:00
David Saylor b262a67c89 MDL-75616 backup: Use standard temp directory for extraction 2023-11-13 11:08:17 +11:00
AMOS bot 05492ddbb3 Automatically generated installer lang files 2023-11-12 00:10:15 +00:00
Sara Arjona 185856927d MDL-74129 h5p: Preserve metadata information
The metadata information was not restored when an H5P file was uploaded
(it was saved when it was edited directly from the Content bank, but the
original information in the H5P file was lost).
This patch includes all the metadata fields and its values in the original
H5P file to preserve this information too.
2023-11-10 10:33:47 +01:00
Ilya Tregubov 935c2509f1 weekly release 4.3+ 2023-11-10 09:17:15 +08:00
Paul Holden a502fbcd1e MDL-79962 roles: consistent sorting of role entity name column.
The "name" field is typically omitted for default/pre-defined roles,
which should be accounted for when sorting.
2023-11-09 17:04:03 +00:00
Dani Palou 061186c215 MDL-77581 behat: Test create lesson pages using UI 2023-11-09 11:32:00 +01:00
Dani Palou eac49ffa4c MDL-77581 behat: Apply new lesson cluster generators to existing tests 2023-11-09 11:32:00 +01:00
Dani Palou db82329f6c MDL-77581 behat: Create generators for lesson clusters 2023-11-09 11:32:00 +01:00
Dani Palou 875ad48c9d MDL-77581 lesson: Fix wrong PHPDoc in some generator functions
While creating the new perform_create_page function I noticed that the PHPDoc return type of the existing functions was wrong
2023-11-09 11:01:51 +01:00
Dani Palou c627e1a4de MDL-77581 behat: Remove lesson_student_dashboard test file
After f7c476bac5 was integrated, these tests didn't assert anything specific and similar steps are already tested in lesson_navigation
2023-11-09 11:01:51 +01:00
Dani Palou 3b0165ec67 MDL-77581 behat: Apply new lesson generators to existing tests 2023-11-09 11:01:51 +01:00
Dani Palou 96bfaf67fd MDL-77581 behat: Create generators for lesson pages and answers 2023-11-09 11:01:51 +01:00
Dani Palou fc4354c7e3 MDL-77581 behat: Support finish_generate_ in generators 2023-11-09 11:01:51 +01:00
Shamiso.Jaravaza b5c49b8ac9 MDL-79956 mod_bigbluebuttonbn: fix import links 2023-11-08 21:48:03 -07:00
Michael Aherne 2721a7cdc3 MDL-80030 filelib: Fix info type. 2023-11-09 11:13:52 +08:00
Ilya Tregubov ab79a0e972 Merge branch 'MDL-79992-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-11-09 09:57:09 +08:00
Sara Arjona 275af6c114 Merge branch 'MDL-79827-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-08 18:10:44 +01:00
Sara Arjona dcc8300ef4 Merge branch 'MDL-79975-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-08 18:03:03 +01:00
Sara Arjona af62e9773c Merge branch 'MDL-79781-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-08 17:19:51 +01:00
Sara Arjona 0ac35f9248 Merge branch 'MDL-76555-403' of https://github.com/pmaneggia/moodle into MOODLE_403_STABLE 2023-11-08 17:06:18 +01:00
Mikel Martín a028969791 MDL-79601 report_completion: Fix RTL First/Last name alignment 2023-11-08 16:23:29 +01:00
Mikel Martín 7bc41babf8 MDL-79601 report_progress: Fix RTL First/Last name alignment 2023-11-08 16:23:29 +01:00
Andrew Nicols 4e08cbd42e MDL-79981 core: Add ability to manually run and filter phpunit on GHA 2023-11-08 12:53:43 +08:00
Ilya Tregubov d3427d45fa Merge branch 'MDL-79615_403_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_403_STABLE 2023-11-08 10:43:00 +08:00
Huong Nguyen 67a690d176 Merge branch 'MDL-79739-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-11-08 09:23:50 +07:00
Huong Nguyen 81d72254b5 Merge branch 'MDL-79840-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-08 09:23:09 +07:00
Ilya Tregubov b2e58aed7b Merge branch 'MDL-79858-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-08 09:49:29 +08:00
Paul Holden 5ca36b0731 MDL-79267 mod_forum: define report subplugin type language strings. 2023-11-07 09:49:56 +00:00
Huong Nguyen b105ec5188 Merge branch 'MDL-78953-403' of https://github.com/pedrojordao/moodle into MOODLE_403_STABLE 2023-11-07 15:33:52 +07:00
Jun Pataleta a85f7c200b MDL-80019 mod_bigbluebuttonbn: Use updated completion field names
Field names for the completion conditions have been updated since 4.3.
So the fields names should also be updated in the test.
2023-11-07 13:13:18 +08:00
Jun Pataleta f09f15e0be Merge branch 'MDL-80019-403' of https://github.com/call-learning/moodle into MOODLE_403_STABLE 2023-11-07 13:11:51 +08:00
Laurent David e35be12fb7 MDL-80019 mod_bigbluebuttonbn: Completion form freeze fix
* When the completion is locked, we should not be able to edit the completion elements
2023-11-06 22:11:02 +01:00
Sara Arjona 2f1a67685f Merge branch 'mdl-78650-403-stable' of https://github.com/Fragonite/moodle into MOODLE_403_STABLE 2023-11-06 09:51:00 +01:00
Huong Nguyen d3bc17fe56 Merge branch 'MDL-79062-403-2' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-11-06 10:52:04 +07:00
Dan Marsden adfd93a303 MDL-80004 scorm: add missing require locallib during course reset. 2023-11-06 12:05:12 +13:00
Paola Maneggia 82f9838f28 MDL-76555 mod_resource: Fix PHP8.0 type error (legacy resources) 2023-11-05 13:46:39 +01:00
Mikel Martín a18057fd06 MDL-80002 forumreport_summary: Fix summary report date filtering 2023-11-03 15:47:30 +01:00
Paul Holden dbc285e49e MDL-79996 communication: valid instance checks during user deletion. 2023-11-03 12:55:55 +00:00
Sara Arjona 31b409d920 MDL-79992 backup: Display course backups from activity restore
The Course backup area was not displaying the course backups when
accessing to the Restore page for an activity because the context
was not updated properly for this area.
2023-11-03 12:23:18 +01:00
Jake Dallimore 501c58729f MDL-76694 core_comment: exit the js init if the element cannot be found
In pages which result in the theme_boost/embedded template being used,
blocks may be rendered and the resulting HTML ignored, leaving any JS
they may have added to run without a corresponding DOM element to act
on. This fixes that case for comments, making sure we exit gracefully
during the init if the element can't be found.
2023-11-03 10:13:14 +08:00
pedrojordao 3cc283a25e MDL-78953 autocomplete: Add only one empty option when deselecting item.
Each option that was deselected was prepending an empty option in the select.
2023-11-02 18:47:59 -03:00
Paul Holden 188b5021fb MDL-79975 tool_task: correct class attribute table cell property. 2023-11-02 13:19:50 +00:00
Sara Arjona be7a698223 weekly release 4.3+ 2023-11-02 13:40:53 +01:00
Jun Pataleta 60a1c97289 MDL-79062 grade: Behat test fixes
* Feature: We can use a minimum grade different than zero
  - Use correct minimum input values.
  - Use data generators for faster test execution.
* Scenario: Disable category overriding
  - Use the field name to ensure that the correct field is being tested.
2023-11-02 17:34:29 +08:00
Jun Pataleta 92afaa484f MDL-79062 grades: Sort-by-name menu item accessibility fixes
* <h6> tags cannot be in table cells. Replace them with <div> tags.
* Group the ascending/descending sort menu items to better indicate
where they belong to.
2023-11-02 17:34:28 +08:00
Jun Pataleta 9fdb460330 MDL-79062 gradereport_grader: Set numeric type for grade value inputs
* Set grade inputs for grade items with type set to GRADE_VALUE to
number and add min and max input attributes, where necessary.
2023-11-02 17:34:28 +08:00
Jun Pataleta ccfc156b43 MDL-79062 gradereport_grader: Remove setting of tabindex >= 1
Tab indices that are greater than or equal to 1 break the natural
tab order of the document and may cause problems for keyboard users.
2023-11-02 17:34:27 +08:00
Huong Nguyen 10f10ee269 Merge branch 'MDL-78903-403' of https://github.com/meirzamoodle/moodle into MOODLE_403_STABLE 2023-11-02 10:18:20 +07:00
Huong Nguyen 47bf3467a2 Merge branch 'MDL-79801-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-11-02 10:14:46 +07:00
Huong Nguyen 04d7b13fc4 Merge branch 'MDL-79617_403_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_403_STABLE 2023-11-02 09:05:36 +07:00
Alexander Van der Bellen a3e7f7fd14 MDL-78650 mod_assign: Improve group submission action event handling
Don't return an event action when a group submission has already been submitted
by another student.
2023-11-01 20:38:30 +08:00
Alexander Van der Bellen 745b504426 MDL-78650 mod_assign: Add Behat test 2023-11-01 20:38:24 +08:00
Alexander Van der Bellen 89913c7eeb MDL-78650 mod_assign: Add unit test 2023-11-01 20:38:20 +08:00
Daniel Neis Araujo eb658e33c3 MDL-73378 gradebook: Category grade null when all subgrades are null 2023-10-31 13:58:16 -03:00
Sara Arjona 03e68d81b4 Merge branch 'MDL-79856-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-31 13:26:32 +01:00
Sara Arjona ae80f632bf Merge branch 'MDL-79849-403' of https://github.com/jleyva/moodle into MOODLE_403_STABLE 2023-10-31 13:08:20 +01:00
Jun Pataleta e2079313e2 Merge branch 'MDL-79853-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-10-31 16:46:06 +08:00
Huong Nguyen b4bade5ca9 Merge branch 'MDL-79807_403_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_403_STABLE 2023-10-31 12:49:48 +08:00
Huong Nguyen 10883ef268 Merge branch 'MDL-79460-403' of https://github.com/HuongNV13/moodle into MOODLE_403_STABLE 2023-10-31 12:49:48 +08:00
David Woloszyn 19e1e834a7 MDL-79460 communication_matrix: Re-enabled tests that use new sync route 2023-10-31 09:34:06 +07:00
Meirza f30b0eee9b MDL-78903 tiny_h5p: show repositories if editor filepicker type set 2023-10-31 08:00:28 +07:00
Meirza 0ad939f062 MDL-78903 tiny_media: show repositories if editor filepicker type set 2023-10-31 08:00:27 +07:00
Jun Pataleta e8f534c4f4 Merge branch 'MDL-77274-403' of https://github.com/laurentdavid/moodle into MOODLE_403_STABLE 2023-10-30 17:14:27 +08:00
Jun Pataleta 7e22a9c2c7 Merge branch 'MDL-79800-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-10-30 16:40:12 +08:00
Mikel Martín c542a77f11 MDL-79800 courseformat: Fix activity cards right elements margins
- Fix margins in elements displayed in the right side of activity cards.
Replace right margins with left margins to avoid extra space when editing
mode is off and action menu is not displayed.
- Fix groupmode icon spacing when displayed in small resolutions with edit
mode disabled
2023-10-30 07:52:38 +01:00
Laurent David db52a8bc31 MDL-77274 core_renderer: Respect full name format in letter avatars
* Make sure that we respect the fullnamedisplay and alternativefullnameformat
parameters to decide on the initials for a given user
* Add further tests

Co-authored-by: Tatsunori Uchino <tats.u@live.jp>
2023-10-30 06:16:09 +01:00
Huong Nguyen 4800afbc3e Merge branch 'MDL-79639_403_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_403_STABLE 2023-10-30 11:22:59 +07:00
Jun Pataleta 990b740ec1 Merge branch 'MDL-79194-403' of https://github.com/laurentdavid/moodle into MOODLE_403_STABLE 2023-10-27 23:33:20 +08:00
Mark Johnson b1d436a281 MDL-79615 course: Improve efficency of cache rebuilds
When bulk-updating course module visibility, set_coursemodule_visibily
was triggering a partial cache purge and rebuild for each course module.
This potentially led to 2 cache sets each requiring a lock to be
acquired and released per course module, plus any other cache updates
for other changes to the course in the same request.

This adds a new $rebuildcache paramter to the
set_coursemodule_visibilty, which is true by default to retain the
existing behaviour. If set false, it will skip doing the partial purge
and rebuild for that course module, and it is up to the calling code to
ensure the cache is updated as requried.

To assist with this, there is a new
course_modinfo::purge_course_module_cache_multiple() method, which
allows multiple course modules to be purged from the cache in a single
cache set.
2023-10-27 10:51:29 +01:00
Ilya Tregubov 8bf31f2277 Merge branch 'MDL-79693-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-27 16:45:37 +08:00
Jun Pataleta 97fc41ebcb Merge branch 'MDL-77364-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-10-27 16:34:00 +08:00
Sara Arjona bac3ffbe79 MDL-77364 myoverview: Display course name tooltip
Based on the feedback given by the UX team:
- The text has been increased to display more (50 vs 55).
- A tooltip has been added to display the full course name on hover,
following the accessibility guidelines.
2023-10-27 07:26:24 +02:00
Jun Pataleta dc7dd96189 weekly release 4.3+ 2023-10-27 09:43:04 +08:00
Jun Pataleta 67c567062e NOBUG: Fixed SVG browser compatibility 2023-10-27 09:43:03 +08:00
Jun Pataleta b7ee271c8b Merge branch 'MDL-79768-403-fix' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-10-26 23:05:58 +08:00
Ferran Recio 81cdd8db81 MDL-79194 core_courseformat: optimize section reload
* When reloading a section, we also forced the reloading of
course modules, resulting in doing the same work twice (once for
the section reload and once for the course module reload)
* Debounce the reloading process so prevent unwanted duplicate
reloads
2023-10-26 14:53:07 +02:00
Paul Holden 90d7b45f5f MDL-79858 block_myoverview: correctly export request course button. 2023-10-26 13:40:31 +01:00
Mark Johnson 632d4faeec MDL-79807 quiz_statistics: Clear stats cache when question added/removed 2023-10-26 13:38:31 +01:00
Paul Holden aac3b19bff MDL-79781 course: detect invalid creator role for pending courses. 2023-10-26 13:18:34 +01:00
Paul Holden a65a8fc40a MDL-79856 roles: use role localname when confirming deletion. 2023-10-26 12:00:54 +01:00
Angelia Dela Cruz c0bedfd833 MDL-79768 fix: Fixed random failing Behat due to time difference 2023-10-26 18:05:04 +08:00
Laurent David b72551c475 MDL-79194 core_course: Refresh modules menus with section changes
* Whenever a section is hidden, we need to refresh all contextual (hamburger)
menus of each course modules.
2023-10-26 11:04:40 +02:00
Andrew Nicols 437967f78e MDL-79853 core: Add phpunit options to manual runs 2023-10-26 14:48:51 +08:00
Jun Pataleta e05747e353 Merge branch 'MDL-79768-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-10-26 10:48:18 +08:00
Jun Pataleta 4865c40790 Merge branch 'MDL-42189-403' of https://github.com/davewoloszyn/moodle into MOODLE_403_STABLE 2023-10-26 10:32:13 +08:00
Paul Holden d63fd0365a Merge branch 'MDL-79762-43' of https://github.com/kabalin/moodle into MOODLE_403_STABLE 2023-10-25 23:55:54 +01:00
Juan Leyva f054958593 MDL-79849 tool_mobile: Add search disabled features 2023-10-25 17:32:26 +02:00
Ruslan Kabalin 7ee0ee6206 MDL-79762 core: Add possibility to define modal type for modalform
If `moduleName` param is passed in config object for modalform, it will be
used to instantiate modal class, otherwise 'core/modal_save_cancel' is
used.

Co-authored-by: Marina Glancy <marina@moodle.com>
2023-10-25 15:57:11 +01:00
Paul Holden cf715c550a MDL-79840 contentbank: fix references to invalid icon images. 2023-10-25 08:45:51 +01:00
Jun Pataleta 440a27c5de Merge branch 'MDL-75572-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-10-25 13:44:40 +08:00
Sara Arjona 2130e4ff8b MDL-75572 criteria: Only award badges to sucessfull completions
The UX team confirmed a badge shouldn't be awarded when the criteria
use a passing grade and the user gets a failing grade.
So the COMPLETION_COMPLETE_FAIL status won't be considered
completed for activities with completion that require a passing
grade.
2023-10-25 07:08:26 +02:00
Jun Pataleta 676626064c Merge branch 'MDL-79782-403' of https://github.com/roland04/moodle into MOODLE_403_STABLE 2023-10-24 22:47:47 +08:00
Jun Pataleta 655ac0b6a6 Merge branch 'MDL-79767-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-24 16:23:12 +08:00
Jun Pataleta 28233e5b3d Merge branch 'MDL-79637-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-10-24 10:48:55 +08:00
Paul Holden e001508f68 MDL-79827 tiny_link: show repositories only if editor filepicker set. 2023-10-23 22:01:01 +01:00
Mark Johnson 9b96653fc5 MDL-79617 repository_upload: Close session early in upload process 2023-10-23 15:32:15 +01:00
Angelia Dela Cruz 920ddcb70f MDL-79768 mod_data: Test for student can see upcoming data activity 2023-10-23 08:50:51 +08:00
David Woloszyn 82d1033f43 MDL-42189 gradereport_overview: Report hidden from suspended enrolments 2023-10-23 09:46:58 +11:00
Paul Holden 6856da7f09 MDL-79801 tag: fix report entity flagged column/filter query.
The "flag" field isn't a boolean state (1/0), it's a cumulative
count of how many times the tag has been flagged by users. This
should be accounted for to ensure that column aggregation and
filtering performs correctly.
2023-10-20 14:22:17 +01:00
Sara Arjona 150d134fa2 weekly release 4.3+ 2023-10-20 12:16:13 +02:00
Sara Arjona d30fa9918f Merge branch 'install_403_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_403_STABLE 2023-10-20 12:16:09 +02:00
Mikel Martín 343ad024c0 MDL-79782 pix: Replace angles- SVGs with Free versions 2023-10-20 08:50:10 +02:00
Huong Nguyen 4f8778cfc7 Merge branch 'MDL-78775-403' of https://github.com/ilyatregubov/moodle into MOODLE_403_STABLE 2023-10-20 09:29:47 +07:00
Ilya Tregubov b770c56b6d MDL-78775 gradereport_grade: Fix Behat.
Sort by lastname before doing any assertions.
2023-10-20 09:56:26 +08:00
Paul Holden 156953f115 MDL-79783 theme_boost: remove form-check padding inside table cells. 2023-10-19 14:13:46 +01:00
Mark Johnson 07a6698d01 MDL-79639 quiz_statistics: Prevent database deadlocks
This changes the cache purge code to select IDs for deletion
first, rather than using a subquery in a DELETE, since this
risks causing a deadlock in MySQL.
2023-10-19 08:57:34 +01:00
Huong Nguyen 1ec619db69 Merge branch 'MDL-79689-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-10-19 10:03:37 +07:00
Paul Holden 9f5f8d4a0a MDL-79767 communication: correct arguments when loading instance. 2023-10-18 22:38:50 +01:00
Sara Arjona 810f134cdc Merge branch 'MDL-79635-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-18 19:55:48 +02:00
Sara Arjona 7b1a0a0e65 Merge branch 'MDL-77651-403' of https://github.com/junpataleta/moodle into MOODLE_403_STABLE 2023-10-18 15:47:11 +02:00
Sara Arjona 447530591d Merge branch 'MDL-79747_403' of https://github.com/timhunt/moodle into MOODLE_403_STABLE 2023-10-18 10:28:57 +02:00
Huong Nguyen 34223e32ef Merge branch 'MDL-78775-403' of https://github.com/ilyatregubov/moodle into MOODLE_403_STABLE 2023-10-18 12:56:24 +07:00
Ilya Tregubov ac3cda51f0 MDL-78775 core_grades: Fix Behat 2023-10-18 12:53:53 +08:00
Angelia Dela Cruz f25ac24adf MDL-79689 mod_assign: Behat for enabling anonymous submissions 2023-10-18 10:46:30 +08:00
Huong Nguyen c3ba14a052 Merge branch 'MDL-79705-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-18 09:36:17 +07:00
Huong Nguyen bd844a184c Merge branch 'MDL-78979-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-18 09:23:31 +07:00
AMOS bot c968b1236f Automatically generated installer lang files 2023-10-18 00:11:10 +00:00
Jun Pataleta ff2d542295 MDL-77651 calendar: Hide left/right arrow characters
* Hide the arrow characters for the calendar templates so they won't be
read out by screen readers and avoid confusion for screen reader users.
2023-10-17 23:51:52 +08:00
Jun Pataleta bf68987951 MDL-77651 core: Hide left/right arrow characters for link_arrow_xx()
* The arrow characters in link_arrow_right() and link_arrow_left()
functions get announced by screen readers. This causes confusion
and is unnecessary.
2023-10-17 23:51:52 +08:00
Paul Holden e2049d770c MDL-79705 reportbuilder: remove checkbox field callback handling.
We no longer need special handling of this field type, because it
now returns language strings rather than HTML markup for a checkbox
element on display.
2023-10-17 16:51:29 +01:00
Paul Holden 021bdd0e4b MDL-79705 profilefield_checkbox: display data as simple Yes/No. 2023-10-17 16:51:29 +01:00
Tim Hunt 9bb59ad004 MDL-79747 quiz stats: task should run as admin the right way
The correct way to get an ad-hoc task to run as the main admin account
is to leave userid as null.

Setting it causes fatal errors if the main admin account is set to
auth: nologin.
2023-10-17 16:50:32 +01:00
Iñaki Arenaza fd1035ecf0 MDL-78481 mod_lesson: matching pagetype applying filters fix 2023-10-17 17:15:39 +02:00
Paul Holden 0602fdc0cb MDL-79693 output: remove embedded toast region from clipboard modal.
This was causing the toast notification upon the clipboard action
result to immediately disappear as the modal was closed. The toast
module can happily handle this for us itself, so remove from the
template.
2023-10-17 08:20:57 +01:00
Andrew Nicols 1294e309dc MDL-79739 core: Only run some tests in separate processes 2023-10-17 12:21:12 +08:00
Huong Nguyen 596bc2c2bf Merge branch 'MDL-78775-403' of https://github.com/ilyatregubov/moodle into MOODLE_403_STABLE 2023-10-17 10:47:02 +07:00
Ilya Tregubov 09568062fd Merge branch 'MDL-79691-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-10-17 10:28:27 +08:00
Huong Nguyen b205b758e8 Merge branch 'MDL-79367-403' of https://github.com/sarjona/moodle into MOODLE_403_STABLE 2023-10-17 09:17:46 +07:00
Paul Holden 55077e45bb MDL-78979 mod_data: correct restore decode rule for data view page. 2023-10-16 20:53:52 +01:00
Angelia Dela Cruz 9c4f0d31f2 MDL-79691 mod_h5pactivity: Behat coverage for H5P activity grades reset 2023-10-16 16:18:43 +08:00
Sara Arjona c220ad62dd Merge branch 'MDL-79566-403' of https://github.com/HuongNV13/moodle into MOODLE_403_STABLE 2023-10-16 09:53:48 +02:00
Ilya Tregubov ffc8c116fd Merge branch 'MDL-79365-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-16 14:07:55 +08:00
Sara Arjona 8679a15604 MDL-79367 availability: Fail grade does not mark activities as completed
The UX team confirmed that an activity shouldn't be considered completed
when the criteria use a passing grade and the user gets a failing grade.
So the COMPLETION_COMPLETE_FAIL status won't be considered
completed from now on.
2023-10-16 07:52:40 +02:00
Huong Nguyen 9995038273 Merge branch 'MDL-79698-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-10-16 11:39:53 +07:00
Huong Nguyen 70ee7b1beb Merge branch 'MDL-79653-403' of https://github.com/andelacruz/moodle into MOODLE_403_STABLE 2023-10-16 10:54:38 +07:00
Huong Nguyen 5cc2ab26eb Merge branch 'MDL-79352-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-16 10:42:06 +07:00
Huong Nguyen cf0446155b MDL-79566 tiny_autosave: Add Javascript submission handler 2023-10-16 09:29:16 +07:00
Paul Holden 87c42699d9 MDL-79365 customfield_textarea: ensure field uniqueness is correct. 2023-10-13 14:30:34 +01:00
Andrew Nicols 97bcb22dba MDL-79693 core: Move toast regions to document on modal close 2023-10-13 14:22:48 +01:00
Andrew Nicols ecd82700a7 MDL-79698 core: Correct duplicate array key in test provider 2023-10-13 15:44:17 +08:00
Ilya Tregubov daa598b1b4 MDL-78775 core_grades: Fix saving on grader report page
When we have a pagination on grader page and search for user
that is not on first page, saving was throwing an error
since page didn't have enough data
2023-10-13 14:09:25 +08:00
Ilya Tregubov 13eb20d8d1 weekly release 4.3+ 2023-10-13 13:39:23 +08:00
Angelia Dela Cruz d0a9c57c0b MDL-79653 gradingform_guide: Behat coverage for deleting marking guide 2023-10-13 10:46:23 +08:00
Huong Nguyen 21b11cdb3d Merge branch 'MDL-79638-403' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-10-12 11:07:19 +07:00
Ilya Tregubov d4b2c50163 Merge branch 'MDL-79160-master' of https://github.com/danghieu1407/moodle into MOODLE_403_STABLE 2023-10-12 09:43:41 +08:00
Ilya Tregubov bd50ac1876 Merge branch 'MDL-79422-master' of https://github.com/andrewnicols/moodle into MOODLE_403_STABLE 2023-10-12 09:09:27 +08:00
Ilya Tregubov da4204c491 Merge branch 'MDL-79562-403' of https://github.com/lameze/moodle into MOODLE_403_STABLE 2023-10-12 09:06:32 +08:00
Simey Lameze 780b99229c MDL-79562 behat: make verification step more specific 2023-10-12 08:16:22 +08:00
Jun Pataleta bebde352fe Merge branch 'MDL-79611-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-11 18:15:46 +08:00
Jun Pataleta 1adf99597e Merge branch 'MDL-79633-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-11 13:41:12 +08:00
Huong Nguyen 70c1b02809 Merge branch 'MDL-78103-403' of https://github.com/HuongNV13/moodle into MOODLE_403_STABLE 2023-10-11 11:25:04 +07:00
chen levy 335c9c920d MDL-78103 theme: Fixed dropdown menu size by the content 2023-10-11 11:10:26 +07:00
Safat b1ad4fb830 MDL-79614 communication_matrix: Add missing call for sync flag 2023-10-11 11:04:44 +08:00
Jun Pataleta 2b5073a222 MDL-79626 upgrade: add the 4.3.0 separation line to all upgrade scripts 2023-10-11 09:40:13 +08:00
Andrew Nicols 731b150241 MDL-79637 phpunit: Do not reset DB during init of isolated tests
During the bootstrap of PHPUnit we ensure that the database has been
reset to its initial state.

We do this by checking the internally-stored DB write count between
runs. If the count is not yet set (null), or it has been increased, we
force a reset.

When running an isolated test the test runner resets the database, it
then sets up a new isolated test environment by writing a new PHPUnit
test case and passing it to a new PHP Process using standard in. As part
of this, the bootstrap is run for that process.

Because we are in a new process, the db write count is fresh and not yet
set. This has been leading to an additional db reset before the isolated
test.

To handle this we want to _not_ perform a reset during the
initialisation for isolated runs. We know that the DB is in a fresh
state before we start the run.

To support this we need to know whether the test is an isolated test
during the bootstrap, which means we cannot use the previous approach to
calculating this.

Instead we look at the PHP_SELF value. PHP sets this to "Standard input
code" when run from stdin, instead of running a file.

There should not be any other legitimate reason to run a PHPUnit
bootstrap via this stdin approach.

Unfortunately this approach is a little bit risky as it depends on the
presence of a specific string, however this string has been in place
since 2016, and there is no legitimate way of calculating this.

I did consider looking at whether the called script included `/vendor/`
and `/phpunit`, but this is also likely a risky approach if someone
calls PHPUnit in an unexpected way.

This approach is itself unit tested so any change to PHP's stdin string
before we deprecate this approach entirely in 12 months time will be
caught.
2023-10-11 09:29:26 +08:00
Paul Holden 228ee621e6 Merge branch 'MDL-79642-q_tags_off-403' of https://github.com/leonstr/moodle into MOODLE_403_STABLE 2023-10-10 21:18:55 +01:00
Andrew Nicols 16f65ba275 MDL-79638 phpunit: Add unit test for increment resets 2023-10-11 00:10:33 +08:00
Andrew Nicols 165918258d MDL-79638 phpunit: Remove mysql/mariadb hack
This hack was introduced to work around a bug in MySQL 5.6.14 and
MariaDB at the time.

https://bugs.mysql.com/bug.php?id=69882

It was addressed a few months later in 5.6.16, and 5.7.4.
MariaDB merged version 5.6.16 of MySQL's InnoDB engine in MariaDB
10.0.11 and got hte patch from there.

Moodle has required MySQL 8.0, and MariaDB 10.6.7 since Moodle 4.2 and
it is therefore safe to remove these hacks.
2023-10-10 23:35:45 +08:00
Sara Arjona 3392a198d7 Merge branch 'MDL-79623-MOODLE_403_STABLE' of https://github.com/PhMemmel/moodle into MOODLE_403_STABLE 2023-10-10 16:19:19 +02:00
Leon Stringer 7cba44007c MDL-79642 qbank_tagquestion: Fix Return type err
Previously if $CFG->usetags was not enabled the course question bank
page would show:

  Exception - qbank_tagquestion\plugin_feature::get_question_filters():
  Return value must be of type array, none returned

This is now fixed.
2023-10-10 12:13:56 +01:00
Paul Holden 0004f31e2e MDL-79635 group: ensure unique params used to determine visibility.
Or we'll trigger DML "Incorrect number of query parameters" exception.
2023-10-10 10:08:53 +01:00
Sara Arjona 83865c7979 Merge branch 'MDL-77816-403' of https://github.com/paulholden/moodle into MOODLE_403_STABLE 2023-10-10 09:21:27 +02:00
Ilya Tregubov b43222dc67 Merge branch 'MDL-79501-master' of https://github.com/geichelberger/moodle into MOODLE_403_STABLE 2023-10-10 15:06:11 +08:00
Ilya Tregubov e857efcf28 Merge branch 'MDL-79279' of https://github.com/timhunt/moodle into MOODLE_403_STABLE 2023-10-10 11:20:58 +08:00
Ilya Tregubov e7ab69fa26 Merge branch 'MDL-71414-403' of https://github.com/laurentdavid/moodle into MOODLE_403_STABLE 2023-10-10 10:19:00 +08:00
Paul Holden f4743bbb8d MDL-79633 mod_data: correct timemodified tag replacement attribute. 2023-10-09 19:41:02 +01:00
Paul Holden d1b63c5e18 MDL-79352 admin: fix links to tool plugin management page. 2023-10-09 15:11:52 +01:00
Paul Holden cf5065ed71 MDL-79611 group: early exit getting members of non-existing group. 2023-10-09 15:00:33 +01:00
Paul Holden bf380e2d46 MDL-77816 mod_bigbluebuttonbn: feedback when validating completion. 2023-10-09 14:58:49 +01:00
Yannick Schillinger 4b40f8273d MDL-77816 mod_bigbluebuttonbn: Fix completionValidate argument format 2023-10-09 14:58:38 +01:00
Laurent David c0f2ff773f MDL-71414 mod_h5pactivity: Add a new "None" message
* In matching types of questions, sometimes the user does not answer all
questions. We now display "None" in the result report. The answer can
be either correct or incorrect.
* Fix "unknown" answer constant name.
2023-10-09 11:57:34 +02:00
Laurent David 2ef18bce0d MDL-71414 mod_h5pactivity: Fix issue with drop down report
* Drag and Drop report were missing answers when target could be dropped on multiple
drop zones.
2023-10-09 11:57:34 +02:00
Philipp Memmel 536780ce38 MDL-79623 tool_componentlibrary: Fix correct modal content attribute 2023-10-09 09:05:41 +00:00
10331 changed files with 167103 additions and 273110 deletions
-7
View File
@@ -1,7 +0,0 @@
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
See CONTRIBUTING.md guidelines for how to contribute patches for Moodle. Thank you.
--
-6
View File
@@ -1,6 +0,0 @@
> [!IMPORTANT]
> PLEASE DO NOT PUBLISH SECURITY FINDINGS PUBLICLY.
If you discover a potential security issue, please report it via our [Security Submission Form](https://moodle.org/security/report).
For more information about our security processes and responsible disclosure policy, see the [Security Procedures documentation](https://moodledev.io/general/development/process/security).
-1
View File
@@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1231.24 314.44" preserveAspectRatio="xMinYMid meet"><defs><style>.cls-1{fill:#f48020;}.cls-2,.cls-3{fill:#383738;stroke:#4a4a4c;}.cls-2{stroke-width:2.37px;}.cls-3{stroke-width:2.38px;}.cls-4{fill:#585858;}</style></defs><title>Moodle_Logo_UseonBlack_RGB</title><path class="cls-1" d="M1086.3,235.34a53.42,53.42,0,0,0,16.71,29q13.26,12.27,29.48,12.27,11.29,0,24.56-5.89,16.23-6.88,16.22-16.22l58-.49q-12.29,29-41.76,45.2-27.52,15.23-60.43,15.24-42.25,0-70-26.29t-27.75-68.54q0-43.73,27.75-69.51t72-25.8q48.15,0,75.17,31.94,25.07,29.47,25.06,79.1Zm89.91-33.91q-3.43-17.69-14.73-29-12.8-12.28-29.49-12.29-17.21,0-28.74,11.79t-15.47,29.48Z"/><path class="cls-1" d="M965.45,308.54V0h55V308.54Z"/><path class="cls-1" d="M892.69,308.54V290.36q-7.38,9.83-25.06,15.72a92.31,92.31,0,0,1-30,5.41q-39.31,0-63.13-27T750.7,217.65q0-39.3,23.34-65.84t62.15-26.53q43.71,0,56.5,23.58V0h53.55V308.54Zm0-102.68q0-14.75-14-28.26t-28.74-13.51q-21.12,0-33.41,17.2-10.8,15.24-10.8,37.33,0,21.63,10.8,36.85,12.29,17.71,33.41,17.69,12.78,0,27.76-12t15-24.81Z"/><path class="cls-1" d="M647,313.45q-41.77,0-69-26.53t-27.27-68.3q0-41.73,27.27-68.28t69-26.53q41.75,0,69.27,26.53t27.52,68.28q0,41.79-27.52,68.3T647,313.45ZM647,168q-19.89,0-30.58,15.07t-10.68,35.79q0,20.73,9.94,35.05,11.43,16.31,31.32,16.28t31.32-16.28q10.44-14.31,10.44-35.05t-9.94-35Q667.42,168,647,168Z"/><path class="cls-1" d="M448.07,313.45q-41.76,0-69-26.53t-27.27-68.3q0-41.73,27.27-68.28t69-26.53q41.74,0,69.28,26.53t27.5,68.28q0,41.79-27.5,68.3T448.07,313.45Zm0-145.43q-19.89,0-30.59,15.07t-10.69,35.79q0,20.73,9.94,35.05,11.43,16.31,31.34,16.28t31.32-16.28q10.42-14.31,10.44-35.05t-9.94-35Q468.45,168,448.07,168Z"/><path class="cls-1" d="M288.89,309.11V201q0-33.9-28-33.9t-28,33.9V309.11h-55V201q0-33.9-27.52-33.9-28,0-28,33.9V309.11h-55V194.65q0-35.37,24.56-53.54,21.61-16.22,58.46-16.22,37.35,0,55,19.16,15.23-19.16,55.51-19.16,36.86,0,58.45,16.22,24.57,18.16,24.57,53.54V309.11Z"/><path class="cls-2" d="M.76,145.76"/><path class="cls-3" d="M1.73,145.32"/><path class="cls-4" d="M173.86,116.85l55.08-40.1-.7-2.44C135,83.92,80.42,96.44,0,144.13l.73,2.38,21-.67c15.17.52,30.85,1.26,46,1.32-1,24.09.83,32.65.83,32.65,51.92,17.58,101.22,1.53,127.14-43.9A248.72,248.72,0,0,0,173.86,116.85Z"/><path class="cls-4" d="M113.78,110c-.3-1.08-2.23-1.48-4.28-.9a4.73,4.73,0,0,0-3.14,2.19c-18.53,5-49.16,13.72-70.73,21l-1.33.45c-16.68,5.61-24.73,8.49-25.22,12.55-2.29,18.44-.87,42.18-.86,42.48l.19,6.4c-9.74,27.56.06,49.6,8.38,69.77.06-24.92,1.07-45.22-6-71-.2-3.82-1.49-30.36.61-47.34.34-2.75,11.65-6.56,23.63-10.59l1.33-.44c22-7.42,53.57-16.39,71.9-21.29a6.75,6.75,0,0,0,2.29-.25C112.64,112.43,114.08,111.09,113.78,110Z"/></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

-31
View File
@@ -1,31 +0,0 @@
name: 'Close Pull Requests'
on:
pull_request_target:
types: opened
workflow_dispatch:
jobs:
close:
# Avoid forks to run this job
if: github.repository_owner == 'moodle'
name: Close Pull Requests
runs-on: ubuntu-latest
steps:
- uses: dessant/repo-lockdown@v4
with:
process-only: prs
close-pr: true
skip-closed-pr-comment: true
pr-comment: >
**Please, don't open pull requests via GitHub.**
This repository (moodle.git) at GitHub is just a mirror of the official Moodle repository.
For how to contribute patches for Moodle see
[CONTRIBUTING.md](https://github.com/moodle/moodle/blob/main/CONTRIBUTING.md).
Closing this pull request.
-143
View File
@@ -1,143 +0,0 @@
name: One by One Testing
# Run all the individual unit tests one by one, with
# fully independent PHPUnit executions. Useful to
# detect issues with some tests that are using stuff
# that has been made available by others, but is not
# available when running individually.
#
# Note that we aren't using PHPUnit's own isolation
# here but completely separated runs, one for each
# test.
#
# The workflow will fail reporting all the tests
# that have failed (and will pass if no failure is
# detected, of course).
#
# It's only executed via workflow dispatch (automated
# or manual), not by push/tag. And acceptd configuration
# of phpunit, specially useful to run it with PHPUnit's
# own isolation or any other option.
on:
workflow_dispatch:
inputs:
phpunit_extra_options:
description: Additional options to apply to PHPUnit
required: false
default: ''
env:
chunks: 7
jobs:
collect:
name: Collect individual unit tests
runs-on: ubuntu-latest
outputs:
matrix: ${{steps.individual-tests.outputs.matrix }}
steps:
- name: Checking out code
uses: actions/checkout@v4
- name: Looking for all individual tests
id: individual-tests
run: |
count=0 # Number of individual tests found.
while read -r testfile; do # For each test file.
while read -r testname; do # For each unit test in a file.
count=$((count + 1))
# Sent it to the correct chunk file.
chunk=$(((($count % $chunks)) + 1))
echo "$testname $testfile" >> ./chunk_$chunk.txt
done < <(grep "function test_" "${testfile}" | sed -r "s/^.*function (test_[a-zA-Z0-9_]+).*/\1/")
done < <(find . -name "*_test.php")
# Generate the matrix to run tests.
echo "matrix=$(ls -1 chunk_*.txt | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
echo "$count individual tests collected in $chunks files"
- name: Upload individual tests files
uses: actions/upload-artifact@v4
with:
name: individual_tests
path: chunk_*.txt
retention-days: 1
test:
name: Run tests
needs: collect
runs-on: ubuntu-latest
services:
exttests:
image: moodlehq/moodle-exttests
ports:
- 8080:80
redis:
image: redis
ports:
- 6379:6379
strategy:
fail-fast: false
matrix:
file: ${{ fromJson(needs.collect.outputs.matrix) }}
steps:
- name: Setting up DB pgsql
uses: m4nu56/postgresql-action@v1
with:
postgresql version: 13
postgresql db: test
postgresql user: test
postgresql password: test
- name: Setting up PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.3
ini-values: max_input_vars=5000
coverage: none
- name: Checking out code
uses: actions/checkout@v4
- name: Download individual test files
uses: actions/download-artifact@v4
with:
name: individual_tests # Make all the chunk files available for the next steps.
- name: Setting up PHPUnit
env:
dbtype: pgsql
run: |
echo "pathtophp=$(which php)" >> $GITHUB_ENV
cp .github/workflows/config-template.php config.php
mkdir ../moodledata
sudo locale-gen en_AU.UTF-8
php admin/tool/phpunit/cli/init.php --no-composer-self-update
- name: Run PHPUnit test (one by one)
env:
dbtype: pgsql
run: |
status=0
count=0
while read -r line; do # For each line in the chunk file
count=$((count + 1))
filter="${line% *}"
file="${line#* }"
# Run the individual unit test and report problems if needed to.
if ! php vendor/bin/phpunit \
--fail-on-empty-test-suite \
--fail-on-warning \
--fail-on-risky \
--filter "$filter" ${{ inputs.phpunit_extra_options }} \
"$file" >/dev/null 2>&1; then
if [ $status -eq 0 ]; then
echo "Problems found, list of PHPUnit commands failing:"
fi
echo "vendor/bin/phpunit --filter '${filter}' ${{ inputs.phpunit_extra_options }} $file"
status=$((status + 1))
fi
done < ${{ matrix.file }}
echo "Finished: $count individual tests executed, $status tests failed"
exit $status
+7 -7
View File
@@ -3,7 +3,7 @@ name: Core
on:
push:
branches-ignore:
- main
- master
- MOODLE_[0-9]+_STABLE
tags-ignore:
- v[0-9]+.[0-9]+.[0-9]+*
@@ -15,7 +15,7 @@ on:
default: ''
env:
php: 8.3
php: 8.2
jobs:
Grunt:
@@ -23,10 +23,10 @@ jobs:
steps:
- name: Checking out code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Configuring node & npm
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
@@ -62,12 +62,12 @@ jobs:
include:
# MySQL builds always run with the lowest PHP supported version.
- os: ubuntu-22.04
php: 8.1
php: 8.0
extensions:
db: mysqli
# PostgreSQL builds always run with the highest PHP supported version.
- os: ubuntu-22.04
php: 8.3
php: 8.2
db: pgsql
steps:
@@ -105,7 +105,7 @@ jobs:
coverage: none
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Setting up PHPUnit
env:
-23
View File
@@ -1,23 +0,0 @@
name: Web Installer Testing
on:
workflow_dispatch:
jobs:
InstallationTest:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: [8.1, 8.3]
steps:
- name: Construct repository URL
run: echo "REPOSITORY_URL=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" >> $GITHUB_ENV
shell: bash
- uses: moodlehq/moodle-webinstaller-test@main
with:
repository: ${{ env.REPOSITORY_URL }}
branch: ${{ github.ref_name }}
php: ${{ matrix.php }}
+6 -6
View File
@@ -8,7 +8,7 @@ on:
required: false
default: ''
env:
php: 8.3
php: 8.2
jobs:
Grunt:
@@ -21,10 +21,10 @@ jobs:
git config --global core.eol lf
- name: Checking out code
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Configuring node & npm
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
@@ -51,7 +51,7 @@ jobs:
matrix:
include:
- os: windows-latest
php: 8.3
php: 8.2
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
# this is the place to enable them.
@@ -59,7 +59,7 @@ jobs:
db: pgsql
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
- os: windows-latest
php: 8.1
php: 8.0
db: pgsql
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
@@ -117,7 +117,7 @@ jobs:
git config --global core.eol lf
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
uses: actions/checkout@v4
uses: actions/checkout@v3
# Needs to be done after php is available, git configured and Moodle checkout has happened.
- name: Setting up moodle-exttests service
-3
View File
@@ -26,9 +26,6 @@
/.patches/
/.idea/
.phpstorm.*
!/.phpstorm.meta.php/
/.phpstorm.meta.php/*
!/.phpstorm.meta.php/di.php
/nbproject/
CVS
.DS_Store
+14 -6
View File
@@ -21,7 +21,7 @@
*/
/**
* Function to generate the destination for the minification task
* Function to generate the destination for the uglify task
* (e.g. build/file.min.js). This function will be passed to
* the rename property of files array when building dynamically:
* http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
@@ -60,6 +60,7 @@ module.exports = grunt => {
grunt.registerTask('js', ['amd', 'yui']);
// Register NPM tasks.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-rollup');
@@ -103,7 +104,6 @@ module.exports = grunt => {
// The queue runner will run the next `size` items in the queue.
const runQueue = (size = 1) => {
queue.splice(0, size).forEach(resolve => {
grunt.log.debug(`Item resolved. Kicking off next one.`);
resolve();
});
};
@@ -113,17 +113,15 @@ module.exports = grunt => {
// The options hook is run in parallel.
// We can return an unresolved Promise which is queued for later resolution.
options: async(options) => {
options: async() => {
return new Promise(resolve => {
queue.push(resolve);
startQueue();
return options;
});
},
// When an item in the queue completes, start the next item in the queue.
generateBundle: (options, bundle) => {
grunt.log.debug(`Finished output phase for ${Object.keys(bundle).join(', ')}`);
buildEnd: () => {
runQueue();
},
};
@@ -157,6 +155,16 @@ module.exports = grunt => {
],
presets: [
['@babel/preset-env', {
targets: {
browsers: [
">0.3%",
"last 2 versions",
"not ie >= 0",
"not op_mini all",
"not Opera > 0",
"not dead"
]
},
modules: false,
useBuiltIns: false
}]
+12 -28
View File
@@ -20,33 +20,17 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
module.exports = (grunt) => {
const path = require('path');
grunt.registerTask('jsdoc', 'Generate JavaScript documentation using jsdoc', function() {
const done = this.async();
const configuration = path.resolve('.grunt/jsdoc/jsdoc.conf.js');
grunt.util.spawn({
cmd: 'jsdoc',
args: [
'--configure',
configuration,
]
}, function(error, result, code) {
if (result.stdout) {
grunt.log.write(result.stdout);
}
if (result.stderr) {
grunt.log.error(result.stderr);
}
if (error) {
grunt.fail.fatal(`JSDoc failed with error code ${code}`);
} else {
grunt.log.write('JSDoc completed successfully'.green);
}
done();
});
module.exports = grunt => {
// Project configuration.
grunt.config.merge({
jsdoc: {
dist: {
options: {
configure: ".grunt/jsdoc/jsdoc.conf.js",
},
},
},
});
grunt.loadNpmTasks('grunt-jsdoc');
};
+1 -5
View File
@@ -29,7 +29,6 @@ module.exports = grunt => {
// Use a fully-qualified path.
src: files,
options: {
quietDeprecationWarnings: true,
configOverrides: {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
@@ -46,10 +45,7 @@ module.exports = grunt => {
return {
stylelint: {
scss: {
options: {
quietDeprecationWarnings: true,
customSyntax: 'postcss-scss',
},
options: {syntax: 'scss'},
src: files,
},
},
+1 -1
View File
@@ -1 +1 @@
lts/iron
lts/gallium
-40
View File
@@ -1,40 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper file for PhpStorm, and other IDEs, to provide better code completion.
*
* @package core
* @copyright 2024 Andrew Lyons <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace PHPSTORM_META;
// Assume that anything returned by \core\di::get('...') is an instance of the first argument.
override(\core\di::get(0), map([
'' => '@',
]));
// Assume that anything returned by \Psr\Container\ContainerInterface::get('...') is an instance of the first argument.
override(\Psr\Container\ContainerInterface::get(0), map([
'' => '@',
]));
// Assume that anything returned by \DI\Container::get('...') is an instance of the first argument.
override(\DI\Container::get(0), map([
'' => '@',
]));
+4 -16
View File
@@ -1,14 +1,9 @@
{
"customSyntax": "postcss-scss",
"plugins": [
"stylelint-csstree-validator"
],
"rules": {
"csstree/validator": {
"syntaxExtensions": [
"sass"
]
},
"csstree/validator": true,
"at-rule-empty-line-before": [ "always",
{"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
],
@@ -50,7 +45,7 @@
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
"function-url-scheme-disallowed-list": ["data"],
"function-url-scheme-blacklist": ["data"],
"function-whitespace-after": "always",
"indentation": 4,
"keyframe-declaration-no-important": true,
@@ -89,19 +84,12 @@
"selector-type-no-unknown": true,
"string-no-newline": true,
"time-min-milliseconds": 100,
"unit-disallowed-list": ["pt"],
"unit-blacklist": ["pt"],
"unit-case": "lower",
"unit-no-unknown": true,
"value-keyword-case": ["lower", {"ignoreKeywords": ["/(@|$)/"]}],
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
},
"overrides": [
{
"files": ["**/yui/**/*.css"],
"rules": {
}
}
]
}
}
-52
View File
@@ -1,52 +0,0 @@
# Contributing to Moodle
[Moodle][1] is made by people like you. We are members of a big worldwide community of developers, designers, teachers, testers, translators and many more. We work in universities, schools, companies and other places. You are very welcome to join us and contribute to the project.
There are many ways that you can contribute to Moodle, not just through development. See our [community contribution guide][2] for some of the many ways that you can help.
## Github
> [!NOTE]
> Please do not open pull requests via Github.
All issues should be reported via, and patched provided to the [Moodle Tracker][3].
The Moodle [Github][4] repository is a clone of the official Moodle repository, whcih can be found at https://git.moodle.org.
## Moodle core bug fixes and new features
Over the years, Moodle has developed a mature process for reporting, reviewing, and accepting patches. This is fully documented in our [documentation on development processes][6], but in summary:
- Every bug fix or new feature must have a tracker issue.
- You publish the branch implementing the fix or new feature in your public clone of the moodle.git repository (typically on Github).
- Your patch is peer-reviewed, discussed, integrated, tested and then released as a part of one of our weekly releases.
- New features are developed on the `main` branch. Bug fixes are also backported to currently supported maintenance (stable) branches.
> [!IMPORTANT]
> Please do not publish security issues, or patches releating to them publicly.
> See our [Responsible Disclosure Policy][5] for more information.
## Moodle plugins
Moodle has a framework for additional plugins to extend its functionality. We
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
register and maintain your plugin. Plugins hosted in the plugins directory can
be easily installed and updated via the Moodle administration interface.
* You are expected to have a public source code repository with your plugin
code.
* After registering your plugin in the plugins directory it is reviewed before
being published.
* You are expected to continuously release updated versions of the plugin via
the plugins directory. We do not pull from your code repository; you must do
it explicitly.
For further details, see <https://moodledev.io/general/community/plugincontribution>.
[1]: https://moodle.org
[2]: https://moodledev.io/general/community/contribute
[3]: https://tracker.moodle.org
[4]: https://github.com/moodle/moodle
[5]: https://moodledev.io/general/development/process/security
[6]: https://moodledev.io/general/development/process
+56
View File
@@ -0,0 +1,56 @@
CONTRIBUTING TO MOODLE
======================
Moodle is made by people like you. We are members of a big worldwide community
of developers, designers, teachers, testers, translators and other users. We
work in universities, schools, companies and other places. You are very welcome
to join us and contribute to the project.
See <https://moodledev.io/general/community/contribute> for the many ways you
can help, not only with coding.
Moodle is open to community contributions to core, though all code must go
through peer-review, automated behaviour testing, continuous integration and
human post-integration checks.
Pull requests
-------------
Please do not open pull requests via Github. The repository there is just a
mirror of the official repository at <https://git.moodle.org>. Issues are
reported and patches provided via <https://tracker.moodle.org>. See below for
more information.
Moodle core bug fixes and new features
--------------------------------------
During the years of intensive development, a mature process of including
submitted patches has evolved.
* Every bug fix or new feature must have a tracker issue.
* You publish the branch implementing the fix or new feature in your public
clone of the moodle.git repository (typically on Github).
* Your patch is peer-reviewed, discussed, integrated, tested and then released
as a part of moodle.git.
* New features are developed on the master branch. Bug fixes are also
backported to currently supported maintenance (stable) branches.
For further details, see <https://moodledev.io/general/development/process>.
Moodle plugins
--------------
Moodle has a framework for additional plugins to extend its functionality. We
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
register and maintain your plugin. Plugins hosted in the plugins directory can
be easily installed and updated via the Moodle administration interface.
* You are expected to have a public source code repository with your plugin
code.
* After registering your plugin in the plugins directory it is reviewed before
being published.
* You are expected to continuously release updated versions of the plugin via
the plugins directory. We do not pull from your code repository; you must do
it explicitly.
For further details, see <https://moodledev.io/general/community/plugincontribution>.
+7
View File
@@ -0,0 +1,7 @@
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
See CONTRIBUTING.txt guidelines for how to contribute patches for Moodle. Thank you.
--
-48
View File
@@ -1,48 +0,0 @@
# Moodle
<p align="center"><a href="https://moodle.org" target="_blank" title="Moodle Website">
<img src="https://raw.githubusercontent.com/moodle/moodle/main/.github/moodlelogo.svg" alt="The Moodle Logo">
</a></p>
[Moodle][1] is the World's Open Source Learning Platform, widely used around the world by countless universities, schools, companies, and all manner of organisations and individuals.
Moodle is designed to allow educators, administrators and learners to create personalised learning environments with a single robust, secure and integrated system.
## Documentation
- Read our [User documentation][3]
- Discover our [developer documentation][5]
- Take a look at our [demo site][4]
## Community
[moodle.org][1] is the central hub for the Moodle Community, with spaces for educators, administrators and developers to meet and work together.
You may also be interested in:
- attending a [Moodle Moot][6]
- our regular series of [developer meetings][7]
- the [Moodle User Association][8]
## Installation and hosting
Moodle is Free, and Open Source software. You can easily [download Moodle][9] and run it on your own web server, however you may prefer to work with one of our experienced [Moodle Partners][10].
Moodle also offers hosting through both [MoodleCloud][11], and our [partner network][10].
## License
Moodle is provided freely as open source software, under version 3 of the GNU General Public License. For more information on our license see
[1]: https://moodle.org
[2]: https://moodle.com
[3]: https://docs.moodle.org/
[4]: https://sandbox.moodledemo.net/
[5]: https://moodledev.io
[6]: https://moodle.com/events/mootglobal/
[7]: https://moodledev.io/general/community/meetings
[8]: https://moodleassociation.org/
[9]: https://download.moodle.org
[10]: https://moodle.com/partners
[11]: https://moodle.com/cloud
[12]: https://moodledev.io/general/license
+28
View File
@@ -0,0 +1,28 @@
.-..-.
_____ | || |
/____/-.---_ .---. .---. .-.| || | .---.
| | _ _ |/ _ \/ _ \/ _ || |/ __ \
* | | | | | || |_| || |_| || |_| || || |___/
|_| |_| |_|\_____/\_____/\_____||_|\_____)
Moodle - the world's open source learning platform
Moodle <https://moodle.org> is a learning platform designed to provide
educators, administrators and learners with a single robust, secure and
integrated system to create personalised learning environments.
You can download Moodle <https://download.moodle.org> and run it on your own
web server, ask one of our Moodle Partners <https://moodle.com/partners/> to
assist you, or have a MoodleCloud site <https://moodle.com/cloud/> set up for
you.
Moodle is widely used around the world by universities, schools, companies and
all manner of organisations and individuals.
Moodle is provided freely as open source software, under the GNU General Public
License <https://moodledev.io/general/license>.
Moodle is written in PHP and JavaScript and uses an SQL database for storing
the data.
See <https://docs.moodle.org> for details of Moodle's many features.
-10
View File
@@ -1,10 +0,0 @@
define("core_admin/bulk_user_actions",["exports","core_reportbuilder/local/selectors","core_table/local/dynamic/events","core_form/changechecker","core/custom_interaction_events","jquery"],(function(_exports,reportSelectors,tableEvents,FormChangeChecker,CustomEvents,_jquery){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
/**
* Add bulk actions to the users list report
*
* @module core_admin/bulk_user_actions
* @copyright 2024 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,reportSelectors=_interopRequireWildcard(reportSelectors),tableEvents=_interopRequireWildcard(tableEvents),FormChangeChecker=_interopRequireWildcard(FormChangeChecker),CustomEvents=_interopRequireWildcard(CustomEvents),_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};const Selectors_bulkActionsForm="form#user-bulk-action-form",Selectors_userReportWrapper='[data-region="report-user-list-wrapper"]',Selectors_checkbox='input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',Selectors_masterCheckbox='input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',Selectors_checkedRows='[data-togglegroup="report-select-all"][data-toggle="slave"]:checked';_exports.init=()=>{var _userBulkForm$closest;const userBulkForm=document.querySelector(Selectors_bulkActionsForm),userReport=null==userBulkForm||null===(_userBulkForm$closest=userBulkForm.closest(Selectors_userReportWrapper))||void 0===_userBulkForm$closest?void 0:_userBulkForm$closest.querySelector(reportSelectors.regions.report);if(!userBulkForm||!userReport)return;const actionSelect=userBulkForm.querySelector("select");CustomEvents.define(actionSelect,[CustomEvents.events.accessibleChange]),(0,_jquery.default)(actionSelect).on(CustomEvents.events.accessibleChange,(event=>{if(event.target.value&&"0"!=="".concat(event.target.value)){const e=new Event("submit",{cancelable:!0});userBulkForm.dispatchEvent(e),e.defaultPrevented||(FormChangeChecker.markFormSubmitted(userBulkForm),userBulkForm.submit())}}));const updateUserIds=()=>{const selectedUsers=[...userReport.querySelectorAll(Selectors_checkedRows)],selectedUserIds=selectedUsers.map((check=>parseInt(check.value)));userBulkForm.querySelector('[name="userids"]').value=selectedUserIds.join(","),actionSelect.disabled=0===selectedUsers.length,actionSelect.disabled&&(actionSelect.value="0");const selectedUsersNames=selectedUsers.map((check=>document.querySelector('label[for="'.concat(check.id,'"]')).textContent));userBulkForm.data={userids:selectedUserIds,usernames:selectedUsersNames}};updateUserIds(),document.addEventListener("change",(event=>{(event.target.matches(Selectors_checkbox)||event.target.matches(Selectors_masterCheckbox))&&userReport.contains(event.target)&&updateUserIds()})),document.addEventListener(tableEvents.tableContentRefreshed,(event=>{userReport.contains(event.target)&&updateUserIds()}))}}));
//# sourceMappingURL=bulk_user_actions.min.js.map
File diff suppressed because one or more lines are too long
-10
View File
@@ -1,10 +0,0 @@
define("core_admin/themeselector/preview_modal",["exports","core/modal_events","core/modal_cancel","core/modal_save_cancel","core/notification","core/templates","core/str"],(function(_exports,_modal_events,_modal_cancel,_modal_save_cancel,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Modal for theme previews.
*
* @module core_admin/themeselector/preview_modal
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_events=_interopRequireDefault(_modal_events),_modal_cancel=_interopRequireDefault(_modal_cancel),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const SELECTORS_THEMES_CONTAINER="themelist",SELECTORS_PREVIEW='[data-action="preview"]';_exports.init=()=>{registerListenerEvents()};const registerListenerEvents=()=>{document.addEventListener("click",(e=>{const preview=e.target.closest(SELECTORS_PREVIEW);preview&&buildModal(preview).catch(_notification.default.exception)}))},buildModal=async element=>{let description=await(0,_str.getString)("choosereadme","theme_"+element.getAttribute("data-choose"));const themesContainer=document.getElementById(SELECTORS_THEMES_CONTAINER),definedInConfig=parseInt(themesContainer.dataset.definedinconfig),data={name:element.getAttribute("data-name"),image:element.getAttribute("data-image"),description:description.replace(/<[^>]+>/g," "),current:element.getAttribute("data-current"),actionurl:element.getAttribute("data-actionurl"),choose:element.getAttribute("data-choose"),sesskey:element.getAttribute("data-sesskey"),definedinconfig:definedInConfig};let modalTemplate=_modal_save_cancel.default;(data.current||data.definedinconfig)&&(modalTemplate=_modal_cancel.default);const modal=await modalTemplate.create({title:data.name,body:_templates.default.render("core_admin/themeselector/theme_preview_modal",data),large:!0,buttons:{save:(0,_str.getString)("selecttheme","moodle"),cancel:(0,_str.getString)("closebuttontitle","moodle")},show:!0});modal.getRoot().on(_modal_events.default.save,(()=>{modal.getRoot().find("form").submit()}))}}));
//# sourceMappingURL=preview_modal.min.js.map
@@ -1 +0,0 @@
{"version":3,"file":"preview_modal.min.js","sources":["../../src/themeselector/preview_modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Modal for theme previews.\n *\n * @module core_admin/themeselector/preview_modal\n * @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalEvents from 'core/modal_events';\nimport ModalCancel from 'core/modal_cancel';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst SELECTORS = {\n THEMES_CONTAINER: 'themelist',\n PREVIEW: '[data-action=\"preview\"]',\n};\n\n/**\n * Entrypoint of the js.\n *\n * @method init\n */\nexport const init = () => {\n registerListenerEvents();\n};\n\n/**\n * Register theme related event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n document.addEventListener('click', (e) => {\n const preview = e.target.closest(SELECTORS.PREVIEW);\n if (preview) {\n buildModal(preview).catch(Notification.exception);\n }\n });\n};\n\n/**\n * Build the modal with the provided data.\n *\n * @method buildModal\n * @param {object} element\n */\nconst buildModal = async(element) => {\n\n // This string can be long. We will fetch it with JS as opposed to passing it as an attribute.\n let description = await getString('choosereadme', 'theme_' + element.getAttribute('data-choose'));\n\n const themesContainer = document.getElementById(SELECTORS.THEMES_CONTAINER);\n const definedInConfig = parseInt(themesContainer.dataset.definedinconfig);\n // Prepare data for modal.\n const data = {\n name: element.getAttribute('data-name'),\n image: element.getAttribute('data-image'),\n description: description.replace(/<[^>]+>/g, ' '), // Strip out HTML tags.\n current: element.getAttribute('data-current'),\n actionurl: element.getAttribute('data-actionurl'),\n choose: element.getAttribute('data-choose'),\n sesskey: element.getAttribute('data-sesskey'),\n definedinconfig: definedInConfig,\n };\n\n // Determine which modal template we should use.\n let modalTemplate = ModalSaveCancel;\n if (data.current || data.definedinconfig) {\n modalTemplate = ModalCancel;\n }\n\n const modal = await modalTemplate.create({\n title: data.name,\n body: Templates.render('core_admin/themeselector/theme_preview_modal', data),\n large: true,\n buttons: {\n 'save': getString('selecttheme', 'moodle'),\n 'cancel': getString('closebuttontitle', 'moodle'),\n },\n show: true,\n });\n\n modal.getRoot().on(ModalEvents.save, () => {\n modal.getRoot().find('form').submit();\n });\n};\n"],"names":["SELECTORS","registerListenerEvents","document","addEventListener","e","preview","target","closest","buildModal","catch","Notification","exception","async","description","element","getAttribute","themesContainer","getElementById","definedInConfig","parseInt","dataset","definedinconfig","data","name","image","replace","current","actionurl","choose","sesskey","modalTemplate","ModalSaveCancel","ModalCancel","modal","create","title","body","Templates","render","large","buttons","show","getRoot","on","ModalEvents","save","find","submit"],"mappings":";;;;;;;gWA8BMA,2BACgB,YADhBA,kBAEO,wCAQO,KAChBC,gCAQEA,uBAAyB,KAC3BC,SAASC,iBAAiB,SAAUC,UAC1BC,QAAUD,EAAEE,OAAOC,QAAQP,mBAC7BK,SACAG,WAAWH,SAASI,MAAMC,sBAAaC,eAW7CH,WAAaI,MAAAA,cAGXC,kBAAoB,kBAAU,eAAgB,SAAWC,QAAQC,aAAa,sBAE5EC,gBAAkBd,SAASe,eAAejB,4BAC1CkB,gBAAkBC,SAASH,gBAAgBI,QAAQC,iBAEnDC,KAAO,CACTC,KAAMT,QAAQC,aAAa,aAC3BS,MAAOV,QAAQC,aAAa,cAC5BF,YAAaA,YAAYY,QAAQ,WAAY,KAC7CC,QAASZ,QAAQC,aAAa,gBAC9BY,UAAWb,QAAQC,aAAa,kBAChCa,OAAQd,QAAQC,aAAa,eAC7Bc,QAASf,QAAQC,aAAa,gBAC9BM,gBAAiBH,qBAIjBY,cAAgBC,4BAChBT,KAAKI,SAAWJ,KAAKD,mBACrBS,cAAgBE,6BAGdC,YAAcH,cAAcI,OAAO,CACrCC,MAAOb,KAAKC,KACZa,KAAMC,mBAAUC,OAAO,+CAAgDhB,MACvEiB,OAAO,EACPC,QAAS,OACG,kBAAU,cAAe,kBACvB,kBAAU,mBAAoB,WAE5CC,MAAM,IAGVR,MAAMS,UAAUC,GAAGC,sBAAYC,MAAM,KACjCZ,MAAMS,UAAUI,KAAK,QAAQC"}
-97
View File
@@ -1,97 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Add bulk actions to the users list report
*
* @module core_admin/bulk_user_actions
* @copyright 2024 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import * as reportSelectors from 'core_reportbuilder/local/selectors';
import * as tableEvents from 'core_table/local/dynamic/events';
import * as FormChangeChecker from 'core_form/changechecker';
import * as CustomEvents from 'core/custom_interaction_events';
import jQuery from 'jquery';
const Selectors = {
bulkActionsForm: 'form#user-bulk-action-form',
userReportWrapper: '[data-region="report-user-list-wrapper"]',
checkbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',
masterCheckbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',
checkedRows: '[data-togglegroup="report-select-all"][data-toggle="slave"]:checked',
};
/**
* Initialise module
*/
export const init = () => {
const userBulkForm = document.querySelector(Selectors.bulkActionsForm);
const userReport = userBulkForm?.closest(Selectors.userReportWrapper)?.querySelector(reportSelectors.regions.report);
if (!userBulkForm || !userReport) {
return;
}
const actionSelect = userBulkForm.querySelector('select');
CustomEvents.define(actionSelect, [CustomEvents.events.accessibleChange]);
jQuery(actionSelect).on(CustomEvents.events.accessibleChange, event => {
if (event.target.value && `${event.target.value}` !== "0") {
const e = new Event('submit', {cancelable: true});
userBulkForm.dispatchEvent(e);
if (!e.defaultPrevented) {
FormChangeChecker.markFormSubmitted(userBulkForm);
userBulkForm.submit();
}
}
});
// Every time the checkboxes in the report are changed, update the list of users in the form values
// and enable/disable the action select.
const updateUserIds = () => {
const selectedUsers = [...userReport.querySelectorAll(Selectors.checkedRows)];
const selectedUserIds = selectedUsers.map(check => parseInt(check.value));
userBulkForm.querySelector('[name="userids"]').value = selectedUserIds.join(',');
// Disable the action selector if nothing selected, and reset the current selection.
actionSelect.disabled = selectedUsers.length === 0;
if (actionSelect.disabled) {
actionSelect.value = "0";
}
const selectedUsersNames = selectedUsers.map(check => document.querySelector(`label[for="${check.id}"]`).textContent);
// Add the user ids and names to the form data attributes so they can be available from the
// other JS modules that listen to the form submit event.
userBulkForm.data = {userids: selectedUserIds, usernames: selectedUsersNames};
};
updateUserIds();
document.addEventListener('change', event => {
// When checkboxes are checked next to individual users or the master toggle (Select all/none).
if ((event.target.matches(Selectors.checkbox) || event.target.matches(Selectors.masterCheckbox))
&& userReport.contains(event.target)) {
updateUserIds();
}
});
document.addEventListener(tableEvents.tableContentRefreshed, event => {
// When the report contents is updated (i.e. page is changed, filters applied, etc).
if (userReport.contains(event.target)) {
updateUserIds();
}
});
};
@@ -1,104 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Modal for theme previews.
*
* @module core_admin/themeselector/preview_modal
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import ModalEvents from 'core/modal_events';
import ModalCancel from 'core/modal_cancel';
import ModalSaveCancel from 'core/modal_save_cancel';
import Notification from 'core/notification';
import Templates from 'core/templates';
import {getString} from 'core/str';
const SELECTORS = {
THEMES_CONTAINER: 'themelist',
PREVIEW: '[data-action="preview"]',
};
/**
* Entrypoint of the js.
*
* @method init
*/
export const init = () => {
registerListenerEvents();
};
/**
* Register theme related event listeners.
*
* @method registerListenerEvents
*/
const registerListenerEvents = () => {
document.addEventListener('click', (e) => {
const preview = e.target.closest(SELECTORS.PREVIEW);
if (preview) {
buildModal(preview).catch(Notification.exception);
}
});
};
/**
* Build the modal with the provided data.
*
* @method buildModal
* @param {object} element
*/
const buildModal = async(element) => {
// This string can be long. We will fetch it with JS as opposed to passing it as an attribute.
let description = await getString('choosereadme', 'theme_' + element.getAttribute('data-choose'));
const themesContainer = document.getElementById(SELECTORS.THEMES_CONTAINER);
const definedInConfig = parseInt(themesContainer.dataset.definedinconfig);
// Prepare data for modal.
const data = {
name: element.getAttribute('data-name'),
image: element.getAttribute('data-image'),
description: description.replace(/<[^>]+>/g, ' '), // Strip out HTML tags.
current: element.getAttribute('data-current'),
actionurl: element.getAttribute('data-actionurl'),
choose: element.getAttribute('data-choose'),
sesskey: element.getAttribute('data-sesskey'),
definedinconfig: definedInConfig,
};
// Determine which modal template we should use.
let modalTemplate = ModalSaveCancel;
if (data.current || data.definedinconfig) {
modalTemplate = ModalCancel;
}
const modal = await modalTemplate.create({
title: data.name,
body: Templates.render('core_admin/themeselector/theme_preview_modal', data),
large: true,
buttons: {
'save': getString('selecttheme', 'moodle'),
'cancel': getString('closebuttontitle', 'moodle'),
},
show: true,
});
modal.getRoot().on(ModalEvents.save, () => {
modal.getRoot().find('form').submit();
});
};
-71
View File
@@ -1,71 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\output;
use moodle_url;
use renderable;
use renderer_base;
use stdClass;
use templatable;
/**
* Theme selector renderable.
*
* @package core_admin
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class theme_selector implements renderable, templatable {
/** @var array $themedata Theme data to pass to the template. */
private $themedata = null;
/** @var bool Whether $CFG->theme is defined in config.php. */
private $definedinconfig;
/**
* Constructor.
*
* @param array $themedata Theme data used for template.
* @param bool $definedinconfig Whether $CFG->theme is defined in config.php.
*/
public function __construct(array $themedata, bool $definedinconfig = false) {
$this->themedata = $themedata;
$this->definedinconfig = $definedinconfig;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output Renderer base.
* @return stdClass
*/
public function export_for_template(renderer_base $output): stdClass {
$data = new stdClass();
// Theme data used to populate cards and modal.
$data->themes = $this->themedata;
// Reset theme caches button.
$reseturl = new moodle_url('/admin/themeselector.php', ['sesskey' => sesskey(), 'reset' => 1]);
$resetbutton = new \single_button($reseturl, get_string('themeresetcaches', 'admin'), 'post',
\single_button::BUTTON_SECONDARY);
$data->resetbutton = $resetbutton->export_for_template($output);
$data->definedinconfig = $this->definedinconfig;
return $data;
}
}
+1 -1
View File
@@ -35,7 +35,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
*
* @return string
*/
public static function get_reason(): string {
public static function get_reason() : string {
return 'privacy:metadata';
}
}
@@ -46,14 +46,12 @@ class task_log extends base {
protected const FAILED = 1;
/**
* Database tables that this entity uses
* Database tables that this entity uses and their default aliases
*
* @return string[]
* @return array
*/
protected function get_default_tables(): array {
return [
'task_log',
];
protected function get_default_table_aliases(): array {
return ['task_log' => 'tl'];
}
/**
@@ -1,108 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_admin\reportbuilder\local\filters;
use core\context\system;
use core_course_category;
use MoodleQuickForm;
use core_reportbuilder\local\filters\base;
use core_reportbuilder\local\helpers\database;
/**
* Course role report filter (by role, category, course)
*
* The provided filter field SQL must refer/return an expression for the user ID (e.g. "{$user}.id")
*
* @package core_admin
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class courserole extends base {
/**
* Setup form
*
* @param MoodleQuickForm $mform
*/
public function setup_form(MoodleQuickForm $mform): void {
$elements = [];
// Role.
$elements['role'] = $mform->createElement('select', "{$this->name}_role", get_string('rolefullname', 'core_role'),
[0 => get_string('anyrole', 'core_filters')] + get_default_enrol_roles(system::instance()));
// Category.
$elements['category'] = $mform->createElement('select', "{$this->name}_category", get_string('category'),
[0 => get_string('anycategory', 'core_filters')] + core_course_category::make_categories_list());
// Course.
$elements['course'] = $mform->createElement('text', "{$this->name}_course", get_string('shortnamecourse'));
$mform->setType("{$this->name}_course", PARAM_RAW_TRIMMED);
$mform->addGroup($elements, "{$this->name}_group", $this->get_header(), '', false)
->setHiddenLabel(true);
}
/**
* Return filter SQL
*
* @param array $values
* @return array
*/
public function get_sql_filter(array $values): array {
[$fieldsql, $params] = $this->filter->get_field_sql_and_params();
[$contextalias, $rolealias, $coursealias] = database::generate_aliases(3);
[$roleparam, $categoryparam, $courseparam] = database::generate_param_names(3);
// Role.
$role = (int) ($values["{$this->name}_role"] ?? 0);
if ($role > 0) {
$selects[] = "{$rolealias}.roleid = :{$roleparam}";
$params[$roleparam] = $role;
}
// Category.
$category = (int) ($values["{$this->name}_category"] ?? 0);
if ($category > 0) {
$selects[] = "{$coursealias}.category = :{$categoryparam}";
$params[$categoryparam] = $category;
}
// Course.
$course = trim($values["{$this->name}_course"] ?? '');
if ($course !== '') {
$selects[] = "{$coursealias}.shortname = :{$courseparam}";
$params[$courseparam] = $course;
}
// Filter values are not set.
if (empty($selects)) {
return ['', []];
}
return ["{$fieldsql} IN (
SELECT {$rolealias}.userid
FROM {role_assignments} {$rolealias}
JOIN {context} {$contextalias} ON {$contextalias}.id = {$rolealias}.contextid AND {$contextalias}.contextlevel = 50
JOIN {course} {$coursealias} ON {$coursealias}.id = {$contextalias}.instanceid
WHERE " . implode(' AND ', $selects) . "
)", $params];
}
}
@@ -1,417 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace core_admin\reportbuilder\local\systemreports;
use core_admin\reportbuilder\local\filters\courserole;
use core\context\system;
use core_cohort\reportbuilder\local\entities\cohort;
use core_cohort\reportbuilder\local\entities\cohort_member;
use core_reportbuilder\local\entities\user;
use core_reportbuilder\local\filters\boolean_select;
use core_reportbuilder\local\helpers\database;
use core_reportbuilder\local\helpers\user_profile_fields;
use core_reportbuilder\local\report\action;
use core_reportbuilder\local\report\filter;
use core_reportbuilder\system_report;
use core_role\reportbuilder\local\entities\role;
use core_user\fields;
use lang_string;
use moodle_url;
use pix_icon;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/authlib.php');
require_once($CFG->libdir.'/enrollib.php');
require_once($CFG->dirroot.'/user/lib.php');
/**
* Browse users system report class implementation
*
* @package core_admin
* @copyright 2023 David Carrillo <davidmc@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class users extends system_report {
/**
* Initialise report, we need to set the main table, load our entities and set columns/filters
*/
protected function initialise(): void {
global $CFG;
// Our main entity, it contains all of the column definitions that we need.
$entityuser = new user();
$entityuseralias = $entityuser->get_table_alias('user');
$this->set_main_table('user', $entityuseralias);
$this->add_entity($entityuser);
// Any columns required by actions should be defined here to ensure they're always available.
$fullnamefields = array_map(fn($field) => "{$entityuseralias}.{$field}", fields::get_name_fields());
$this->add_base_fields("{$entityuseralias}.id, {$entityuseralias}.confirmed, {$entityuseralias}.mnethostid,
{$entityuseralias}.suspended, {$entityuseralias}.username, " . implode(', ', $fullnamefields));
if ($this->get_parameter('withcheckboxes', false, PARAM_BOOL)) {
$canviewfullnames = has_capability('moodle/site:viewfullnames', \context_system::instance());
$this->set_checkbox_toggleall(static function(\stdClass $row) use ($canviewfullnames): array {
return [$row->id, fullname($row, $canviewfullnames)];
});
}
$paramguest = database::generate_param_name();
$this->add_base_condition_sql("{$entityuseralias}.deleted <> 1 AND {$entityuseralias}.id <> :{$paramguest}",
[$paramguest => $CFG->siteguest]);
$entitycohortmember = new cohort_member();
$entitycohortmemberalias = $entitycohortmember->get_table_alias('cohort_members');
$this->add_entity($entitycohortmember
->add_joins($entitycohortmember->get_joins())
->add_join("LEFT JOIN {cohort_members} {$entitycohortmemberalias}
ON {$entityuseralias}.id = {$entitycohortmemberalias}.userid")
);
$entitycohort = new cohort();
$entitycohortalias = $entitycohort->get_table_alias('cohort');
$this->add_entity($entitycohort
->add_joins($entitycohort->get_joins())
->add_joins($entitycohortmember->get_joins())
->add_join("LEFT JOIN {cohort} {$entitycohortalias}
ON {$entitycohortalias}.id = {$entitycohortmemberalias}.cohortid")
);
// Join the role entity (Needed for the system role filter).
$roleentity = new role();
$role = $roleentity->get_table_alias('role');
$this->add_entity($roleentity
->add_join("LEFT JOIN (
SELECT DISTINCT r0.id, ras.userid
FROM {role} r0
JOIN {role_assignments} ras ON ras.roleid = r0.id
WHERE ras.contextid = ".SYSCONTEXTID."
) {$role} ON {$role}.userid = {$entityuseralias}.id")
);
// Now we can call our helper methods to add the content we want to include in the report.
$this->add_columns();
$this->add_filters();
$this->add_actions();
// Set if report can be downloaded.
$this->set_downloadable(true);
}
/**
* Validates access to view this report
*
* @return bool
*/
protected function can_view(): bool {
return has_any_capability(['moodle/user:update', 'moodle/user:delete'], system::instance());
}
/**
* Adds the columns we want to display in the report
*
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
* unique identifier
*/
public function add_columns(): void {
$entityuser = $this->get_entity('user');
$entityuseralias = $entityuser->get_table_alias('user');
$this->add_column($entityuser->get_column('fullnamewithpicturelink'));
// Include identity field columns.
$identitycolumns = $entityuser->get_identity_columns($this->get_context());
foreach ($identitycolumns as $identitycolumn) {
$this->add_column($identitycolumn);
}
// Add "Last access" column.
$this->add_column(($entityuser->get_column('lastaccess'))
->set_callback(static function ($value, \stdClass $row): string {
if ($row->lastaccess) {
return format_time(time() - $row->lastaccess);
}
return get_string('never');
})
);
if ($column = $this->get_column('user:fullnamewithpicturelink')) {
$column
->add_fields("{$entityuseralias}.suspended, {$entityuseralias}.confirmed")
->add_callback(static function(string $fullname, \stdClass $row): string {
if ($row->suspended) {
$fullname .= ' ' . \html_writer::tag('span', get_string('suspended', 'moodle'),
['class' => 'badge badge-secondary ml-1']);
}
if (!$row->confirmed) {
$fullname .= ' ' . \html_writer::tag('span', get_string('confirmationpending', 'admin'),
['class' => 'badge badge-danger ml-1']);
}
return $fullname;
});
}
$this->set_initial_sort_column('user:fullnamewithpicturelink', SORT_ASC);
$this->set_default_no_results_notice(new lang_string('nousersfound', 'moodle'));
}
/**
* Adds the filters we want to display in the report
*
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
* unique identifier
*/
protected function add_filters(): void {
$entityuser = $this->get_entity('user');
$entityuseralias = $entityuser->get_table_alias('user');
$filters = [
'user:fullname',
'user:firstname',
'user:lastname',
'user:username',
'user:idnumber',
'user:email',
'user:department',
'user:institution',
'user:city',
'user:country',
'user:confirmed',
'user:suspended',
'user:timecreated',
'user:lastaccess',
'user:timemodified',
'user:auth',
'user:lastip',
'cohort:idnumber',
'role:name',
];
$this->add_filters_from_entities($filters);
// Enrolled in any course filter.
$ue = database::generate_alias();
[$now1, $now2] = database::generate_param_names(2);
$now = time();
$sql = "CASE WHEN ({$entityuseralias}.id IN (
SELECT userid FROM {user_enrolments} {$ue}
WHERE {$ue}.status = " . ENROL_USER_ACTIVE . "
AND ({$ue}.timestart = 0 OR {$ue}.timestart < :{$now1})
AND ({$ue}.timeend = 0 OR {$ue}.timeend > :{$now2})
)) THEN 1 ELSE 0 END";
$this->add_filter((new filter(
boolean_select::class,
'enrolledinanycourse',
new lang_string('anycourses', 'filters'),
$this->get_entity('user')->get_entity_name(),
))
->set_field_sql($sql, [
$now1 => $now,
$now2 => $now,
])
);
// Course role filter.
$this->add_filter((new filter(
courserole::class,
'courserole',
new lang_string('courserole', 'filters'),
$this->get_entity('user')->get_entity_name(),
))
->set_field_sql("{$entityuseralias}.id")
);
// Add user profile fields filters.
$userprofilefields = new user_profile_fields($entityuseralias . '.id', $entityuser->get_entity_name());
foreach ($userprofilefields->get_filters() as $filter) {
$this->add_filter($filter);
}
// Set options for system role filter.
if ($filter = $this->get_filter('role:name')) {
$filter
->set_header(new lang_string('globalrole', 'role'))
->set_options(get_assignable_roles(system::instance()));
}
}
/**
* Add the system report actions. An extra column will be appended to each row, containing all actions added here
*
* Note the use of ":id" placeholder which will be substituted according to actual values in the row
*/
protected function add_actions(): void {
global $DB, $USER;
$contextsystem = system::instance();
// Action to edit users.
$this->add_action((new action(
new moodle_url('/user/editadvanced.php', ['id' => ':id', 'course' => get_site()->id]),
new pix_icon('t/edit', ''),
[],
false,
new lang_string('edit', 'moodle'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && (is_siteadmin($USER) || !is_siteadmin($row));
}));
// Action to suspend users (non mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['suspend' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/show', ''),
[],
false,
new lang_string('suspenduser', 'admin'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended && !is_mnet_remote_user($row) &&
!($row->id == $USER->id || is_siteadmin($row));
}));
// Action to unsuspend users (non mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['unsuspend' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/hide', ''),
[],
false,
new lang_string('unsuspenduser', 'admin'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && $row->suspended && !is_mnet_remote_user($row) &&
!($row->id == $USER->id || is_siteadmin($row));
}));
// Action to unlock users (non mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['unlock' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/unlock', ''),
[],
false,
new lang_string('unlockaccount', 'admin'),
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && !is_mnet_remote_user($row) &&
login_is_lockedout($row);
}));
// Action to suspend users (mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'deny']),
new pix_icon('t/show', ''),
[],
false,
new lang_string('denyaccess', 'mnet'),
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
if (!$accessctrl = $DB->get_field(table: 'mnet_sso_access_control', return: 'accessctrl',
conditions: ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]
)) {
$accessctrl = 'allow';
}
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
is_mnet_remote_user($row) && $accessctrl == 'allow';
}));
// Action to unsuspend users (mnet remote users).
$this->add_action((new action(
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'allow']),
new pix_icon('t/hide', ''),
[],
false,
new lang_string('allowaccess', 'mnet'),
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
if (!$accessctrl = $DB->get_field(table: 'mnet_sso_access_control', return: 'accessctrl',
conditions: ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]
)) {
$accessctrl = 'allow';
}
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
is_mnet_remote_user($row) && $accessctrl == 'deny';
}));
// Action to delete users.
$this->add_action((new action(
new moodle_url('/admin/user.php', ['delete' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/delete', ''),
[
'class' => 'text-danger',
'data-modal' => 'confirmation',
'data-modal-title-str' => json_encode(['deleteuser', 'admin']),
'data-modal-content-str' => ':deletestr',
'data-modal-yes-button-str' => json_encode(['delete', 'core']),
'data-modal-destination' => ':deleteurl',
],
false,
new lang_string('delete', 'moodle'),
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
// Populate deletion modal attributes.
$row->deletestr = json_encode([
'deletecheckfull',
'moodle',
fullname($row, true),
]);
$row->deleteurl = (new moodle_url('/admin/user.php', [
'delete' => $row->id,
'confirm' => md5($row->id),
'sesskey' => sesskey(),
]))->out(false);
return has_capability('moodle/user:delete', $contextsystem) &&
!is_mnet_remote_user($row) && $row->id != $USER->id && !is_siteadmin($row);
}));
$this->add_action_divider();
// Action to confirm users.
$this->add_action((new action(
new moodle_url('/admin/user.php', ['confirmuser' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/check', ''),
[],
false,
new lang_string('confirmaccount', 'moodle'),
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
return has_capability('moodle/user:update', $contextsystem) && !$row->confirmed;
}));
// Action to resend email.
$this->add_action((new action(
new moodle_url('/admin/user.php', ['resendemail' => ':id', 'sesskey' => sesskey()]),
new pix_icon('t/email', ''),
[],
false,
new lang_string('resendemail', 'moodle'),
))->add_callback(static function(\stdclass $row): bool {
return !$row->confirmed && !is_mnet_remote_user($row);
}));
}
/**
* Row class
*
* @param \stdClass $row
* @return string
*/
public function get_row_class(\stdClass $row): string {
return $row->suspended ? 'text-muted' : '';
}
}
+7 -3
View File
@@ -91,7 +91,7 @@ class hook_list_table extends flexible_table {
*/
public function out(): void {
// All hook consumers referenced from the db/hooks.php files.
$hookmanager = \core\di::get(\core\hook\manager::class);
$hookmanager = \core\hook\manager::get_instance();
$allhooks = (array)$hookmanager->get_all_callbacks();
// Add any unused hooks.
@@ -154,7 +154,11 @@ class hook_list_table extends flexible_table {
return '';
}
$deprecates = \core\hook\manager::get_replaced_callbacks($row->classname);
$rc = new \ReflectionClass($row->classname);
if (!$rc->implementsInterface(\core\hook\deprecated_callback_replacement::class)) {
return '';
}
$deprecates = call_user_func([$row->classname, 'get_deprecated_plugin_callbacks']);
if (count($deprecates) === 0) {
return '';
}
@@ -269,7 +273,7 @@ class hook_list_table extends flexible_table {
if (is_array($tag)) {
return $this->get_tag(...$tag);
}
return $this->get_tag($tag, 'badge bg-info text-white');
return $this->get_tag($tag, 'badge badge-info');
}, $tags);
return implode("\n", $taglist);
@@ -500,15 +500,4 @@ abstract class plugin_management_table extends flexible_table implements dynamic
protected function supports_ordering(): bool {
return $this->plugininfoclass::plugintype_supports_ordering();
}
/**
* Check if the user has the capability to access this table.
*
* Default implementation for plugin management tables is to require 'moodle/site:config' capability
*
* @return bool Return true if capability check passed.
*/
public function has_capability(): bool {
return has_capability('moodle/site:config', $this->get_context());
}
}
+7 -23
View File
@@ -33,7 +33,6 @@ require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
list($options, $unrecognized) = cli_get_params(array(
'courseid' => false,
'courseshortname' => '',
'cmid' => false,
'destination' => '',
'help' => false,
), array('h' => 'help'));
@@ -43,14 +42,13 @@ if ($unrecognized) {
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] || !($options['courseid'] || $options['courseshortname'] || $options['cmid'])) {
if ($options['help'] || !($options['courseid'] || $options['courseshortname'])) {
$help = <<<EOL
Perform backup of the given course or course module.
Perform backup of the given course.
Options:
--courseid=INTEGER Course ID for backup.
--courseshortname=STRING Course shortname for backup. This option is ignored if courseid is set.
--cmid=INTEGER Course module ID for backup. This option is ignored if courseid or courseshortname is set.
--courseshortname=STRING Course shortname for backup.
--destination=STRING Path where to store backup file. If not set the backup
will be stored within the course backup file area.
-h, --help Print out this help.
@@ -78,26 +76,16 @@ if (!empty($dir)) {
}
}
// Check that the course or course module exists.
// Check that the course exists.
if ($options['courseid']) {
$course = $DB->get_record('course', array('id' => $options['courseid']), '*', MUST_EXIST);
} else if ($options['courseshortname']) {
$course = $DB->get_record('course', array('shortname' => $options['courseshortname']), '*', MUST_EXIST);
} else if ($options['cmid']) {
$cm = $DB->get_record('course_modules', ['id' => $options['cmid']], '*', MUST_EXIST);
}
cli_heading('Performing backup...');
if (!empty($course)) {
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
} else if (!empty($cm)) {
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
} else {
throw new \moodle_exception('invalidoption');
}
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
// Set the default filename.
$format = $bc->get_format();
$type = $bc->get_type();
@@ -125,11 +113,7 @@ if (!empty($dir)) {
}
}
} else {
if (!empty($course)) {
mtrace("Backup completed, the new file is listed in the backup area of the given course");
} else {
mtrace("Backup completed, the new file is listed in the backup area of the given module");
}
mtrace("Backup completed, the new file is listed in the backup area of the given course");
}
$bc->destroy();
exit(0);
-132
View File
@@ -1,132 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This script allows to import a course from CLI.
*
* @package core
* @subpackage cli
* @author Tomo Tsuyuki <tomotsuyuki@catalyst-au.net>
* @copyright 2023 Catalyst IT
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', 1);
require(__DIR__ . '/../../config.php');
require_once($CFG->libdir . '/clilib.php');
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
list($options, $unrecognized) = cli_get_params([
'srccourseid' => '',
'srccmid' => '',
'dstcourseid' => '',
'showdebugging' => false,
'help' => false,
], [
's' => 'showdebugging',
'h' => 'help',
]);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] ||
!(($options['srccourseid'] && $options['dstcourseid'])
|| ($options['srccmid'] && $options['dstcourseid']))) {
$help = <<<EOL
Import course or course module into provided course.
Options:
--srccourseid=INT Source course ID to backup.
--srccmid=INT Source course module ID to backup.
--dstcourseid=INT Destination course ID to restore.
-s, --showdebugging Show developer level debugging information
-h, --help Print out this help.
Example1: (Import from a course into another course)
\$sudo -u www-data /usr/bin/php admin/cli/import.php --srccourseid=12 --dstcourseid=13\n
Example2: (Import from a course module into a course)
\$sudo -u www-data /usr/bin/php admin/cli/import.php --srccmid=21 --dstcourseid=11\n
EOL;
echo $help;
exit(0);
}
if ($options['showdebugging']) {
set_debugging(DEBUG_DEVELOPER, true);
}
if (!$admin = get_admin()) {
throw new \moodle_exception('noadmins');
}
if (!empty($options['srccourseid']) && !empty($options['dstcourseid'])) {
// Import from course into course.
if (!$srccourse = $DB->get_record('course', ['id' => $options['srccourseid']], 'id')) {
throw new \moodle_exception('invalidcourseid');
}
if (!$dstcourse = $DB->get_record('course', ['id' => $options['dstcourseid']], 'id')) {
throw new \moodle_exception('invalidcourseid');
}
cli_heading(get_string('importfromcoursetocourse', 'backup', (object)$options));
$bc = new backup_controller(backup::TYPE_1COURSE, $srccourse->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->id);
$backupid = $bc->get_backupid();
$bc->execute_plan();
$bc->destroy();
cli_heading(get_string('backupthenrestore', 'backup'));
$rc = new restore_controller($backupid, $dstcourse->id, backup::INTERACTIVE_NO,
backup::MODE_SAMESITE, $admin->id, backup::TARGET_EXISTING_ADDING);
$rc->execute_precheck();
$rc->execute_plan();
$rc->destroy();
cli_heading(get_string('restoredcourseid', 'backup', $dstcourse->id));
} else if (!empty($options['srccmid']) && !empty($options['dstcourseid'])) {
// Import from course module into course.
if (!$cm = $DB->get_record('course_modules', ['id' => $options['srccmid']], 'id')) {
throw new \moodle_exception('invalidcoursemoduleid', 'error', '', $options['srccmid']);
}
if (!$course = $DB->get_record('course', ['id' => $options['dstcourseid']], 'id')) {
throw new \moodle_exception('invalidcourseid');
}
cli_heading(get_string('importfromccmidtocourse', 'backup', (object)$options));
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->id);
$backupid = $bc->get_backupid();
$bc->execute_plan();
$bc->destroy();
cli_heading(get_string('backupthenrestore', 'backup'));
$rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO,
backup::MODE_SAMESITE, $admin->id, backup::TARGET_EXISTING_ADDING);
$rc->execute_precheck();
$rc->execute_plan();
$rc->destroy();
cli_heading(get_string('restoredcourseid', 'backup', $course->id));
} else {
throw new \moodle_exception('invalidoption');
}
exit(0);
+7 -3
View File
@@ -177,7 +177,6 @@ $CFG->admin = array_pop($parts);
ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
require_once($CFG->libdir.'/classes/component.php');
require_once($CFG->libdir.'/classes/text.php');
require_once($CFG->libdir.'/classes/string_manager.php');
require_once($CFG->libdir.'/classes/string_manager_install.php');
@@ -193,8 +192,13 @@ require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/componentlib.class.php');
require_once($CFG->dirroot.'/cache/lib.php');
// Register our classloader.
\core_component::register_autoloader();
// Register our classloader, in theory somebody might want to replace it to load other hacked core classes.
// Required because the database checks below lead to session interaction which is going to lead us to requiring autoloaded classes.
if (defined('COMPONENT_CLASSLOADER')) {
spl_autoload_register(COMPONENT_CLASSLOADER);
} else {
spl_autoload_register('core_component::classloader');
}
require($CFG->dirroot.'/version.php');
$CFG->target_release = $release;
-3
View File
@@ -31,7 +31,6 @@ require_once($CFG->libdir.'/clilib.php');
$longoptions = [
'help' => false,
'muc' => false,
'courses' => false,
'theme' => false,
'lang' => false,
'js' => false,
@@ -56,8 +55,6 @@ all caches will be purged.
Options:
-h, --help Print out this help
--muc Purge all MUC caches (includes lang cache)
--courses Purge all course caches (or only those specified by a comma-separated list).
e.g. --courses=4,67,145
--theme Purge theme cache
--lang Purge language string cache
--js Purge JavaScript cache
+12 -40
View File
@@ -32,13 +32,11 @@ require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
list($options, $unrecognized) = cli_get_params([
'file' => '',
'categoryid' => '',
'courseid' => '',
'showdebugging' => false,
'help' => false,
], [
'f' => 'file',
'c' => 'categoryid',
'C' => 'courseid',
's' => 'showdebugging',
'h' => 'help',
]);
@@ -48,17 +46,15 @@ if ($unrecognized) {
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help'] || !($options['file']) || !($options['categoryid'] || $options['courseid'])) {
if ($options['help'] || !($options['file']) || !($options['categoryid'])) {
$help = <<<EOL
Restore backup into provided category or course.
If courseid is set, course module/s will be added into the course.
Restore backup into provided category.
Options:
-f, --file=STRING Path to the backup file.
-c, --categoryid=INT ID of the course category to restore to.
-C, --courseid=INT ID of the course to restore to. This option is ignored if categoryid is set.
-s, --showdebugging Show developer level debugging information
-h, --help Print out this help.
-f, --file=STRING Path to the backup file.
-c, --categoryid=INT ID of the category to restore too.
-s, --showdebugging Show developer level debugging information
-h, --help Print out this help.
Example:
\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/file.mbz --categoryid=1\n
@@ -80,16 +76,8 @@ if (!file_exists($options['file'])) {
throw new \moodle_exception('filenotfound');
}
if ($options['categoryid']) {
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
throw new \moodle_exception('invalidcategoryid');
}
} else if ($options['courseid']) {
if (!$course = $DB->get_record('course', ['id' => $options['courseid']], 'id')) {
throw new \moodle_exception('invalidcourseid');
}
} else {
throw new \moodle_exception('invalidoption');
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
throw new \moodle_exception('invalidcategoryid');
}
$backupdir = restore_controller::get_tempdir_name(SITEID, $USER->id);
@@ -104,29 +92,13 @@ try {
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
get_string('restoringcourseshortname', 'backup'));
if (!empty($course)) {
$courseid = $course->id;
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
backup::MODE_GENERAL, $admin->id, backup::TARGET_EXISTING_ADDING);
} else {
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
}
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
$rc->execute_precheck();
$rc->execute_plan();
$rc->destroy();
// Rename course name if the backup is from course module and restore to category.
if (empty($course)) {
$course = get_course($courseid);
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoretonewcourse', 'backup'),
get_string('newcourse'));
$course->fullname = $fullname;
$course->shortname = $shortname;
$course->visible = 1;
$DB->update_record('course', $course);
}
} catch (Exception $e) {
cli_heading(get_string('cleaningtempdata'));
fulldelete($path);
+5 -1
View File
@@ -189,7 +189,11 @@ if ($disable = $options['disable']) {
}
$task->set_lock($lock);
$cronlock->release();
if (!$task->is_blocking()) {
$cronlock->release();
} else {
$task->set_cron_lock($cronlock);
}
\core\cron::run_inner_scheduled_task($task);
}
-207
View File
@@ -3923,8 +3923,6 @@
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="4.2" requires="3.11.8">
@@ -3941,7 +3939,6 @@
<VENDOR name="oracle" version="19" />
</DATABASE>
<PHP version="8.0.0" level="required">
<RESTRICT function="restrict_php_version_83" message="unsupportedphpversion83" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -4115,8 +4112,6 @@
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="4.3" requires="3.11.8">
@@ -4133,7 +4128,6 @@
<VENDOR name="oracle" version="19" />
</DATABASE>
<PHP version="8.0.0" level="required">
<RESTRICT function="restrict_php_version_83" message="unsupportedphpversion83" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -4309,8 +4303,6 @@
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="4.4" requires="4.1.2">
@@ -4502,205 +4494,6 @@
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="4.5" requires="4.1.2">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="10.6.7" />
<VENDOR name="mysql" version="8.0" />
<VENDOR name="postgres" version="13" />
<VENDOR name="mssql" version="14.0" />
<VENDOR name="oracle" version="19" />
</DATABASE>
<PHP version="8.1.0" level="required">
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="required">
<FEEDBACK>
<ON_ERROR message="mbstringrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
<PHP_EXTENSION name="sodium" level="required"/>
<PHP_EXTENSION name="exif" level="optional"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
<FEEDBACK>
<ON_ERROR message="sixtyfourbitsrequired" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
<FEEDBACK>
<ON_CHECK message="iscustomadminwarnings" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+1 -1
View File
@@ -30,7 +30,7 @@ require_once($CFG->libdir . '/tablelib.php');
admin_externalpage_setup('hooksoverview');
require_capability('moodle/site:config', \core\context\system::instance());
$hookmanager = \core\di::get(\core\hook\manager::class);
$hookmanager = \core\hook\manager::get_instance();
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('hooksoverview', 'core_admin'));
+3 -1
View File
@@ -301,12 +301,14 @@ class helper {
// Set Activity chooser tabs to the default value ("Starred, Recommended, All, Activities, Resources").
static::add_item($presetid, 'activitychoosertabmode', '3');
// Modules: Enable database, external tool (lti), IMS content package (imscp), lesson, SCORM, wiki, workshop.
// Modules: Enable chat, database, external tool (lti), IMS content package (imscp), lesson, SCORM, survey, wiki, workshop.
static::add_plugin($presetid, 'mod', 'chat', true);
static::add_plugin($presetid, 'mod', 'data', true);
static::add_plugin($presetid, 'mod', 'lti', true);
static::add_plugin($presetid, 'mod', 'imscp', true);
static::add_plugin($presetid, 'mod', 'lesson', true);
static::add_plugin($presetid, 'mod', 'scorm', true);
static::add_plugin($presetid, 'mod', 'survey', true);
static::add_plugin($presetid, 'mod', 'wiki', true);
static::add_plugin($presetid, 'mod', 'workshop', true);
+2 -2
View File
@@ -761,8 +761,8 @@ class manager {
public function delete_preset(int $presetid): void {
global $DB;
// Check the preset exists (cannot delete the pre-installed core "Starter" and "Full" presets).
$preset = $DB->get_record('adminpresets', ['id' => $presetid, 'iscore' => self::NONCORE_PRESET]);
// Check the preset exists.
$preset = $DB->get_record('adminpresets', ['id' => $presetid]);
if (!$preset) {
throw new moodle_exception('errordeleting', 'core_adminpresets');
}
+2 -2
View File
@@ -41,7 +41,7 @@ class provider implements
* @param collection $collection A list of information about this component
* @return collection The collection object filled out with information about this component.
*/
public static function get_metadata(collection $collection): collection {
public static function get_metadata(collection $collection) : collection {
// These tables are really data about site configuration and not user data.
// The adminpresets includes information about which user performed a configuration change using the admin_presets
@@ -74,7 +74,7 @@ class provider implements
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
public static function get_contexts_for_userid(int $userid) : contextlist {
return new contextlist();
}
+2
View File
@@ -227,6 +227,7 @@ class core_adminpresets_generator extends \component_generator_base {
public function access_protected($object, string $property) {
$reflection = new ReflectionClass($object);
$property = $reflection->getProperty($property);
$property->setAccessible(true);
return $property->getValue($object);
}
@@ -243,6 +244,7 @@ class core_adminpresets_generator extends \component_generator_base {
// Set method accessibility.
$method = new ReflectionMethod(manager::class, 'get_setting');
$method->setAccessible(true);
// Get the proper adminpresets_setting instance.
$settingpage = $adminroot->locate($category);
+1 -1
View File
@@ -344,7 +344,7 @@ class helper_test extends \advanced_testcase {
],
'plugins' => [
'assign' => 1,
'book' => 1,
'chat' => 1,
'data' => 1,
'lesson' => 1,
],
+1 -28
View File
@@ -16,7 +16,6 @@
namespace core_adminpresets;
use moodle_exception;
use stdClass;
/**
@@ -29,14 +28,6 @@ use stdClass;
* @coversDefaultClass \core_adminpresets\manager
*/
class manager_test extends \advanced_testcase {
/**
* Include required libraries.
*/
public static function setUpBeforeClass(): void {
global $CFG;
require_once($CFG->libdir.'/adminlib.php');
}
/**
* Test the behaviour of protected get_site_settings method.
*
@@ -608,28 +599,10 @@ class manager_test extends \advanced_testcase {
$manager = new manager();
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Error deleting from database');
$this->expectException(\moodle_exception::class);
$manager->delete_preset($unexistingid);
}
/**
* Test trying to delete the core/pre-defined presets
*
* @covers ::delete_preset
*/
public function test_delete_preset_core(): void {
global $DB;
$this->resetAfterTest();
$starterpreset = $DB->get_record('adminpresets', ['iscore' => manager::STARTER_PRESET]);
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Error deleting from database');
(new manager())->delete_preset($starterpreset->id);
}
/**
* Test the behaviour of delete_preset() method.
*
@@ -36,7 +36,7 @@ class privacy_provider_test extends provider_testcase {
* Test for provider::get_metadata().
* @covers ::get_metadata
*/
public function test_get_metadata(): void {
public function test_get_metadata() {
$collection = new collection('core_adminpresets');
$newcollection = provider::get_metadata($collection);
$itemcollection = $newcollection->get_collection();
@@ -49,7 +49,7 @@ class privacy_provider_test extends provider_testcase {
* Test for provider::get_contexts_for_userid() doesn't return any context.
* @covers ::get_contexts_for_userid
*/
public function test_get_contexts_for_userid(): void {
public function test_get_contexts_for_userid() {
global $USER;
$this->resetAfterTest();
@@ -67,7 +67,7 @@ class privacy_provider_test extends provider_testcase {
* Test for provider::get_users_in_context() doesn't return any user.
* @covers ::get_users_in_context
*/
public function test_get_users_in_context(): void {
public function test_get_users_in_context() {
global $USER;
$this->resetAfterTest();
@@ -88,7 +88,7 @@ class privacy_provider_test extends provider_testcase {
* Test for provider::export_user_data().
* @covers ::export_user_data
*/
public function test_export_user_data(): void {
public function test_export_user_data() {
global $USER;
$this->resetAfterTest();
@@ -121,7 +121,7 @@ class privacy_provider_test extends provider_testcase {
* Test for provider::delete_data_for_all_users_in_context().
* @covers ::delete_data_for_all_users_in_context
*/
public function test_delete_data_for_all_users_in_context(): void {
public function test_delete_data_for_all_users_in_context() {
global $DB, $USER;
$this->resetAfterTest();
@@ -146,7 +146,7 @@ class privacy_provider_test extends provider_testcase {
* Test for provider::delete_data_for_user().
* @covers ::delete_data_for_user
*/
public function test_delete_data_for_user(): void {
public function test_delete_data_for_user() {
global $DB, $USER;
$this->resetAfterTest();
+32 -50
View File
@@ -617,7 +617,7 @@ class core_admin_renderer extends plugin_renderer_base {
* @param bool $croninfrequent
* @return string HTML to output.
*/
public function cron_infrequent_warning(bool $croninfrequent): string {
public function cron_infrequent_warning(bool $croninfrequent) : string {
global $CFG;
if (!$croninfrequent) {
@@ -874,8 +874,8 @@ class core_admin_renderer extends plugin_renderer_base {
protected function mobile_configuration_warning($mobileconfigured) {
$output = '';
if (!$mobileconfigured) {
$settingslink = new moodle_url('/admin/search.php', ['query' => 'enablemobilewebservice']);
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'), 'get');
$settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
$output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . '&nbsp;' . $configurebutton);
}
@@ -1111,11 +1111,10 @@ class core_admin_renderer extends plugin_renderer_base {
if ($isstandard = $plugin->is_standard()) {
$row->attributes['class'] .= ' standard';
$sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'),
'sourcetext badge bg-secondary text-dark');
$sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'), 'sourcetext badge badge-secondary');
} else {
$row->attributes['class'] .= ' extension';
$sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext badge bg-info text-white');
$sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext badge badge-info');
}
$coredependency = $plugin->is_core_dependency_satisfied($version);
@@ -1129,19 +1128,19 @@ class core_admin_renderer extends plugin_renderer_base {
$statusclass = 'statustext badge ';
switch ($statuscode) {
case core_plugin_manager::PLUGIN_STATUS_NEW:
$statusclass .= $dependenciesok ? 'bg-success text-white' : 'bg-warning text-dark';
$statusclass .= $dependenciesok ? 'badge-success' : 'badge-warning';
break;
case core_plugin_manager::PLUGIN_STATUS_UPGRADE:
$statusclass .= $dependenciesok ? 'bg-info text-white' : 'bg-warning text-dark';
$statusclass .= $dependenciesok ? 'badge-info' : 'badge-warning';
break;
case core_plugin_manager::PLUGIN_STATUS_MISSING:
case core_plugin_manager::PLUGIN_STATUS_DOWNGRADE:
case core_plugin_manager::PLUGIN_STATUS_DELETE:
$statusclass .= 'bg-danger text-white';
$statusclass .= 'badge-danger';
break;
case core_plugin_manager::PLUGIN_STATUS_NODB:
case core_plugin_manager::PLUGIN_STATUS_UPTODATE:
$statusclass .= $dependenciesok ? 'bg-light text-dark' : 'bg-warning text-dark';
$statusclass .= $dependenciesok ? 'badge-light' : 'badge-warning';
break;
}
$status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass);
@@ -1264,11 +1263,11 @@ class core_admin_renderer extends plugin_renderer_base {
}
$out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 0)),
get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge bg-light text-dark'),
get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge badge-light'),
'btn btn-link mr-1');
$out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 1)),
get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge bg-light text-dark'),
get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge badge-light'),
'btn btn-link mr-1');
$out .= $this->output->container_end(); // End of .actions container.
@@ -1421,9 +1420,9 @@ class core_admin_renderer extends plugin_renderer_base {
$supportedmoodles = array();
foreach ($plugin->version->supportedmoodles as $moodle) {
if ($CFG->branch == str_replace('.', '', $moodle->release)) {
$supportedmoodles[] = html_writer::span($moodle->release, 'badge bg-success text-white');
$supportedmoodles[] = html_writer::span($moodle->release, 'badge badge-success');
} else {
$supportedmoodles[] = html_writer::span($moodle->release, 'badge bg-light text-dark');
$supportedmoodles[] = html_writer::span($moodle->release, 'badge badge-light');
}
}
@@ -1529,7 +1528,7 @@ class core_admin_renderer extends plugin_renderer_base {
$label = '';
} else {
$class = 'requires-failed';
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge bg-danger text-white');
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-danger');
}
if ($branch != null && !$plugin->is_core_compatible_satisfied($branch)) {
@@ -1558,10 +1557,8 @@ class core_admin_renderer extends plugin_renderer_base {
} else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_MISSING) {
if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) {
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'),
'badge bg-warning text-dark');
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'),
'badge bg-warning text-dark');
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge badge-warning');
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'badge badge-warning');
$class = 'requires-failed requires-missing requires-available';
$actions[] = html_writer::link(
new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $reqname)),
@@ -1569,25 +1566,24 @@ class core_admin_renderer extends plugin_renderer_base {
);
} else {
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge bg-danger text-white');
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge badge-danger');
$label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'),
'badge bg-danger text-white');
'badge badge-danger');
$class = 'requires-failed requires-missing requires-unavailable';
}
$displayuploadlink = true;
} else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OUTDATED) {
if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) {
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge bg-warning text-dark');
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'),
'badge bg-warning text-dark');
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-warning');
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'badge badge-warning');
$class = 'requires-failed requires-outdated requires-available';
$displayupdateslink = true;
} else {
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge bg-danger text-white');
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-danger');
$label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'),
'badge bg-danger text-white');
'badge badge-danger');
$class = 'requires-failed requires-outdated requires-unavailable';
}
$displayuploadlink = true;
@@ -1697,7 +1693,7 @@ class core_admin_renderer extends plugin_renderer_base {
new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 1)),
get_string('overviewupdatable', 'core_plugin'),
array('title' => get_string('filterupdatesonly', 'core_plugin'))
).' '.html_writer::span($numupdatable, 'badge bg-info text-white number number-updatable');
).' '.html_writer::span($numupdatable, 'badge badge-info number number-updatable');
} else {
// No updates, or the notifications disabled.
$infoupdatable = '';
@@ -1872,13 +1868,13 @@ class core_admin_renderer extends plugin_renderer_base {
$source = '';
} else {
$row->attributes['class'] .= ' extension';
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge bg-info text-white');
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge badge-info');
}
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge bg-danger text-white');
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge badge-danger');
} else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge bg-success text-white');
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge badge-success');
} else {
$msg = '';
}
@@ -2055,10 +2051,8 @@ class core_admin_renderer extends plugin_renderer_base {
// We are checking installed & enabled things
if ($environment_result->getLevel() == 'required') {
$stringtouse = 'environmentrequirecustomcheck';
} else if ($environment_result->getLevel() == 'optional') {
$stringtouse = 'environmentrecommendcustomcheck';
} else {
$stringtouse = 'environmentshouldfixcustomcheck';
$stringtouse = 'environmentrecommendcustomcheck';
}
} else if ($environment_result->getPart() == 'php_setting') {
@@ -2089,8 +2083,7 @@ class core_admin_renderer extends plugin_renderer_base {
if ($status) { //Handle ok result (ok)
$status = get_string('statusok');
} else {
// Handle check result (warning).
if (in_array($environment_result->getLevel(), ['optional', 'recommended'])) {
if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
$status = get_string('check');
$warningline = true;
} else { //Handle error result (error)
@@ -2120,13 +2113,13 @@ class core_admin_renderer extends plugin_renderer_base {
// Format error or warning line
if ($errorline) {
$messagetype = 'error';
$statusclass = 'bg-danger text-white';
$statusclass = 'badge-danger';
} else if ($warningline) {
$messagetype = 'warn';
$statusclass = 'bg-warning text-dark';
$statusclass = 'badge-warning';
} else {
$messagetype = 'ok';
$statusclass = 'bg-success text-white';
$statusclass = 'badge-success';
}
$status = html_writer::span($status, 'badge ' . $statusclass);
// Here we'll store all the feedback found
@@ -2210,7 +2203,7 @@ class core_admin_renderer extends plugin_renderer_base {
$out = format_text(get_string('registerwithmoodleorginfo', 'core_hub'), FORMAT_MARKDOWN);
$out .= html_writer::link(
MOODLE_PRODUCTURL.'/solutions/moodle-app/',
new moodle_url('/admin/settings.php', ['section' => 'moodleservices']),
$this->output->pix_icon('i/info', '').' '.get_string('registerwithmoodleorginfoapp', 'core_hub'),
['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
);
@@ -2260,15 +2253,4 @@ class core_admin_renderer extends plugin_renderer_base {
return $this->warning($xmlrpcwarning);
}
/**
* Renders the theme selector list.
*
* @param core_admin\output\theme_selector $themeselector
* @return string HTML
*/
public function theme_selector_list(core_admin\output\theme_selector $themeselector): string {
$renderable = $themeselector->export_for_template($this);
return $this->render_from_template('core_admin/themeselector/theme_selector', $renderable);
}
}
-13
View File
@@ -38,19 +38,6 @@ if (!is_siteadmin()) {
}
$admisselector = new core_role_admins_existing_selector();
if (array_key_exists('siteadmins', $CFG->config_php_settings)) {
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('manageadmins', 'core_role'), 3);
echo $OUTPUT->notification(get_string('siteadministratorsconfigphp', 'core_role'), \core\output\notification::NOTIFY_INFO);
echo $OUTPUT->box_start();
echo $OUTPUT->paragraph(get_string('existingadmins', 'core_role'));
$admisselector->display();
echo $OUTPUT->box_end();
echo $OUTPUT->footer();
die();
}
$potentialadmisselector = new core_role_admins_potential_selector();
if ($addusersaction) {
+3 -3
View File
@@ -99,7 +99,7 @@ abstract class core_role_allow_role_page {
* @param int $fromroleid
* @param int $targetroleid
*/
abstract protected function set_allow($fromroleid, $targetroleid);
protected abstract function set_allow($fromroleid, $targetroleid);
/**
* Load the current allows from the database.
@@ -183,11 +183,11 @@ abstract class core_role_allow_role_page {
* Snippet of text displayed above the table, telling the admin what to do.
* @return string
*/
abstract public function get_intro_text();
public abstract function get_intro_text();
/**
* Returns the allow class respective event class name.
* @return string
*/
abstract protected function get_eventclass();
protected abstract function get_eventclass();
}
@@ -142,12 +142,12 @@ abstract class core_role_capability_table_base {
/**
* For subclasses to override, output header cells, after the initial capability one.
*/
abstract protected function add_header_cells();
protected abstract function add_header_cells();
/**
* For subclasses to override, return the number of cells that add_header_cells/add_row_cells output.
*/
abstract protected function num_extra_columns();
protected abstract function num_extra_columns();
/**
* For subclasses to override. Allows certain capabilties
@@ -191,5 +191,5 @@ abstract class core_role_capability_table_base {
* @param stdClass $capability the capability this row relates to.
* @return string html of row cells
*/
abstract protected function add_row_cells($capability);
protected abstract function add_row_cells($capability);
}
@@ -84,7 +84,7 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
}
}
abstract protected function load_parent_permissions();
protected abstract function load_parent_permissions();
/**
* Update $this->permissions based on submitted data, while making a list of
@@ -156,7 +156,7 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
return $rowclasses;
}
abstract protected function add_permission_cells($capability);
protected abstract function add_permission_cells($capability);
protected function add_row_cells($capability) {
$cells = $this->add_permission_cells($capability);
@@ -645,7 +645,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
protected function print_field($name, $caption, $field, $helpicon = null) {
global $OUTPUT;
// Attempt to generate HTML like formslib.
echo '<div class="fitem row mb-3">';
echo '<div class="fitem row form-group">';
echo '<div class="fitemtitle col-md-3">';
if ($name) {
echo '<label for="' . $name . '">';
@@ -663,7 +663,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
} else {
$extraclass = '';
}
echo '<div class="felement col-md-9 d-flex flex-wrap align-items-center' . $extraclass . '">';
echo '<div class="felement col-md-9 form-inline' . $extraclass . '">';
echo $field;
if (isset($this->errors[$name])) {
echo $OUTPUT->error_text($this->errors[$name]);
+2 -2
View File
@@ -53,7 +53,7 @@ class provider implements
* @param collection $collection An object for storing metadata.
* @return collection The metadata.
*/
public static function get_metadata(collection $collection): collection {
public static function get_metadata(collection $collection) : collection {
$rolecapabilities = [
'roleid' => 'privacy:metadata:role_capabilities:roleid',
'capability' => 'privacy:metadata:role_capabilities:capability',
@@ -100,7 +100,7 @@ class provider implements
* @param int $userid The user ID.
* @return contextlist The list of context IDs.
*/
public static function get_contexts_for_userid(int $userid): contextlist {
public static function get_contexts_for_userid(int $userid) : contextlist {
global $DB;
$contextlist = new contextlist();
@@ -1,124 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\datasource;
use core\reportbuilder\local\entities\context;
use core_reportbuilder\datasource;
use core_reportbuilder\local\entities\user;
use core_role\reportbuilder\local\entities\{role, role_assignment};
/**
* Roles datasource
*
* @package core_role
* @copyright 2024 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class roles extends datasource {
/**
* Return user friendly name of the report source
*
* @return string
*/
public static function get_name(): string {
return get_string('roles', 'core_role');
}
/**
* Initialise report
*/
protected function initialise(): void {
$contextentity = new context();
$contextalias = $contextentity->get_table_alias('context');
$roleentity = new role();
$rolealias = $roleentity->get_table_alias('role');
// Role table.
$this->add_entity($roleentity->set_table_alias('context', $contextalias));
$this->set_main_table('role', $rolealias);
// Join role assignments.
$roleassignmententity = new role_assignment();
$roleassignmentalias = $roleassignmententity->get_table_alias('role_assignments');
$this->add_entity($roleassignmententity);
$this->add_join("JOIN {role_assignments} {$roleassignmentalias} ON {$roleassignmentalias}.roleid = {$rolealias}.id");
// Join context.
$this->add_entity($contextentity);
$this->add_join("LEFT JOIN {context} {$contextalias} ON {$contextalias}.id = {$roleassignmentalias}.contextid");
// Join user.
$userentity = new user();
$useralias = $userentity->get_table_alias('user');
$this->add_entity($userentity
->add_join("LEFT JOIN {user} {$useralias} ON {$useralias}.id = {$roleassignmentalias}.userid"));
$this->add_all_from_entities();
}
/**
* Return the columns that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_columns(): array {
return [
'context:link',
'role:originalname',
'user:fullnamewithlink',
];
}
/**
* Return the column sorting that will be added to the report upon creation
*
* @return int[]
*/
public function get_default_column_sorting(): array {
return [
'context:link' => SORT_ASC,
'role:originalname' => SORT_ASC,
'user:fullnamewithlink' => SORT_ASC,
];
}
/**
* Return the filters that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_filters(): array {
return [
'context:level',
'role:name',
'user:fullname',
];
}
/**
* Return the conditions that will be added to the report upon creation
*
* @return string[]
*/
public function get_default_conditions(): array {
return [];
}
}
@@ -14,8 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\local\entities;
use context;
@@ -36,14 +34,14 @@ use core_reportbuilder\local\report\{column, filter};
class role extends base {
/**
* Database tables that this entity uses
* Database tables that this entity uses and their default aliases
*
* @return string[]
* @return array
*/
protected function get_default_tables(): array {
protected function get_default_table_aliases(): array {
return [
'context',
'role',
'context' => 'rctx',
'role' => 'r',
];
}
@@ -99,13 +97,7 @@ class role extends base {
->set_type(column::TYPE_TEXT)
->add_fields("{$rolealias}.name, {$rolealias}.shortname, {$rolealias}.id, {$contextalias}.id AS contextid")
->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
->set_is_sortable(true, [
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
THEN {$rolealias}.shortname
ELSE {$rolealias}.name
END",
])
->set_is_sortable(true, ["CASE WHEN {$rolealias}.name = '' THEN {$rolealias}.shortname ELSE {$rolealias}.name END"])
->set_callback(static function($name, stdClass $role): string {
if ($name === null) {
return '';
@@ -117,30 +109,6 @@ class role extends base {
return role_get_name($role, $context, ROLENAME_BOTH);
});
// Original name column.
$columns[] = (new column(
'originalname',
new lang_string('roleoriginalname', 'core_role'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_fields("{$rolealias}.name, {$rolealias}.shortname")
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
->set_is_sortable(true, [
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
THEN {$rolealias}.shortname
ELSE {$rolealias}.name
END",
])
->set_callback(static function($name, stdClass $role): string {
if ($name === null) {
return '';
}
return role_get_name($role, null, ROLENAME_ORIGINAL);
});
// Short name column.
$columns[] = (new column(
'shortname',
@@ -1,143 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\local\entities;
use lang_string;
use core_reportbuilder\local\entities\base;
use core_reportbuilder\local\filters\date;
use core_reportbuilder\local\helpers\format;
use core_reportbuilder\local\report\{column, filter};
/**
* Role assignment entity
*
* @package core_role
* @copyright 2024 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class role_assignment extends base {
/**
* Database tables that this entity uses
*
* @return string[]
*/
protected function get_default_tables(): array {
return [
'role_assignments',
];
}
/**
* The default title for this entity
*
* @return lang_string
*/
protected function get_default_entity_title(): lang_string {
return new lang_string('roleassignment', 'core_role');
}
/**
* Initialise the entity
*
* @return base
*/
public function initialise(): base {
$columns = $this->get_all_columns();
foreach ($columns as $column) {
$this->add_column($column);
}
// All the filters defined by the entity can also be used as conditions.
$filters = $this->get_all_filters();
foreach ($filters as $filter) {
$this
->add_filter($filter)
->add_condition($filter);
}
return $this;
}
/**
* Returns list of all available columns
*
* @return column[]
*/
protected function get_all_columns(): array {
$raalias = $this->get_table_alias('role_assignments');
// Time modified column.
$columns[] = (new column(
'timemodified',
new lang_string('timemodified', 'core_reportbuilder'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TIMESTAMP)
->add_field("{$raalias}.timemodified")
->set_is_sortable(true)
->set_callback([format::class, 'userdate']);
// Component column.
$columns[] = (new column(
'component',
new lang_string('plugin'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_TEXT)
->add_field("{$raalias}.component")
->set_is_sortable(true);
// Item ID column.
$columns[] = (new column(
'itemid',
new lang_string('pluginitemid'),
$this->get_entity_name()
))
->add_joins($this->get_joins())
->set_type(column::TYPE_INTEGER)
->add_field("{$raalias}.itemid")
->set_is_sortable(true);
return $columns;
}
/**
* Return list of all available filters
*
* @return filter[]
*/
protected function get_all_filters(): array {
$raalias = $this->get_table_alias('role_assignments');
// Time modified filter.
$filters[] = (new filter(
date::class,
'timemodified',
new lang_string('timemodified', 'core_reportbuilder'),
$this->get_entity_name(),
"{$raalias}.timemodified"
))
->add_joins($this->get_joins());
return $filters;
}
}
+1 -1
View File
@@ -45,7 +45,7 @@ M.core_role.init_cap_table_filter = function(Y, tableid, contextid) {
this.table = Y.one('#'+this.tableid);
// Create a div to hold the search UI.
this.div = Y.Node.create('<div class="capabilitysearchui d-flex flex-wrap align-items-center"></div>').setStyles({
this.div = Y.Node.create('<div class="capabilitysearchui form-inline"></div>').setStyles({
width : this.table.get('offsetWidth'),
marginLeft : 'auto',
marginRight : 'auto'
+2 -2
View File
@@ -27,7 +27,7 @@ use core_role_preset;
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class preset_test extends \advanced_testcase {
public function test_xml(): void {
public function test_xml() {
global $DB;
$roles = $DB->get_records('role');
@@ -81,7 +81,7 @@ class preset_test extends \advanced_testcase {
* Tests covered method.
* @covers \core_role_preset::parse_preset
*/
public function test_mixed_levels(): void {
public function test_mixed_levels() {
// The problem here is that we cannot guarantee plugin contexts
// have unique short names, so we have to also support level numbers.
$xml = file_get_contents(__DIR__ . '/fixtures/mixed_levels.xml');
+9 -9
View File
@@ -45,7 +45,7 @@ class provider_test extends provider_testcase {
* Test to check export_user_preferences.
* returns user preferences data.
*/
public function test_export_user_preferences(): void {
public function test_export_user_preferences() {
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
@@ -64,7 +64,7 @@ class provider_test extends provider_testcase {
/**
* Check all contexts are returned if there is any user data for this user.
*/
public function test_get_contexts_for_userid(): void {
public function test_get_contexts_for_userid() {
global $DB;
$this->resetAfterTest();
@@ -114,7 +114,7 @@ class provider_test extends provider_testcase {
/**
* Test that user data is exported correctly.
*/
public function test_export_user_data(): void {
public function test_export_user_data() {
global $DB;
$this->resetAfterTest();
@@ -243,7 +243,7 @@ class provider_test extends provider_testcase {
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context(): void {
public function test_delete_data_for_all_users_in_context() {
global $DB;
$this->resetAfterTest();
@@ -329,7 +329,7 @@ class provider_test extends provider_testcase {
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user(): void {
public function test_delete_data_for_user() {
global $DB;
$this->resetAfterTest();
@@ -387,7 +387,7 @@ class provider_test extends provider_testcase {
/**
* Export for a user with a key against a script where no instance is specified.
*/
public function test_export_user_role_to_cohort(): void {
public function test_export_user_role_to_cohort() {
global $DB;
$this->resetAfterTest();
@@ -443,7 +443,7 @@ class provider_test extends provider_testcase {
/**
* Test for provider::delete_user_role_to_cohort().
*/
public function test_delete_user_role_to_cohort(): void {
public function test_delete_user_role_to_cohort() {
global $DB;
$this->resetAfterTest();
@@ -478,7 +478,7 @@ class provider_test extends provider_testcase {
/**
* Test that only users within a course context are fetched.
*/
public function test_get_users_in_context(): void {
public function test_get_users_in_context() {
global $DB;
$this->resetAfterTest();
@@ -599,7 +599,7 @@ class provider_test extends provider_testcase {
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users(): void {
public function test_delete_data_for_users() {
global $DB;
$this->resetAfterTest();
@@ -1,239 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_role\reportbuilder\datasource;
use core\context\course;
use core_reportbuilder_generator;
use core_reportbuilder_testcase;
use core_reportbuilder\local\filters\{date, select, text};
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
/**
* Unit tests for roles datasource
*
* @package core_role
* @covers \core_role\reportbuilder\datasource\roles;
* @copyright 2024 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
final class roles_test extends core_reportbuilder_testcase {
/**
* Test default datasource
*/
public function test_datasource_default(): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$context = course::instance($course->id);
$studentone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
$studenttwo = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Amy']);
$manager = $this->getDataGenerator()->create_and_enrol($course, 'manager');
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Roles', 'source' => roles::class, 'default' => 1]);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(3, $content);
// Default columns are context link, original role name and user link. Sorted by each.
[$contextlink, $rolename, $userlink] = array_values($content[0]);
$this->assertStringContainsString($context->get_context_name(), $contextlink);
$this->assertEquals('Manager', $rolename);
$this->assertStringContainsString(fullname($manager), $userlink);
[$contextlink, $rolename, $userlink] = array_values($content[1]);
$this->assertStringContainsString($context->get_context_name(), $contextlink);
$this->assertEquals('Student', $rolename);
$this->assertStringContainsString(fullname($studenttwo), $userlink);
[$contextlink, $rolename, $userlink] = array_values($content[2]);
$this->assertStringContainsString($context->get_context_name(), $contextlink);
$this->assertEquals('Student', $rolename);
$this->assertStringContainsString(fullname($studentone), $userlink);
}
/**
* Test datasource columns that aren't added by default
*/
public function test_datasource_non_default_columns(): void {
global $DB;
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$context = course::instance($course->id);
// Create an alias for our role.
$roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
$DB->insert_record('role_names', (object) [
'contextid' => $context->id,
'roleid' => $roleid,
'name' => 'Moocher',
]);
$manager = $this->getDataGenerator()->create_user();
$this->getDataGenerator()->enrol_user($manager->id, $course->id, $roleid);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
$report = $generator->create_report(['name' => 'Roles', 'source' => roles::class, 'default' => 0]);
// Role.
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:name']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:shortname']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:description']);
// Role assignment.
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role_assignment:timemodified']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role_assignment:component']);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role_assignment:itemid']);
$content = $this->get_custom_report_content($report->get('id'));
$this->assertCount(1, $content);
[$rolename, $roleshortname, $roledescription, $timemodified, $component, $itemid] = array_values($content[0]);
// Role.
$this->assertEquals('Moocher (Manager)', $rolename);
$this->assertEquals('manager', $roleshortname);
$this->assertEquals('Managers can access courses and modify them, but usually do not participate in them.',
$roledescription);
// Role assignment.
$this->assertNotEmpty($timemodified);
$this->assertEquals('', $component);
$this->assertEquals(0, $itemid);
}
/**
* Data provider for {@see test_datasource_filters}
*
* @return array[]
*/
public static function datasource_filters_provider(): array {
global $DB;
return [
// Role.
'Filter role name' => ['role:name', [
'role:name_operator' => select::EQUAL_TO,
'role:name_value' => $DB->get_field('role', 'id', ['shortname' => 'student']),
], true],
'Filter role name (no match)' => ['role:name', [
'role:name_operator' => select::EQUAL_TO,
'role:name_value' => -1,
], false],
// Role assignment.
'Filter role assignment time modified' => ['role_assignment:timemodified', [
'role_assignment:timemodified_operator' => date::DATE_RANGE,
'role_assignment:timemodified_from' => 1622502000,
], true],
'Filter role assignment time modified (no match)' => ['role_assignment:timemodified', [
'role_assignment:timemodified_operator' => date::DATE_RANGE,
'role_assignment:timemodified_to' => 1622502000,
], false],
// Context.
'Filter context level' => ['context:level', [
'context:level_operator' => select::EQUAL_TO,
'context:level_value' => CONTEXT_COURSE,
], true],
'Filter context level (no match)' => ['context:level', [
'context:level_operator' => select::EQUAL_TO,
'context:level_value' => CONTEXT_COURSECAT,
], false],
// User.
'Filter user firstname' => ['user:firstname', [
'user:firstname_operator' => text::IS_EQUAL_TO,
'user:firstname_value' => 'Zoe',
], true],
'Filter user firstname (no match)' => ['user:firstname', [
'user:firstname_operator' => text::IS_EQUAL_TO,
'user:firstname_value' => 'Amy',
], false],
];
}
/**
* Test datasource filters
*
* @param string $filtername
* @param array $filtervalues
* @param bool $expectmatch
*
* @dataProvider datasource_filters_provider
*/
public function test_datasource_filters(
string $filtername,
array $filtervalues,
bool $expectmatch,
): void {
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
/** @var core_reportbuilder_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
// Create report containing single column, and given filter.
$report = $generator->create_report(['name' => 'Roles', 'source' => roles::class, 'default' => 0]);
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:shortname']);
// Add filter, set it's values.
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
$content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
if ($expectmatch) {
$this->assertCount(1, $content);
$this->assertEquals('student', reset($content[0]));
} else {
$this->assertEmpty($content);
}
}
/**
* Stress test datasource
*
* In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
*/
public function test_stress_datasource(): void {
if (!PHPUNIT_LONGTEST) {
$this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
}
$this->resetAfterTest();
$course = $this->getDataGenerator()->create_course();
$this->getDataGenerator()->create_and_enrol($course);
$this->datasource_stress_test_columns(roles::class);
$this->datasource_stress_test_columns_aggregation(roles::class);
$this->datasource_stress_test_conditions(roles::class, 'role:shortname');
}
}
+54 -81
View File
@@ -8,6 +8,59 @@ $capabilities = array(
);
if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // speedup for non-admins, add all caps used on this page
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themes')));
// "themesettings" settingpage
$temp = new admin_settingpage('themesettings', new lang_string('themesettings', 'admin'));
$setting = new admin_setting_configtext('themelist', new lang_string('themelist', 'admin'),
new lang_string('configthemelist', 'admin'), '', PARAM_NOTAGS);
$setting->set_force_ltr(true);
$temp->add($setting);
$setting = new admin_setting_configcheckbox('themedesignermode', new lang_string('themedesignermode', 'admin'), new lang_string('configthemedesignermode', 'admin'), 0);
$setting->set_updatedcallback('theme_reset_all_caches');
$temp->add($setting);
$temp->add(new admin_setting_configcheckbox('allowuserthemes', new lang_string('allowuserthemes', 'admin'), new lang_string('configallowuserthemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowcoursethemes', new lang_string('allowcoursethemes', 'admin'), new lang_string('configallowcoursethemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowcategorythemes', new lang_string('allowcategorythemes', 'admin'), new lang_string('configallowcategorythemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowcohortthemes', new lang_string('allowcohortthemes', 'admin'), new lang_string('configallowcohortthemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowthemechangeonurl', new lang_string('allowthemechangeonurl', 'admin'), new lang_string('configallowthemechangeonurl', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'), new lang_string('configallowuserblockhiding', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('langmenuinsecurelayout',
new lang_string('langmenuinsecurelayout', 'admin'),
new lang_string('langmenuinsecurelayout_desc', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('logininfoinsecurelayout',
new lang_string('logininfoinsecurelayout', 'admin'),
new lang_string('logininfoinsecurelayout_desc', 'admin'), 0));
$temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'),
new lang_string('configcustommenuitems', 'admin'), '', PARAM_RAW, '50', '10'));
$temp->add(new admin_setting_configtextarea(
'customusermenuitems',
new lang_string('customusermenuitems', 'admin'),
new lang_string('configcustomusermenuitems', 'admin'),
'profile,moodle|/user/profile.php
grades,grades|/grade/report/mygrades.php
calendar,core_calendar|/calendar/view.php?view=month
privatefiles,moodle|/user/files.php
reports,core_reportbuilder|/reportbuilder/index.php',
PARAM_RAW,
'50',
'10'
));
$ADMIN->add('themes', $temp);
$ADMIN->add('themes', new admin_externalpage('themeselector', new lang_string('themeselector','admin'), $CFG->wwwroot . '/theme/index.php'));
// settings for each theme
foreach (core_component::get_plugin_list('theme') as $theme => $themedir) {
$settings_path = "$themedir/settings.php";
if (file_exists($settings_path)) {
$settings = new admin_settingpage('themesetting'.$theme, new lang_string('pluginname', 'theme_'.$theme));
include($settings_path);
if ($settings) {
$ADMIN->add('themes', $settings);
}
}
}
// Logos section.
$temp = new admin_settingpage('logos', new lang_string('logossettings', 'admin'));
@@ -181,6 +234,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
new lang_string('confignavcourselimit', 'admin'), 10, PARAM_INT));
$temp->add(new admin_setting_configcheckbox('usesitenameforsitepages', new lang_string('usesitenameforsitepages', 'admin'), new lang_string('configusesitenameforsitepages', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('linkadmincategories', new lang_string('linkadmincategories', 'admin'), new lang_string('linkadmincategories_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('linkcoursesections', new lang_string('linkcoursesections', 'admin'), new lang_string('linkcoursesections_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('navshowfrontpagemods', new lang_string('navshowfrontpagemods', 'admin'), new lang_string('navshowfrontpagemods_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('navadduserpostslinks', new lang_string('navadduserpostslinks', 'admin'), new lang_string('navadduserpostslinks_help', 'admin'), 1));
@@ -282,85 +336,4 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
$temp = new admin_settingpage('templates', new lang_string('templates', 'admin'));
$temp->add($setting);
$ADMIN->add('appearance', $temp);
// Advanced theme settings page.
$temp = new admin_settingpage('themesettingsadvanced', new lang_string('themesettingsadvanced', 'admin'));
$setting = new admin_setting_configtext('themelist', new lang_string('themelist', 'admin'),
new lang_string('configthemelist', 'admin'), '', PARAM_NOTAGS);
$setting->set_force_ltr(true);
$temp->add($setting);
$setting = new admin_setting_configcheckbox('themedesignermode', new lang_string('themedesignermode', 'admin'),
new lang_string('configthemedesignermode', 'admin'), 0);
$setting->set_updatedcallback('theme_reset_all_caches');
$temp->add($setting);
$setting = new admin_setting_configcheckbox('allowuserthemes', new lang_string('allowuserthemes', 'admin'),
new lang_string('configallowuserthemes', 'admin'), 0);
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
$temp->add($setting);
$setting = new admin_setting_configcheckbox('allowcoursethemes', new lang_string('allowcoursethemes', 'admin'),
new lang_string('configallowcoursethemes', 'admin'), 0);
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
$temp->add($setting);
$setting = new admin_setting_configcheckbox('allowcategorythemes', new lang_string('allowcategorythemes', 'admin'),
new lang_string('configallowcategorythemes', 'admin'), 0);
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
$temp->add($setting);
$setting = new admin_setting_configcheckbox('allowcohortthemes', new lang_string('allowcohortthemes', 'admin'),
new lang_string('configallowcohortthemes', 'admin'), 0);
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
$temp->add($setting);
$temp->add(new admin_setting_configcheckbox('allowthemechangeonurl', new lang_string('allowthemechangeonurl', 'admin'),
new lang_string('configallowthemechangeonurl', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'),
new lang_string('configallowuserblockhiding', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('langmenuinsecurelayout',
new lang_string('langmenuinsecurelayout', 'admin'),
new lang_string('langmenuinsecurelayout_desc', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('logininfoinsecurelayout',
new lang_string('logininfoinsecurelayout', 'admin'),
new lang_string('logininfoinsecurelayout_desc', 'admin'), 0));
$temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'),
new lang_string('configcustommenuitems', 'admin'), '', PARAM_RAW, '50', '10'));
$defaultsettingcustomusermenuitems = [
'profile,moodle|/user/profile.php',
'grades,grades|/grade/report/mygrades.php',
'calendar,core_calendar|/calendar/view.php?view=month',
'privatefiles,moodle|/user/files.php',
'reports,core_reportbuilder|/reportbuilder/index.php',
];
$temp->add(new admin_setting_configtextarea(
'customusermenuitems',
new lang_string('customusermenuitems', 'admin'),
new lang_string('configcustomusermenuitems', 'admin'),
implode("\n", $defaultsettingcustomusermenuitems),
PARAM_RAW,
'50',
'10'
));
$ADMIN->add('appearance', $temp);
// Theme selector page.
$ADMIN->add('appearance', new admin_externalpage('themeselector',
new lang_string('themeselector', 'admin'), $CFG->wwwroot . '/admin/themeselector.php'));
// Settings page for each theme.
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themesettingscustom', 'admin')));
foreach (core_component::get_plugin_list('theme') as $theme => $themedir) {
$settingspath = "$themedir/settings.php";
if (file_exists($settingspath)) {
$settings = new admin_settingpage("themesetting$theme", new lang_string('pluginname', "theme_$theme"),
'moodle/site:config', true
);
include($settingspath);
// Add settings if not hidden (to avoid displaying the section if it appears empty in the UI).
if ($settings && !$settings->hidden) {
$ADMIN->add('themes', $settings);
}
}
}
} // end of speedup
+2 -2
View File
@@ -727,12 +727,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
$temp = new admin_settingpage('asyncgeneralsettings', new lang_string('asyncgeneralsettings', 'backup'));
$temp->add(new admin_setting_configcheckbox('enableasyncbackup', new lang_string('enableasyncbackup', 'backup'),
new lang_string('enableasyncbackup_help', 'backup'), 1, 1, 0));
new lang_string('enableasyncbackup_help', 'backup'), 0, 1, 0));
$temp->add(new admin_setting_configcheckbox(
'backup/backup_async_message_users',
new lang_string('asyncemailenable', 'backup'),
new lang_string('asyncemailenabledetail', 'backup'), 1));
new lang_string('asyncemailenabledetail', 'backup'), 0));
$temp->hide_if('backup/backup_async_message_users', 'enableasyncbackup');
$temp->add(new admin_setting_configtext(
+23 -5
View File
@@ -74,8 +74,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
$temp->add(new admin_setting_special_gradeexport());
$temp->add(new admin_setting_special_gradeexportdefault());
$temp->add(new admin_setting_special_gradelimiting());
$temp->add(new admin_setting_configcheckbox('grade_report_showmin',
@@ -115,7 +113,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
$defaultvisible = array(GRADE_AGGREGATE_SUM);
$defaults = array('value' => GRADE_AGGREGATE_SUM, 'forced' => false);
$defaults = array('value' => GRADE_AGGREGATE_SUM, 'forced' => false, 'adv' => false);
$temp->add(new admin_setting_gradecat_combo('grade_aggregation', new lang_string('aggregation', 'grades'), new lang_string('aggregation_help', 'grades'), $defaults, $options));
$temp->add(new admin_setting_configmultiselect('grade_aggregations_visible', new lang_string('aggregationsvisible', 'grades'),
@@ -123,10 +121,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
$options = array(0 => new lang_string('no'), 1 => new lang_string('yes'));
$defaults = array('value' => 1, 'forced' => false);
$defaults = array('value'=>1, 'forced'=>false, 'adv'=>true);
$temp->add(new admin_setting_gradecat_combo('grade_aggregateonlygraded', new lang_string('aggregateonlygraded', 'grades'),
new lang_string('aggregateonlygraded_help', 'grades'), $defaults, $options));
$defaults = array('value' => 0, 'forced' => false);
$defaults = array('value'=>0, 'forced'=>false, 'adv'=>true);
$temp->add(new admin_setting_gradecat_combo('grade_aggregateoutcomes', new lang_string('aggregateoutcomes', 'grades'),
new lang_string('aggregateoutcomes_help', 'grades'), $defaults, $options));
@@ -163,6 +161,26 @@ if (has_capability('moodle/grade:manage', $systemcontext)
'3' => '3',
'4' => '4',
'5' => '5')));
$temp->add(new admin_setting_configmultiselect('grade_item_advanced', new lang_string('gradeitemadvanced', 'grades'), new lang_string('gradeitemadvanced_help', 'grades'),
array('iteminfo', 'idnumber', 'gradepass', 'plusfactor', 'multfactor', 'display', 'decimals', 'hiddenuntil', 'locktime'),
array('iteminfo' => new lang_string('iteminfo', 'grades'),
'idnumber' => new lang_string('idnumbermod'),
'gradetype' => new lang_string('gradetype', 'grades'),
'scaleid' => new lang_string('scale'),
'grademin' => new lang_string('grademin', 'grades'),
'grademax' => new lang_string('grademax', 'grades'),
'gradepass' => new lang_string('gradepass', 'grades'),
'plusfactor' => new lang_string('plusfactor', 'grades'),
'multfactor' => new lang_string('multfactor', 'grades'),
'display' => new lang_string('gradedisplaytype', 'grades'),
'decimals' => new lang_string('decimalpoints', 'grades'),
'hidden' => new lang_string('hidden', 'grades'),
'hiddenuntil' => new lang_string('hiddenuntil', 'grades'),
'locked' => new lang_string('locked', 'grades'),
'locktime' => new lang_string('locktime', 'grades'),
'aggregationcoef' => new lang_string('aggregationcoef', 'grades'),
'parentcategory' => new lang_string('parentcategory', 'grades'))));
}
$ADMIN->add('grades', $temp);
-14
View File
@@ -41,18 +41,4 @@ if (!empty($defaulth5plib)) {
$settings->add(new admin_settings_h5plib_handler_select('h5plibraryhandler', new lang_string('h5plibraryhandler', 'core_h5p'),
new lang_string('h5plibraryhandler_help', 'core_h5p'), $defaulth5plib));
$setting = new admin_setting_configtextarea(
'core_h5p/h5pcustomcss',
new lang_string('h5pcustomcss', 'core_h5p'),
new lang_string('h5pcustomcss_help', 'core_h5p'),
'',
PARAM_NOTAGS
);
$setting->set_updatedcallback(function () {
// Enables use of file_storage constants.
\core_h5p\local\library\autoloader::register();
\core_h5p\file_storage::generate_custom_styles();
});
$settings->add($setting);
}
+53
View File
@@ -0,0 +1,53 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file gives information about Moodle Services
*
* @package core
* @copyright 2018 Amaia Anabitarte <amaia@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
// Create Moodle Services information.
$moodleservices->add(new admin_setting_heading('moodleservicesintro', '',
new lang_string('moodleservices_help', 'admin')));
// Moodle Partners information.
if (empty($CFG->disableserviceads_partner)) {
$moodleservices->add(new admin_setting_heading('moodlepartners',
new lang_string('moodlepartners', 'admin'),
new lang_string('moodlepartners_help', 'admin')));
}
// Moodle app information.
$moodleservices->add(new admin_setting_heading('moodleapp',
new lang_string('moodleapp', 'admin'),
new lang_string('moodleapp_help', 'admin')));
// Branded Moodle app information.
if (empty($CFG->disableserviceads_branded)) {
$moodleservices->add(new admin_setting_heading('moodlebrandedapp',
new lang_string('moodlebrandedapp', 'admin'),
new lang_string('moodlebrandedapp_help', 'admin')));
}
}
-16
View File
@@ -135,18 +135,6 @@ if ($hassiteconfig) {
$temp->add($setting);
$ADMIN->add('authsettings', $temp);
// Toggle password visiblity icon.
$temp->add(new admin_setting_configselect('loginpasswordtoggle',
new lang_string('auth_loginpasswordtoggle', 'auth'),
new lang_string('auth_loginpasswordtoggle_desc', 'auth'),
TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY,
[
TOGGLE_SENSITIVE_DISABLED => get_string('disabled', 'admin'),
TOGGLE_SENSITIVE_ENABLED => get_string('enabled', 'admin'),
TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY => get_string('smallscreensonly', 'admin'),
],
));
$temp = new admin_externalpage('authtestsettings', get_string('testsettings', 'core_auth'), new moodle_url("/auth/test_settings.php"), 'moodle/site:config', true);
$ADMIN->add('authsettings', $temp);
@@ -196,10 +184,6 @@ if ($hassiteconfig) {
$temp = new admin_settingpage('manageantiviruses', new lang_string('antivirussettings', 'antivirus'));
$temp->add(new admin_setting_manageantiviruses());
// Status check.
$temp->add(new admin_setting_heading('antivirus/statuschecks', new lang_string('statuschecks'), ''));
$temp->add(new admin_setting_check('antivirus/checkantivirus', new \core\check\environment\antivirus()));
// Common settings.
$temp->add(new admin_setting_heading('antiviruscommonsettings', new lang_string('antiviruscommonsettings', 'antivirus'), ''));
+1 -3
View File
@@ -152,9 +152,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$sensiblesettingsdefault .= 'server_password@@search_solr, ssl_keypassword@@search_solr, ';
$sensiblesettingsdefault .= 'alternateserver_password@@search_solr, alternatessl_keypassword@@search_solr, ';
$sensiblesettingsdefault .= 'test_password@@cachestore_redis, password@@mlbackend_python, ';
$sensiblesettingsdefault .= 'badges_badgesalt@@none, calendar_exportsalt@@none, ';
$sensiblesettingsdefault .= 'bigbluebuttonbn_shared_secret@@none, apikey@@tiny_premium, ';
$sensiblesettingsdefault .= 'matrixaccesstoken@@communication_matrix, api_secret@@factor_sms';
$sensiblesettingsdefault .= 'badges_badgesalt@@none, calendar_exportsalt@@none';
$temp->add(new admin_setting_configtextarea('adminpresets/sensiblesettings',
get_string('sensiblesettings', 'core_adminpresets'),
get_string('sensiblesettingstext', 'core_adminpresets'),
-11
View File
@@ -390,17 +390,6 @@ if ($hassiteconfig) {
30 * MINSECS
)
);
$temp->add(
new admin_setting_configduration(
'task_adhoc_failed_retention',
new lang_string('task_adhoc_failed_retention', 'admin'),
new lang_string('task_adhoc_failed_retention_desc', 'admin'),
\core\task\manager::ADHOC_TASK_FAILED_RETENTION,
WEEKSECS
)
);
$ADMIN->add('taskconfig', $temp);
// Task log configuration.
+6
View File
@@ -14,6 +14,12 @@ $ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_str
new moodle_url("/admin/registration/index.php")));
// hidden upgrade script
$ADMIN->add('root', new admin_externalpage('upgradesettings', new lang_string('upgradesettings', 'admin'), "$CFG->wwwroot/$CFG->admin/upgradesettings.php", 'moodle/site:config', true));
// Adding Moodle Services information page.
$moodleservices = new admin_settingpage('moodleservices', new lang_string('moodleservices',
'admin'));
$ADMIN->add('root', $moodleservices);
$userfeedback = new admin_settingpage('userfeedback', new lang_string('feedbacksettings', 'admin'));
$ADMIN->add('root', $userfeedback);
+1 -1
View File
@@ -26,7 +26,7 @@
}
}}
<div class="simplesearchform d-flex justify-content-end">
<form autocomplete="off" action="{{action}}" method="get" accept-charset="utf-8" class="mform d-flex flex-wrap align-items-center simplesearchform">
<form autocomplete="off" action="{{action}}" method="get" accept-charset="utf-8" class="mform form-inline simplesearchform">
<div class="input-group">
<label for="searchinput-{{uniqid}}">
<span class="sr-only">{{#str}} search, core {{/str}}</span>
@@ -38,6 +38,6 @@
}
}}
<div class="form-checkbox defaultsnext">
{{^readonly}}<input type="hidden" name="{{name}}" value="{{no}}">{{/readonly}}
<input type="hidden" name="{{name}}" value="{{no}}">
<input {{#readonly}}disabled{{/readonly}} type="checkbox" name="{{name}}" value="{{value}}" id="{{id}}" {{#checked}}checked{{/checked}}>
</div>
@@ -39,7 +39,7 @@
Setting configduration.
}}
<div class="form-duration defaultsnext">
<div class="d-flex flex-wrap align-items-center">
<div class="form-inline">
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
<label class="sr-only" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
<select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
+1 -1
View File
@@ -44,7 +44,7 @@
Setting configfile.
}}
<div class="form-file defaultsnext">
<div class="d-flex flex-wrap align-items-center">
<div class="form-inline">
<input type="text" name="{{name}}" id="{{id}}" size="{{size}}" value="{{value}}" class="form-control text-ltr" {{#readonly}}readonly{{/readonly}}>
{{#showvalidity}}
{{#valid}}
@@ -39,7 +39,7 @@
Setting configfilesize.
}}
<div class="form-filesize defaultsnext">
<div class="d-flex flex-wrap align-items-center">
<div class="form-inline">
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
<label class="sr-only" for="{{id}}u">{{#str}}filesizeunits, admin{{/str}}</label>
<select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
@@ -35,7 +35,7 @@
}
}}
<div class="form-multicheckbox">
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
<input type="hidden" name="{{name}}[xxxxx]" value="1">
{{#hasoptions}}
<ul>
{{#options}}
@@ -40,7 +40,7 @@
Setting configmultiselect.
}}
<div class="form-select">
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
<input type="hidden" name="{{name}}[xxxxx]" value="1">
<select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
{{#options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
@@ -59,7 +59,7 @@
Setting configmultiselect with optgroup support.
}}
<div class="form-select">
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
<input type="hidden" name="{{name}}[xxxxx]" value="1">
<select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
{{#options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
+2 -11
View File
@@ -27,8 +27,6 @@
* forceltr - always display as ltr
* attributes - list of additional attributes containing name, value
* readonly - bool
* data - list of arbitrary data attributes
* maxcharacter - maximum character
Example context (json):
{
@@ -38,19 +36,12 @@
"size": "21",
"forceltr": false,
"readonly": false,
"attributes": [ { "name": "readonly", "value": "readonly" } ],
"data": [ { "key": "validation_max_length", "value": "10" } ],
"maxcharacter": false
"attributes": [ { "name": "readonly", "value": "readonly" } ]
}
}}
{{!
Setting configtext.
}}
<div class="form-text defaultsnext">
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}} {{#data}} data-{{key}}={{#quote}}{{{value}}}{{/quote}}{{/data}}>
{{#data}}
{{#maxcharacter}}
<div class="form-defaultinfo text-muted d-block">{{#str}} maxcharacter, admin, {{value}} {{/str}}</div>
{{/maxcharacter}}
{{/data}}
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}}>
</div>
+1 -1
View File
@@ -45,7 +45,7 @@
Setting configtime.
}}
<div class="form-time defaultsnext">
<div class="d-flex flex-wrap align-items-center text-ltr">
<div class="form-inline text-ltr">
<label class="sr-only" for="{{id}}h">{{#str}}hours{{/str}}</label>
<select id="{{id}}h" name="{{name}}[h]" class="custom-select" {{#readonly}}disabled{{/readonly}}>
{{#hours}}
@@ -40,9 +40,9 @@
{{!
Setting courselist_frontpage.
}}
<div class="mb-3">
<div class="form-group">
{{#selects}}
<select id="{{id}}{{key}}" name="{{name}}[]" class="custom-select mb-1">
<select id="{{id}}{{key}}" name="{{name}}[]" class="custom-select">
{{#options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
{{/options}}
+1 -1
View File
@@ -35,7 +35,7 @@
{{!
Setting emoticons.
}}
<div class="mb-3">
<div class="form-group">
<table id="emoticonsetting" class="admintable generaltable">
<thead>
<tr>
@@ -24,6 +24,7 @@
* id - element id
* options - list of options containing name, value and selected
* forced - is it forced
* advanced - is it advanced
Example context (json):
{
@@ -32,13 +33,14 @@
"options": [
{ "name": "Option name", "value": "Value", "selected": true }
],
"forced": true
"forced": true,
"advanced": true
}
}}
{{!
Setting configselect.
}}
<div class="mb-3">
<div class="form-group">
<select id="{{id}}" name="{{name}}[value]" class="form-select custom-select">
{{#options}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
@@ -46,5 +48,7 @@
</select>
<input type="checkbox" id="{{id}}force" name="{{name}}[forced]" value="1" {{#forced}}checked{{/forced}}>
<label for="{{id}}force">{{#str}}force{{/str}}</label>
<input type="checkbox" id="{{id}}adv" name="{{name}}[adv]" value="1" {{#advanced}}checked{{/advanced}}>
<label for="{{id}}adv">{{#str}}advanced{{/str}}</label>
</div>
+34
View File
@@ -0,0 +1,34 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_admin/tasklogs
This is the template for the search form which appears above the task logs report.
}}
<form class="form-inline" method="GET" action="{{{action}}}">
<label class="sr-only" for="tasklog-filter">{{#str}}filter{{/str}}</label>
<input class="form-control" type="text" id="tasklog-filter" name="filter" value="{{{filter}}}">
<label class="sr-only" for="tasklog-resultfilter">{{#str}}resultfilter, admin{{/str}}</label>
<select class="form-control custom-select" name="result" id="tasklog-resultfilter">
{{#resultfilteroptions}}
<option value="{{{value}}}"{{#selected}} selected="selected"{{/selected}}>{{title}}</option>
{{/resultfilteroptions}}
</select>
<input class="btn btn-primary" type="submit" value="{{#str}}filter{{/str}}">
</form>
@@ -1,101 +0,0 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_admin/themeselector/theme_card
This template renders the singular card for a theme.
Example context (json):
{
"name": "Boost",
"choose": "boost",
"image": "http://moodlesite/theme/image.php?theme=boost&image=screenshot&component=theme",
"current": true,
"actionurl": "http://moodlesite/admin/themeselector.php",
"sesskey": "123XYZ",
"settingsurl": "http://moodlesite/admin/settings.php?section=themesettingboost",
"reporturl": "http://moodlesite/report/themeusage/index.php?themechoice=boost"
}
}}
<div class="card theme-card" role="listitem" id="theme-card-{{choose}}" aria-labelledby="theme-name-{{choose}} {{#current}}current-theme-{{choose}}{{/current}}">
<div class="card-img card-img-top" style='background-image: url("{{image}}");'></div>
<div class="card-body p-3">
<div class="d-flex">
<div class="flex-grow-1">
<h3 class="h5" id="theme-name-{{choose}}">{{name}}</h3>
</div>
<div>
<button
type="button"
id="theme-preview-{{choose}}"
class="btn btn-link p-0"
title="{{#str}}previewthemename, moodle, {{name}}{{/str}}"
data-action="preview"
data-name="{{name}}"
data-image="{{image}}"
data-current="{{current}}"
data-actionurl="{{actionurl}}"
data-choose="{{choose}}"
data-sesskey="{{sesskey}}">
<i class="icon fa fa-info-circle m-0" aria-hidden="true"></i>
<span class="sr-only">{{#str}}previewthemename, moodle, {{name}}{{/str}}</span>
</button>
{{#reporturl}}
<a
href="{{reporturl}}"
id="theme-usage-report-{{choose}}"
class="btn btn-link p-0 ml-2"
title="{{#str}}themeusagereportname, admin, {{name}}{{/str}}">
<i class="icon fa fa-area-chart m-0" aria-hidden="true"></i>
<span class="sr-only">{{#str}}themeusagereportname, admin, {{name}}{{/str}}</span>
</a>
{{/reporturl}}
{{#settingsurl}}
<a
href="{{settingsurl}}"
id="theme-settings-{{choose}}"
class="btn btn-link p-0 ml-2"
title="{{#str}}themeeditsettingsname, admin, {{name}}{{/str}}">
<i class="icon fa fa-cog m-0" aria-hidden="true"></i>
<span class="sr-only">{{#str}}themeeditsettingsname, admin, {{name}}{{/str}}</span>
</a>
{{/settingsurl}}
</div>
</div>
</div>
<div class="d-flex align-items-end flex-column p-3">
{{#current}}
<strong><span class="text-success" id="current-theme-{{choose}}">{{#str}}currenttheme, moodle{{/str}}</span></strong>
{{#definedinconfig}}
<div class="alert alert-info p-1">{{#str}}configoverride, admin{{/str}}</div>
{{/definedinconfig}}
{{/current}}
{{^current}}
{{#actionurl}}
<form method="post" action="{{actionurl}}" id="theme-select-form-{{choose}}">
<input type="hidden" name="sesskey" value="{{sesskey}}">
<input type="hidden" name="choose" value="{{choose}}">
<button type="submit" class="btn btn-primary">
<span aria-hidden="true">{{#str}}selecttheme, moodle{{/str}}</span>
<span class="sr-only">{{#str}}selectthemename, moodle, {{name}}{{/str}}</span>
</button>
</form>
{{/actionurl}}
{{/current}}
</div>
</div>
@@ -1,58 +0,0 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_admin/themeselector/theme_preview_modal
This template renders the modal for the selected theme.
Example context (json):
{
"name": "Boost",
"choose": "boost",
"image": "http://moodlesite/theme/image.php?theme=boost&image=screenshot&component=theme",
"description": "Boost is a modern highly-customisable theme...",
"current": true,
"actionurl": "http://moodlesite/admin/themeselector.php",
"sesskey": "123XYZ"
}
}}
<div>
<div>
<img
src="{{image}}"
alt=""
id="modal-theme-preview-{{choose}}"
class="w-100 mb-3">
</div>
<div class="d-flex">
<div class="flex-grow-1">
<p><strong>{{#str}}themepreviewdescription, moodle, {{name}}{{/str}}</strong></p>
</div>
<div class="d-flex align-items-end flex-column">
{{#current}}
<strong><span class="text-success">{{#str}}currenttheme, moodle{{/str}}</span></strong>
{{#definedinconfig}}
<div class="alert alert-info p-1">{{#str}}configoverride, admin{{/str}}</div>
{{/definedinconfig}}
{{/current}}
</div>
</div>
<p>{{description}}</p>
{{#actionurl}}
<form method="post" action="{{actionurl}}" id="modal-theme-select-form-{{choose}}">
<input type="hidden" name="sesskey" value="{{sesskey}}">
<input type="hidden" name="choose" value="{{choose}}">
</form>
{{/actionurl}}
</div>
@@ -1,77 +0,0 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_admin/themeselector/theme_selector
This template renders the cards view for choosing a theme.
Example context (json):
{
"themes": [
{
"name": "Boost",
"choose": "boost",
"image": "http://moodlesite/theme/image.php?theme=boost&image=screenshot&component=theme",
"current": true,
"actionurl": "http://moodlesite/admin/themeselector.php",
"sesskey": "123XYZ"
},
{
"name": "Classic",
"choose": "classic",
"image": "http://moodlesite/theme/image.php?theme=classic&image=screenshot&component=theme",
"actionurl": "http://moodlesite/admin/themeselector.php",
"sesskey": "123XYZ"
}
],
"resetbutton": {
"id": "single_button123",
"method": "post",
"url": "index.php",
"label": "Clear theme caches",
"params": [
{
"name": "sesskey",
"value": "123XYZ"
},
{
"name": "reset",
"value": "1"
}
]
}
}
}}
<h2>{{#str}}themeselector, admin{{/str}}</h2>
{{#resetbutton}}
<div class="mb-3">
{{>core/single_button}}
</div>
{{/resetbutton}}
<div class="card-grid row row-cols-1 row-cols-md-3 mx-0" id="themelist" data-region="card-deck" role="list" data-definedinconfig="{{definedinconfig}}">
{{#themes}}
<div class="col d-flex px-1 mb-2">
{{>core_admin/themeselector/theme_card}}
</div>
{{/themes}}
</div>
{{#js}}
require(['core_admin/themeselector/preview_modal'], function(Modal) {
Modal.init();
});
{{/js}}
+1
View File
@@ -75,6 +75,7 @@ class behat_admin extends behat_base {
// Multi element settings, interacting only the first one.
$fieldxpath = "//*[label[contains(., $label)]|span[contains(., $label)]]" .
"/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
"/descendant::div[contains(concat(' ', @class, ' '), ' form-group ')]" .
"/descendant::*[self::input | self::textarea | self::select]" .
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
}
+13 -177
View File
@@ -1,4 +1,4 @@
@core @core_admin @core_reportbuilder
@core @core_admin
Feature: An administrator can browse user accounts
In order to find the user accounts I am looking for
As an admin
@@ -17,24 +17,24 @@ Feature: An administrator can browse user accounts
Scenario: User accounts display default fields
When I navigate to "Users > Accounts > Browse list of users" in site administration
# Name field always present, email field is default for showidentity.
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
Then the following should exist in the "users" table:
| First name / Last name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
# Should not see other identity fields or non-default name fields.
And I should not see "Department" in the "reportbuilder-table" "table"
And I should not see "Attack" in the "reportbuilder-table" "table"
And I should not see "Favourite frog" in the "reportbuilder-table" "table"
And I should not see "Kermit" in the "reportbuilder-table" "table"
And I should not see "First name - phonetic" in the "reportbuilder-table" "table"
And I should not see "Yoozare" in the "reportbuilder-table" "table"
And I should not see "Department" in the "table" "css_element"
And I should not see "Attack"
And I should not see "Favourite frog" in the "table" "css_element"
And I should not see "Kermit"
And I should not see "First name - phonetic" in the "table" "css_element"
And I should not see "Yoozare"
Scenario: User accounts with extra name fields
Given the following config values are set as admin:
| alternativefullnameformat | firstnamephonetic lastname |
When I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name - phonetic | Email address |
Then the following should exist in the "users" table:
| First name - phonetic / Last name | Email address |
| Yewzer One | one@example.com |
| Yoozare Two | two@example.com |
@@ -42,14 +42,13 @@ Feature: An administrator can browse user accounts
Given the following config values are set as admin:
| showuseridentity | department,profile_field_frog |
When I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Favourite frog | Department |
Then the following should exist in the "users" table:
| First name / Last name | Favourite frog | Department |
| User One | Kermit | Attack |
| User Two | Tree | Defence |
And I should not see "Email address" in the "table" "css_element"
And I should not see "one@example.com"
@javascript
Scenario: Sort user accounts by custom profile field
Given the following config values are set as admin:
| showuseridentity | profile_field_frog |
@@ -58,166 +57,3 @@ Feature: An administrator can browse user accounts
Then "Kermit" "text" should appear before "Tree" "text"
And I follow "Favourite frog"
Then "Tree" "text" should appear before "Kermi" "text"
@javascript
Scenario: Edit user information
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Edit" action in the "User One" report row
And I set the field "Last name" to "OneOne"
And I press "Update profile"
Then I should see "User OneOne"
@javascript
Scenario: Suspend and activate user account
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Suspend user account" action in the "User One" report row
And I should see "Suspended" in the "User One" "table_row"
And I press "Activate user account" action in the "User One" report row
Then I should not see "Suspended" in the "User One" "table_row"
@javascript
Scenario: Delete a user account
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I press "Delete" action in the "User One" report row
And I should see "Are you absolutely sure you want to completely delete the user User One" in the "Delete user" "dialogue"
And I click on "Delete" "button" in the "Delete user" "dialogue"
Then I should see "Deleted user User One"
And I should not see "User One" in the "reportbuilder-table" "table"
@javascript
Scenario: Resend email and confirm a user account
Given the following "users" exist:
| username | firstname | lastname | email | confirmed |
| user3 | User | Three | three@example.com | 0 |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "Confirmation pending" in the "User Three" "table_row"
And I press "Resend confirmation email" action in the "User Three" report row
And I should see "Confirmation email sent successfully"
And I press "Confirm" action in the "User Three" report row
And I should not see "Confirmation pending" in the "User Three" "table_row"
@javascript
Scenario: User report filters
Given the following "users" exist:
| username | firstname | lastname | email | profile_field_frog |
| user3 | User | Three | three@example.com | Glass |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
| User Three | three@example.com |
And I click on "Filters" "button"
And I set the following fields in the "Last name" "core_reportbuilder > Filter" to these values:
| Last name operator | Is equal to |
| Last name value | Three |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
| Favourite frog operator | Is equal to |
| Favourite frog value | Kermit |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
@javascript
Scenario: User report enrolled in any course filter
Given the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user2 | C1 | student |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
And I click on "Filters" "button"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | Yes |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
@javascript
Scenario: User report system role and course role filters
Given the following "users" exist:
| username | firstname | lastname | email |
| user3 | User | Three | three@example.com |
And the following "courses" exist:
| shortname | fullname |
| C1 | Course 1 |
And the following "course enrolments" exist:
| user | course | role |
| user1 | C1 | student |
| user2 | C1 | editingteacher |
| user3 | C1 | student |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| user1 | coursecreator | system | |
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then the following should exist in the "reportbuilder-table" table:
| First name | Email address |
| User One | one@example.com |
| User Two | two@example.com |
| User Three | three@example.com |
And I click on "Filters" "button"
And I set the following fields in the "System role" "core_reportbuilder > Filter" to these values:
| System role operator | Is equal to |
| System role value | Course creator |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I click on "Filters" "button"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
| Role name | Teacher |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I click on "Filters" "button"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
Scenario: Add a new user
Given I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "Add a new user" "link"
Then I should see "Username"
And I should see "User picture"
And I should see "Additional names"
@javascript
Scenario: Browse user list as a person with limited capabilities
Given the following "users" exist:
| username | firstname | lastname | email |
| manager | Max | Manager | manager@example.com |
And the following "roles" exist:
| name | shortname | description | archetype |
| Custom manager | custom1 | My custom role 1 | |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| moodle/site:configview | Allow | custom1 | System | |
| moodle/user:update | Allow | custom1 | System | |
And the following "role assigns" exist:
| user | role | contextlevel | reference |
| manager | custom1 | System | |
When I log in as "manager"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "User One" "checkbox"
And the "Bulk user actions" select box should contain "Confirm"
And the "Bulk user actions" select box should not contain "Delete"
And I set the field "Bulk user actions" to "Force password change"
And I should see "Are you absolutely sure you want to force a password change to User One ?"
And I press "Yes"
And I press "Continue"
And I should see "Browse list of users"
+96 -137
View File
@@ -1,4 +1,4 @@
@core @core_admin @core_reportbuilder
@core @core_admin
Feature: An administrator can filter user accounts by role, cohort and other profile fields
In order to find the user accounts I am looking for
As an admin
@@ -33,150 +33,109 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
@javascript
Scenario: Filter user accounts by role and cohort
When I click on "Filters" "button"
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
| Role name | Student |
| Course short name | C1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Cohort ID" "core_reportbuilder > Filter" to these values:
| Cohort ID operator | Is equal to |
| Cohort ID value | CH1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
When I set the following fields to these values:
| courserole_rl | Student |
| courserole_ct | any category |
| courserole | C1 |
And I press "Add filter"
Then I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should not see "User Four"
And I set the following fields to these values:
| cohort | CH1 |
And I press "Add filter"
And I should not see "User One"
And I should see "User Two"
And I should see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should see "User Four"
@javascript
Scenario: Filter user accounts by confirm and authentication method
When I click on "Filters" "button"
And I set the following fields in the "Confirmed" "core_reportbuilder > Filter" to these values:
| Confirmed operator | No |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Authentication" "core_reportbuilder > Filter" to these values:
| Authentication operator | Is equal to |
| Authentication value | Manual accounts |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
When I set the following fields to these values:
| Confirmed | No |
And I press "Add filter"
Then I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should see "User Four"
And I set the following fields to these values:
| Authentication | manual |
And I press "Add filter"
And I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should not see "User Four"
@javascript
Scenario: Filter user accounts by enrolled in any course
When I click on "Filters" "button"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | Yes |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
| Enrolled in any course operator | No |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
When I set the following fields to these values:
| id_anycourses | Yes |
And I press "Add filter"
Then I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I set the following fields to these values:
| id_anycourses | No |
And I press "Add filter"
And I should not see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should see "User Four"
@javascript
Scenario: Filter user accounts by last IP address
When I click on "Filters" "button"
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
| Last IP address operator | Is equal to |
| Last IP address value | 127.0.1.1 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
| Last IP address operator | Is equal to |
| Last IP address value | 127.0.1.2 |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should see "User Three" in the "reportbuilder-table" "table"
And I should see "User Four" in the "reportbuilder-table" "table"
When I set the following fields to these values:
| id_lastip | 127.0.1.1 |
And I press "Add filter"
Then I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I set the following fields to these values:
| id_lastip | 127.0.1.2 |
And I press "Add filter"
And I should not see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should see "User Four"
And I press "Remove all filters"
And I should see "User One"
And I should see "User Two"
And I should see "User Three"
And I should see "User Four"
@javascript
Scenario: Filter users by institution and department
When I click on "Filters" "button"
And I set the following fields in the "Institution" "core_reportbuilder > Filter" to these values:
| Institution operator | Is equal to |
| Institution value | moodle |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I set the following fields in the "Department" "core_reportbuilder > Filter" to these values:
| Department operator | Is equal to |
| Department value | red |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
When I set the field "id_institution" to "moodle"
And I press "Add filter"
Then I should see "User One"
And I should see "User Two"
And I should not see "User Three"
And I should not see "User Four"
And I set the field "id_department" to "red"
And I press "Add filter"
And I should see "User One"
And I should not see "User Two"
@javascript
Scenario: Filter users by custom profile field (specific or any)
When I click on "Filters" "button"
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
| Favourite frog operator | Is equal to |
| Favourite frog value | Kermit |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Type of undead" "core_reportbuilder > Filter" to these values:
| Type of undead operator | Is equal to |
| Type of undead value | Zombie |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
@javascript
Scenario: Filter users by full name
When I click on "Filters" "button"
And I set the following fields in the "Full name" "core_reportbuilder > Filter" to these values:
| Full name operator | Is equal to |
| Full name value | User One |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "User One" in the "reportbuilder-table" "table"
And I should not see "User Two" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I set the following fields in the "Full name" "core_reportbuilder > Filter" to these values:
| Full name operator | Is equal to |
| Full name value | User Two |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
And I should see "User Two" in the "reportbuilder-table" "table"
And I should not see "User One" in the "reportbuilder-table" "table"
And I should not see "User Three" in the "reportbuilder-table" "table"
And I should not see "User Four" in the "reportbuilder-table" "table"
When I set the field "id_profile_fld" to "Favourite frog"
And I set the field "id_profile" to "Kermit"
And I press "Add filter"
Then I should see "User One"
And I should not see "User Two"
And I should not see "User Three"
And I should not see "User Four"
And I press "Remove all filters"
And I set the field "id_profile_fld" to "any field"
And I set the field "id_profile" to "Zombie"
And I press "Add filter"
And I should see "User Two"
And I should not see "User One"
And I should not see "User Three"
And I should not see "User Four"
@@ -0,0 +1,150 @@
@core @core_admin @javascript
Feature: An administrator can configure the available user list filters
In order to have all needed user filters instantly at hand
As an admin
I want to configure the filters which are shown as default
Scenario: Do not change the user filter default configuration
When I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
Scenario: Change the user filter default configuration to something else
Given the following config values are set as admin:
| userfiltersdefault | realname,username,email |
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should see "Username" in the "New filter" "fieldset"
And I should see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should see "Username" in the "New filter" "fieldset"
And I should see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
Scenario: Change the user filter default configuration to no filter at all
Given the following config values are set as admin:
| userfiltersdefault | |
And I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
And I navigate to "Users > Accounts > Bulk user actions" in site administration
Then I should see "User full name"
And I should not see "Last name" in the "New filter" "fieldset"
And I should not see "Firstname" in the "New filter" "fieldset"
And I should not see "Username" in the "New filter" "fieldset"
And I should not see "Email address" in the "New filter" "fieldset"
And I should not see "City/town" in the "New filter" "fieldset"
And I should not see "Country" in the "New filter" "fieldset"
And I should not see "Confirmed" in the "New filter" "fieldset"
And I should not see "Suspended account" in the "New filter" "fieldset"
And I should not see "User profile fields" in the "New filter" "fieldset"
And I should not see "Course role" in the "New filter" "fieldset"
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
And I should not see "System role" in the "New filter" "fieldset"
And I should not see "Cohort ID" in the "New filter" "fieldset"
And I should not see "First access" in the "New filter" "fieldset"
And I should not see "Last access" in the "New filter" "fieldset"
And I should not see "Last modified" in the "New filter" "fieldset"
And I should not see "Authentication" in the "New filter" "fieldset"
And I should not see "ID number" in the "New filter" "fieldset"
And I should not see "Last IP address" in the "New filter" "fieldset"
And I should not see "MNet ID provider" in the "New filter" "fieldset"
+55 -55
View File
@@ -7,35 +7,35 @@ Feature: Reset course indentation
Background:
Given the following "courses" exist:
| fullname | shortname | format |
| Sections Course 1 | T1 | topics |
| Sections Course 2 | T2 | topics |
| Topics Course 1 | T1 | topics |
| Topics Course 2 | T2 | topics |
| Weekly Course 1 | W1 | weeks |
| Weekly Course 2 | W2 | weeks |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| forum | Sections forum name | Sections forum description | T1 | forum1 |
| data | Sections database name | Sections database description | T1 | data1 |
| wiki | Sections wiki name | Sections wiki description | T2 | wiki1 |
| forum | Weekly forum name | Weekly forum description | W1 | forum2 |
| data | Weekly database name | Weekly database description | W1 | data2 |
| wiki | Weekly wiki name | Weekly wiki description | W2 | wiki2 |
| activity | name | intro | course | idnumber |
| forum | Topics forum name | Topics forum description | T1 | forum1 |
| data | Topics database name | Topics database description | T1 | data1 |
| wiki | Topics wiki name | Topics wiki description | T2 | wiki1 |
| forum | Weekly forum name | Weekly forum description | W1 | forum2 |
| data | Weekly database name | Weekly database description | W1 | data2 |
| wiki | Weekly wiki name | Weekly wiki description | W2 | wiki2 |
And I log in as "admin"
And I am on "Sections Course 1" course homepage with editing mode on
And I open "Sections forum name" actions menu
And I click on "Move right" "link" in the "Sections forum name" activity
And I open "Sections forum name" actions menu
And "Move right" "link" in the "Sections forum name" "activity" should not be visible
And "Move left" "link" in the "Sections forum name" "activity" should be visible
And I am on "Topics Course 1" course homepage with editing mode on
And I open "Topics forum name" actions menu
And I click on "Move right" "link" in the "Topics forum name" activity
And I open "Topics forum name" actions menu
And "Move right" "link" in the "Topics forum name" "activity" should not be visible
And "Move left" "link" in the "Topics forum name" "activity" should be visible
And I press the escape key
And I open "Sections database name" actions menu
And "Move right" "link" in the "Sections database name" "activity" should be visible
And "Move left" "link" in the "Sections database name" "activity" should not be visible
And I am on "Sections Course 2" course homepage with editing mode on
And I open "Sections wiki name" actions menu
And I click on "Move right" "link" in the "Sections wiki name" activity
And I open "Sections wiki name" actions menu
And "Move right" "link" in the "Sections wiki name" "activity" should not be visible
And "Move left" "link" in the "Sections wiki name" "activity" should be visible
And I open "Topics database name" actions menu
And "Move right" "link" in the "Topics database name" "activity" should be visible
And "Move left" "link" in the "Topics database name" "activity" should not be visible
And I am on "Topics Course 2" course homepage with editing mode on
And I open "Topics wiki name" actions menu
And I click on "Move right" "link" in the "Topics wiki name" activity
And I open "Topics wiki name" actions menu
And "Move right" "link" in the "Topics wiki name" "activity" should not be visible
And "Move left" "link" in the "Topics wiki name" "activity" should be visible
And I am on "Weekly Course 1" course homepage with editing mode on
And I open "Weekly forum name" actions menu
And I click on "Move right" "link" in the "Weekly forum name" activity
@@ -54,7 +54,7 @@ Feature: Reset course indentation
And "Move left" "link" in the "Weekly wiki name" "activity" should be visible
Scenario Outline: Apply course indentation reset
Given I navigate to "Plugins > Course formats > <format>" in site administration
Given I navigate to "Plugins > Course formats > <format> format" in site administration
And I wait "5" seconds
And "Reset indentation sitewide" "link" should exist
When I click on "Reset indentation sitewide" "link"
@@ -62,31 +62,31 @@ Feature: Reset course indentation
And "Reset indentation sitewide" "button" should exist
And I click on "Reset indentation sitewide" "button"
Then I should see "Indentation reset."
And I am on "<prefix> Course 1" course homepage with editing mode on
And I open "<prefix> forum name" actions menu
And "Move right" "link" in the "<prefix> forum name" "activity" should be visible
And "Move left" "link" in the "<prefix> forum name" "activity" should not be visible
And I am on "<format> Course 1" course homepage with editing mode on
And I open "<format> forum name" actions menu
And "Move right" "link" in the "<format> forum name" "activity" should be visible
And "Move left" "link" in the "<format> forum name" "activity" should not be visible
And I press the escape key
And I open "<prefix> database name" actions menu
And "Move right" "link" in the "<prefix> database name" "activity" should be visible
And "Move left" "link" in the "<prefix> database name" "activity" should not be visible
And I am on "<prefix> Course 2" course homepage with editing mode on
And I open "<prefix> wiki name" actions menu
And "Move right" "link" in the "<prefix> wiki name" "activity" should be visible
And "Move left" "link" in the "<prefix> wiki name" "activity" should not be visible
# Check other course formats had not been reset
And I open "<format> database name" actions menu
And "Move right" "link" in the "<format> database name" "activity" should be visible
And "Move left" "link" in the "<format> database name" "activity" should not be visible
And I am on "<format> Course 2" course homepage with editing mode on
And I open "<format> wiki name" actions menu
And "Move right" "link" in the "<format> wiki name" "activity" should be visible
And "Move left" "link" in the "<format> wiki name" "activity" should not be visible
# Check other course formats had not been reset
And I am on "<other> Course 1" course homepage with editing mode on
And I open "<other> forum name" actions menu
And "Move right" "link" in the "<other> forum name" "activity" should not be visible
And "Move left" "link" in the "<other> forum name" "activity" should be visible
Examples:
| format | prefix | other |
| Custom sections | Sections | Weekly |
| Weekly sections | Weekly | Sections |
| format | other |
| Topics | Weekly |
| Weekly | Topics |
Scenario Outline: Cancel course indentation reset
Given I navigate to "Plugins > Course formats > <format>" in site administration
Given I navigate to "Plugins > Course formats > <format> format" in site administration
And "Reset indentation sitewide" "link" should exist
When I click on "Reset indentation sitewide" "link"
And I should see "Reset indentation sitewide"
@@ -94,20 +94,20 @@ Feature: Reset course indentation
And "Cancel" "button" should exist
And I click on "Cancel" "button"
Then I should not see "Indentation reset."
And I am on "<prefix> Course 1" course homepage with editing mode on
And I open "<prefix> forum name" actions menu
And "Move right" "link" in the "<prefix> forum name" "activity" should not be visible
And "Move left" "link" in the "<prefix> forum name" "activity" should be visible
And I am on "<format> Course 1" course homepage with editing mode on
And I open "<format> forum name" actions menu
And "Move right" "link" in the "<format> forum name" "activity" should not be visible
And "Move left" "link" in the "<format> forum name" "activity" should be visible
And I press the escape key
And I open "<prefix> database name" actions menu
And "Move right" "link" in the "<prefix> database name" "activity" should be visible
And "Move left" "link" in the "<prefix> database name" "activity" should not be visible
And I am on "<prefix> Course 2" course homepage with editing mode on
And I open "<prefix> wiki name" actions menu
And "Move right" "link" in the "<prefix> wiki name" "activity" should not be visible
And "Move left" "link" in the "<prefix> wiki name" "activity" should be visible
And I open "<format> database name" actions menu
And "Move right" "link" in the "<format> database name" "activity" should be visible
And "Move left" "link" in the "<format> database name" "activity" should not be visible
And I am on "<format> Course 2" course homepage with editing mode on
And I open "<format> wiki name" actions menu
And "Move right" "link" in the "<format> wiki name" "activity" should not be visible
And "Move left" "link" in the "<format> wiki name" "activity" should be visible
Examples:
| format | prefix |
| Custom sections | Sections |
| Weekly sections | Weekly |
| format |
| Topics |
| Weekly |
+22
View File
@@ -48,3 +48,25 @@ Feature: View task logs report and use its filters
| operator | shouldornotsee |
| Less than | should not see |
| Greater than | should see |
@javascript
Scenario: Reset task log filters
Given I log in as "admin"
And I change window size to "large"
And I navigate to "Server > Tasks > Task logs" in site administration
When I click on "Filters" "button"
And I set the following fields in the "Result" "core_reportbuilder > Filter" to these values:
| Result operator | Is equal to |
| Result value | Fail |
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
Then I should see "Filters applied"
And I should see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
And I should see "Nothing to display"
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
And I should see "Filters reset"
And I should not see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
And I should see "Filters" in the "#dropdownFiltersButton" "css_element"
And "[data-region='report-filters']" "css_element" should be visible
And the following fields in the "Result" "core_reportbuilder > Filter" match these values:
| Result operator | Is any value |
And I should not see "Nothing to display"
@@ -1,114 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_admin\reportbuilder\local\filters;
use advanced_testcase;
use lang_string;
use core_reportbuilder\local\report\filter;
/**
* Unit tests for course role report filter
*
* @package core_admin
* @covers \core_admin\reportbuilder\local\filters\courserole
* @copyright 2023 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class courserole_test extends advanced_testcase {
/**
* Data provider for {@see test_get_sql_filter}
*
* @return array[]
*/
public static function get_sql_filter_provider(): array {
return [
'Empty filter' => ['', '', '', ['admin', 'guest', 'user1', 'user2', 'user3', 'user4']],
'Filter by role' => ['editingteacher', '', '', ['user1', 'user3', 'user4']],
'Filter by role in category' => ['editingteacher', 'cat2', '', ['user1', 'user3']],
'Filter by role in category and course' => ['editingteacher', 'cat2', 'course2', ['user1']],
'Filter by role in course' => ['student', '', 'course2', ['user2']],
'Filter by category' => ['', 'cat2', '', ['user1', 'user2', 'user3']],
'Filter by category and course' => ['', 'cat2', 'course2', ['user1', 'user2']],
'Filter by course' => ['', '', 'course3', ['user3']],
'Filter by course (ensure whitespace is trimmed)' => ['', '', ' course3 ', ['user3']],
];
}
/**
* Test getting filter SQL
*
* @param string $rolename
* @param string $categoryname
* @param string $course
* @param string[] $expectedusers
*
* @dataProvider get_sql_filter_provider
*/
public function test_get_sql_filter(
string $rolename,
string $categoryname,
string $course,
array $expectedusers,
): void {
global $DB;
$this->resetAfterTest();
// Create categories/course structure (categoryone: courseone; categorytwo: coursetwo/coursethree).
$categoryone = $this->getDataGenerator()->create_category(['name' => 'cat1']);
$courseone = $this->getDataGenerator()->create_course(['category' => $categoryone->id, 'shortname' => 'course1']);
$categorytwo = $this->getDataGenerator()->create_category(['name' => 'cat2']);
$coursetwo = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course2']);
$coursethree = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course3']);
// User one is a teacher in courseone/coursetwo.
$userone = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user1']);
$this->getDataGenerator()->enrol_user($userone->id, $coursetwo->id, 'editingteacher');
// User two is a student in coursetwo.
$usertwo = $this->getDataGenerator()->create_and_enrol($coursetwo, 'student', ['username' => 'user2']);
// User three is a teacher in courseone/coursethree.
$userthree = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user3']);
$this->getDataGenerator()->enrol_user($userthree->id, $coursethree->id, 'editingteacher');
// User four is a teacher in courseone.
$userfour = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user4']);
$filter = new filter(
courserole::class,
'test',
new lang_string('yes'),
'testentity',
'id',
);
// Create instance of our filter, passing given operators (with lookups for role/category).
[$select, $params] = courserole::create($filter)->get_sql_filter([
$filter->get_unique_identifier() . '_role' => $DB->get_field('role', 'id', ['shortname' => $rolename]),
$filter->get_unique_identifier() . '_category' => $DB->get_field('course_categories', 'id', ['name' => $categoryname]),
$filter->get_unique_identifier() . '_course' => $course,
]);
$users = $DB->get_fieldset_select('user', 'username', $select, $params);
$this->assertEqualsCanonicalizing($expectedusers, $users);
}
}
-154
View File
@@ -1,154 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Theme selector page for admin use.
*
* @package core_admin
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../config.php');
require_once($CFG->libdir . '/adminlib.php');
$choose = optional_param('choose', '', PARAM_PLUGIN);
$reset = optional_param('reset', 0, PARAM_BOOL);
$confirmation = optional_param('confirmation', 0, PARAM_BOOL);
admin_externalpage_setup('themeselector');
unset($SESSION->theme);
$PAGE->set_primary_active_tab('siteadminnode');
$PAGE->navbar->add(get_string('themeselector', 'admin'), $PAGE->url);
$PAGE->set_pagelayout('standard');
// Clear theme cache.
if ($reset && confirm_sesskey()) {
theme_reset_all_caches();
}
$definedinconfig = array_key_exists('theme', $CFG->config_php_settings);
if ($definedinconfig) {
$forcedthemename = get_string('pluginname', 'theme_'.$CFG->theme);
// Show a notification that the theme is defined in config.php.
\core\notification::info(get_string('themedefinedinconfigphp', 'admin', $forcedthemename));
}
// Change theme.
if (!$definedinconfig && !empty($choose) && confirm_sesskey()) {
// Load the theme to make sure it is valid.
$theme = theme_config::load($choose);
if ($theme instanceof \theme_config) {
set_config('theme', $theme->name);
$notifytype = 'success';
$notifymessage = get_string('themesaved');
} else {
$notifytype = 'error';
$notifymessage = get_string('error');
}
// Redirect with notification.
redirect(new moodle_url('/admin/themeselector.php'), $notifymessage, null, $notifytype);
}
// Insert header.
echo $OUTPUT->header();
// Prepare data for rendering.
$data = [];
$index = 0;
$currentthemeindex = 0;
$themes = core_component::get_plugin_list('theme');
// Loop through available themes.
foreach ($themes as $themename => $themedir) {
try {
$theme = theme_config::load($themename);
} catch (Exception $e) {
// Bad theme, just skip it for now.
continue;
}
if ($themename !== $theme->name) {
// Obsoleted or broken theme, just skip for now.
continue;
}
if (empty($CFG->themedesignermode) && $theme->hidefromselector) {
// The theme doesn't want to be shown in the theme selector and as theme
// designer mode is switched off we will respect that decision.
continue;
}
// All params for modal use are set here, except for 'choosereadme' (description).
// That string can be long. We will fetch it with JS as opposed to passing it as an attribute.
$themedata = [];
// The 'name' param is formatted and should not to be confused with 'choose'.
$themedata['name'] = get_string('pluginname', 'theme_'.$themename);;
$themedata['choose'] = $themename;
// Image to display for previewing.
$image = new moodle_url('/theme/image.php', ['theme' => $themename, 'image' => 'screenshot', 'component' => 'theme']);
$themedata['image'] = $image;
// Is this the current theme?
if ($themename === $CFG->theme) {
$themedata['current'] = true;
$currentthemeindex = $index;
} else if (!$definedinconfig) {
// Form params.
$actionurl = new moodle_url('/admin/themeselector.php');
$themedata['actionurl'] = $actionurl;
$themedata['sesskey'] = sesskey();
}
// Settings url.
$settingspath = "$themedir/settings.php";
if (file_exists($settingspath)) {
$section = "themesetting{$themename}";
$settingsurl = new moodle_url('/admin/settings.php', ['section' => $section]);
$themedata['settingsurl'] = $settingsurl;
}
// Link to the theme usage report if override enabled and it is being used in at least one context.
if (\core\output\theme_usage::is_theme_used_in_any_context($themename) === \core\output\theme_usage::THEME_IS_USED) {
$reporturl = new moodle_url($CFG->wwwroot . '/report/themeusage/index.php');
$reporturl->params(['themechoice' => $themename]);
$themedata['reporturl'] = $reporturl->out(false);
}
$data[$index] = $themedata;
$index++;
}
// Reorder the array to always have the current theme first.
if (isset($data[$currentthemeindex])) {
$currenttheme = $data[$currentthemeindex];
unset($data[$currentthemeindex]);
array_unshift($data, $currenttheme);
}
// Show theme selector.
$renderable = new \core_admin\output\theme_selector($data, $definedinconfig);
$renderer = $PAGE->get_renderer('core', 'admin');
echo $renderer->theme_selector_list($renderable);
// Show footer.
echo $OUTPUT->footer();
@@ -16,7 +16,6 @@
namespace tool_admin_presets\local\action;
use core_adminpresets\manager;
use moodle_exception;
/**
@@ -35,8 +34,8 @@ class delete extends base {
public function show(): void {
global $DB, $OUTPUT;
// Check the preset exists (cannot delete the pre-installed core "Starter" and "Full" presets).
$presetdata = $DB->get_record('adminpresets', ['id' => $this->id, 'iscore' => manager::NONCORE_PRESET], 'name');
// Getting the preset name.
$presetdata = $DB->get_record('adminpresets', ['id' => $this->id], 'name');
if ($presetdata) {
$deletetext = get_string('deletepreset', 'tool_admin_presets', $presetdata->name);
@@ -65,7 +64,7 @@ class delete extends base {
* Delete the DB preset
*/
public function execute(): void {
require_sesskey();
confirm_sesskey();
$this->manager->delete_preset($this->id);
@@ -52,6 +52,8 @@ class export extends base {
* Stores a preset into the DB.
*/
public function execute(): void {
confirm_sesskey();
$url = new \moodle_url('/admin/tool/admin_presets/index.php', ['action' => 'export', 'mode' => 'execute']);
$this->moodleform = new export_form($url);
@@ -85,7 +87,7 @@ class export extends base {
* @throws xml_writer_exception
*/
public function download_xml(): void {
require_sesskey();
confirm_sesskey();
list($xmlstr, $filename) = $this->manager->download_preset($this->id);
@@ -40,6 +40,8 @@ class import extends base {
* Imports the xmlfile into DB
*/
public function execute(): void {
confirm_sesskey();
$url = new \moodle_url('/admin/tool/admin_presets/index.php', ['action' => 'import', 'mode' => 'execute']);
$this->moodleform = new import_form($url);
@@ -38,6 +38,8 @@ class load extends base {
public function execute(): void {
global $OUTPUT;
confirm_sesskey();
$url = new \moodle_url('/admin/tool/admin_presets/index.php', ['action' => 'load', 'mode' => 'execute']);
$this->moodleform = new load_form($url);

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