Compare commits

...

233 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 00821c744c Moodle release 3.10.1 2021-01-16 16:58:29 +01:00
Sara Arjona f420af1016 weekly release 3.10+ 2021-01-15 08:25:49 +01:00
Sara Arjona 67150560b2 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-01-15 08:25:47 +01:00
Sara Arjona 9fac7a8d59 Merge branch 'MDL-69308_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2021-01-14 12:03:52 +01:00
Jake Dallimore e1ca7e93d9 Merge branch 'MDL-69877-310' of git://github.com/mickhawkins/moodle into MOODLE_310_STABLE 2021-01-14 14:52:18 +08:00
Michael Hawkins 8bd6cfb4c4 MDL-69877 core: Added security.txt 2021-01-14 14:30:50 +08:00
AMOS bot a3afe546fd Automatically generated installer lang files 2021-01-14 00:07:23 +00:00
Eloy Lafuente (stronk7) db30a623bf MDL-69308 environment: Apply agreed changes
- PHP 7.3 required.
- Moodle 3.6 required.
- SQL*Server 2017 (aka, 14.0) required.
- Sodium PHP extension required.
2021-01-13 19:29:44 +01:00
Eloy Lafuente (stronk7) 3afcb70b3d MDL-69308 environment: 3.11 base information
This is a direct copy of the 3.10 branch to have
the changes under control in next commits.
2021-01-13 19:29:39 +01:00
Sara Arjona 9ca6f8199e Merge branch 'MDL-70394-310' of git://github.com/rezaies/moodle into MOODLE_310_STABLE 2021-01-13 15:31:26 +01:00
Mihail Geshoski 4fec7a276d MDL-68486 auth_shibboleth: Reset convert_data if it uses dataroot file
Upgrade step that resets the 'Data modification API' (convert_data)
setting to its default value if this setting is currently configured
to use a file located within the $CFG->dataroot directory.
2021-01-13 12:35:00 +08:00
Mihail Geshoski b70a1c71e1 MDL-68486 auth_shibboleth: Prevent using dataroot files in convert_data
Prevents configuring the 'Data modification API' (convert_data) setting
to use files located within the $CFG->dataroot directory as it exposes
the site to security risks.
2021-01-13 12:35:00 +08:00
Jun Pataleta 90c450839d Merge branch 'MDL-70580-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-01-13 10:19:51 +08:00
AMOS bot b7a62b4286 Automatically generated installer lang files 2021-01-13 00:07:25 +00:00
Paul Holden 33427c7c5d MDL-70580 core: retrieve closest tree node in click handler. 2021-01-12 20:17:32 +00:00
Michael Hawkins 8fa9d159bc MDL-69911 core: Clean content passed through TeX filter 2021-01-12 10:24:26 +01:00
Ferran Recio f8f154236d MDL-67782 message: fix messages max length 2021-01-12 10:24:26 +01:00
Juan Segarra Montesinos d54cc8fbd7 MDL-69797 core_grades: Implement authorization into fetch method 2021-01-12 10:24:26 +01:00
Juan Segarra Montesinos 7e6fc779c7 MDL-69797 core_grades: Implement authorization into fetch method 2021-01-12 10:24:26 +01:00
Juan Segarra Montesinos 3467d87c80 MDL-69797 gradingform_rubric: Implement authorization into fetch method 2021-01-12 10:24:26 +01:00
Juan Segarra Montesinos 855957180a MDL-69797 gradingform_guide: Implement authorization into fetch method 2021-01-12 10:24:26 +01:00
Sara Arjona 8862b80c56 Merge branch 'MDL-70009-310' of git://github.com/ilyatregubov/moodle into MOODLE_310_STABLE 2021-01-12 10:21:09 +01:00
Jake Dallimore 8b8142d8d9 Merge branch 'MDL-69431_Moodle_310_Validate_section_arg_modedit' of git://github.com/watson8/moodle into MOODLE_310_STABLE 2021-01-12 17:09:01 +08:00
Ilya Tregubov f0260219fa MDL-70009 h5pactivity: Split get_pluginfile_hash in two methods. 2021-01-12 09:10:57 +02:00
Jun Pataleta be36ead8b0 Merge branch 'MDL-70580-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-01-12 13:15:43 +08:00
AMOS bot f270bd8c8e Automatically generated installer lang files 2021-01-12 00:07:34 +00:00
Andrew Nicols 357909b23b MDL-70580 core: Tree nodes should check if they were clicked directly 2021-01-11 23:43:28 +00:00
Michael Hawkins 2c45443ad7 MDL-70571 lib: Added additional escaping to search_input template 2021-01-11 16:20:32 +01:00
Sara Arjona 77d7480096 Merge branch 'MDL-70034_310' of git://github.com/mdjnelson/moodle into MOODLE_310_STABLE 2021-01-11 15:19:32 +01:00
Sara Arjona b57b9b41cd Merge branch 'MDL-70567-MOODLE_310_STABLE' of https://github.com/dmitriim/moodle into MOODLE_310_STABLE 2021-01-11 13:09:49 +01:00
Sara Arjona cfa2b28de6 Merge branch 'MDL-70578-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2021-01-11 12:58:20 +01:00
Sara Arjona e22723680d Merge branch 'MDL-70352-MOODLE_310_STABLE' of https://github.com/dmitriim/moodle into MOODLE_310_STABLE 2021-01-11 12:24:05 +01:00
AMOS bot db2a9784ef Automatically generated installer lang files 2021-01-11 00:08:40 +00:00
David Watson 06d7da192b MDL-69431 course: validate section url param against maxsections 2021-01-10 17:14:58 +00:00
Eloy Lafuente (stronk7) 586a6da356 Merge branch 'MDL-70550-310-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_310_STABLE 2021-01-09 13:17:50 +01:00
Mark Nelson 2ab950039c MDL-70034 gradingform_guide: use new API to retrieve grade item name 2021-01-09 14:31:09 +08:00
AMOS bot 3b3c246aaa Automatically generated installer lang files 2021-01-09 00:07:26 +00:00
Sara Arjona b3b476ce3c Merge branch 'MDL-70558-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2021-01-08 17:07:23 +01:00
Sara Arjona 682ee99293 Merge branch 'MDL-70102-m310' of https://github.com/sammarshallou/moodle into MOODLE_310_STABLE 2021-01-08 15:51:05 +01:00
David Mudrák b8069c3372 MDL-70550 lang: Use the fixed strings in Behat tests, too 2021-01-08 09:11:38 +01:00
Helen Foster 992d1b29b4 MDL-70550 lang: Import fixed English strings (en_fix) 2021-01-08 09:11:38 +01:00
Jun Pataleta ceab4136aa Merge branch 'MDL-70310-310' of git://github.com/ilyatregubov/moodle into MOODLE_310_STABLE 2021-01-08 14:47:14 +08:00
Luca Bösch 8241aa75d5 MDL-70578 cohorts: Add bootstrap classes to buttons 2021-01-08 07:28:15 +01:00
Jun Pataleta f186074a54 weekly release 3.10+ 2021-01-08 12:14:56 +08:00
Jun Pataleta 8585fe1404 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2021-01-08 12:14:55 +08:00
AMOS bot d4dff59b82 Automatically generated installer lang files 2021-01-08 00:07:23 +00:00
Eloy Lafuente (stronk7) af4b97f57a Merge branch 'MDL-70245-MOODLE_310_STABLE' of https://github.com/TomoTsuyuki/moodle into MOODLE_310_STABLE 2021-01-07 23:49:47 +01:00
Eloy Lafuente (stronk7) c3341dea30 Merge branch 'MDL-70584-310' of git://github.com/marinaglancy/moodle into MOODLE_310_STABLE 2021-01-07 23:31:24 +01:00
sam marshall 2b0b250162 MDL-70102 PHPunit: Core test fails with weird added modules
Specifically it fails if the modules have unusual default capabilities
so that editingteacher doesn't have addinstance.
2021-01-07 16:11:55 +00:00
Marina Glancy dd17f6b1bf MDL-70584 core_iplookup: increase tolerance in test 2021-01-07 14:17:19 +01:00
Ilya Tregubov 4e1786f27f MDL-70310 user: Remove yahoo icon since domain no longer exists. 2021-01-07 09:15:28 +02:00
Jun Pataleta 247437ce25 Merge branch 'MDL-70374_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2021-01-07 12:24:18 +08:00
Eloy Lafuente (stronk7) 8d306e640f Merge branch 'MDL-70476_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2021-01-07 00:28:08 +01:00
Eloy Lafuente (stronk7) 17d296f1ea Merge branch 'MOODLE_310_MDL-70520' of https://github.com/golenkovm/moodle into MOODLE_310_STABLE 2021-01-07 00:19:12 +01:00
Dmitrii Metelkin c9dfaec749 MDL-70567 task: fix broken result filter on logs page 2021-01-06 14:29:17 +11:00
Adrian Greeve 304aaf2b7b Merge branch 'MDL-70482_310_STABLE' of https://github.com/sebmehr/moodle into MOODLE_310_STABLE 2021-01-06 11:23:47 +08:00
Dmitrii Metelkin 34153bcc77 MDL-70352 core: attach modal to a specific element 2021-01-06 11:19:57 +11:00
Paul Holden 65ef2f90bf MDL-70558 tool_langimport: sort available language packs. 2021-01-04 23:56:03 +00:00
AMOS bot b12ab80cf5 Automatically generated installer lang files 2020-12-27 00:07:25 +00:00
Sébastien Mehr 9ee975f3a9 MDL-70482 template: add missing closing bracket 2020-12-24 14:04:54 +01:00
AMOS bot fb02551622 Automatically generated installer lang files 2020-12-24 00:07:25 +00:00
Eloy Lafuente (stronk7) 64db9dc75a weekly release 3.10+ 2020-12-23 20:24:53 +01:00
Eloy Lafuente (stronk7) 9d5931b6e2 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2020-12-23 20:24:51 +01:00
Eloy Lafuente (stronk7) 0369198637 Merge branch 'MDL-56119-310' of https://github.com/inigozendegi/moodle into MOODLE_310_STABLE 2020-12-23 01:27:07 +01:00
Eloy Lafuente (stronk7) 62b9a44045 Merge branch 'MDL-70279-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-12-23 00:47:00 +01:00
Eloy Lafuente (stronk7) 1251f26d67 Merge branch 'MDL-70436-310' of git://github.com/bmbrands/moodle into MOODLE_310_STABLE 2020-12-22 18:29:55 +01:00
Eloy Lafuente (stronk7) 77a6c383bf Merge branch 'MDL-70386-310' of git://github.com/bmbrands/moodle into MOODLE_310_STABLE 2020-12-22 18:22:00 +01:00
Jake Dallimore 53e81c00fa Merge branch 'MDL-70459-310' of git://github.com/rezaies/moodle into MOODLE_310_STABLE 2020-12-22 16:51:36 +08:00
Jake Dallimore 9480706466 Merge branch 'MDL-69422-310-2' of git://github.com/junpataleta/moodle into MOODLE_310_STABLE 2020-12-22 16:03:17 +08:00
Jake Dallimore bb48ca47ef Merge branch 'MDL-70426-310' of https://github.com/HuongNV13/moodle into MOODLE_310_STABLE 2020-12-22 15:16:41 +08:00
Mikhail Golenkov 93b2fe7d38 MDL-70520 mod_assign: Use task API to get scheduled task lastruntime 2020-12-22 15:30:50 +11:00
Mikhail Golenkov 6ba4712549 MDL-70520 tasks: Keep lastruntime when a scheduled task is reset 2020-12-22 15:30:45 +11:00
AMOS bot b192dc7c64 Automatically generated installer lang files 2020-12-22 00:07:24 +00:00
Víctor Déniz 2d9922f388 Merge branch 'MDL-70355-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2020-12-21 23:19:20 +00:00
Eloy Lafuente (stronk7) 639f6143e7 Merge branch 'MDL-70430-310-oauth2refreshtoken' of git://github.com/mudrd8mz/moodle into MOODLE_310_STABLE 2020-12-22 00:07:00 +01:00
Víctor Déniz 0a27966b67 Merge branch 'MDL-70284-dynreg-bug-310' of https://github.com/cengage/moodle into MOODLE_310_STABLE 2020-12-21 16:33:17 +00:00
Sara Arjona 79b89c2d42 Merge branch 'MDL-69107-310-2' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-12-18 15:22:24 +01:00
Tim Hunt 591107c208 MDL-70374 qtype_multichoice: improve alignment of choices 2020-12-18 13:10:13 +00:00
Tim Hunt ccfc9f7bc9 MDL-70476 permission overrides: role names double-escaped in tool tip 2020-12-18 13:04:16 +00:00
Luca Bösch 06bf0c89d6 MDL-70355 calendar: Filter popuptext for calendar entries. 2020-12-17 17:44:04 +01:00
Sara Arjona c25f0087f7 weekly release 3.10+ 2020-12-17 15:52:52 +01:00
Sara Arjona 12830e4214 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2020-12-17 15:52:50 +01:00
Shamim Rezaie 2e1b2cf30e MDL-70394 paygw_paypal: Fix the incorrect foreign key 2020-12-17 00:26:48 +11:00
Víctor Déniz 0bfb0a58a0 Merge branch 'MDL-70261-310' of git://github.com/ilya-catalyst/moodle into MOODLE_310_STABLE 2020-12-16 12:34:29 +00:00
Sara Arjona 50ba1375e8 Merge branch 'MDL-70373_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2020-12-16 12:40:52 +01:00
Shamim Rezaie 5f57b10712 MDL-70459 enrol_fee: Sort the list of currencies when displaying 2020-12-16 22:30:52 +11:00
Shamim Rezaie ec6720a836 MDL-70459 core_payment: use array_merge to merge currencies 2020-12-16 22:30:52 +11:00
Sara Arjona e00b006d51 Merge branch 'MDL-70322-310' of git://github.com/roland04/moodle into MOODLE_310_STABLE 2020-12-16 12:04:22 +01:00
Jun Pataleta 7ce3918e83 Merge branch 'MDL-54907_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2020-12-16 10:26:58 +08:00
Andrew Nicols aa1c7e0a64 MDL-69107 user: Fix autocomplete usages 2020-12-16 07:50:56 +08:00
Sara Arjona cc87756c10 Merge branch 'MDL-70422-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-12-15 16:43:02 +01:00
Sara Arjona e7a53e9410 Merge branch 'MDL-70409-310' of git://github.com/merrill-oakland/moodle into MOODLE_310_STABLE 2020-12-15 16:15:50 +01:00
Sara Arjona a050d3f41b Merge branch 'MDL-70342-310' of git://github.com/abias/moodle into MOODLE_310_STABLE 2020-12-15 15:29:18 +01:00
Sara Arjona bc103afb53 Merge branch 'MDL-70357-310-cronlibthrowables' of git://github.com/mudrd8mz/moodle into MOODLE_310_STABLE 2020-12-15 14:56:04 +01:00
Ilya Tregubov 50d1003bb7 MDL-70261 course: Allow update locked course custom fields
on course upload.
2020-12-15 14:43:11 +02:00
Jake Dallimore 5c899c722c Merge branch 'MDL-67623-310_blocks_myoverview_pagination_regression' of https://github.com/tomdickman/moodle into MOODLE_310_STABLE 2020-12-15 18:22:11 +08:00
Jun Pataleta 73ad678e73 Merge branch 'MDL-70361-dlrlid-310' of https://github.com/cengage/moodle into MOODLE_310_STABLE 2020-12-15 11:17:25 +08:00
Andrew Nicols 22a5445346 MDL-69107 form_autocomplete: Rewrite item selection
The form_autocomplete is essentially a custom element. Unfortunately the
`setValue()` function in Mink has undesired actions so it is necessary
to write our own handling for it.

The standard Mink `setValue()` function focuses the element, sets a
value, and then blurs the element. In the case of the autocomplete this
can cause the autocomplete suggestions list to be closed in some
situations. Instead of using the setValue we click, and type the value,
but do not immediately blur.
2020-12-15 09:08:05 +08:00
AMOS bot 3ca8535203 Automatically generated installer lang files 2020-12-15 00:07:24 +00:00
Sara Arjona 7697ac6538 Merge branch 'MDL-70397-310' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-12-14 17:12:05 +01:00
Jake Dallimore c97eb87506 Merge branch 'MDL-70324-3.10' of https://github.com/JBThong/moodle into MOODLE_310_STABLE 2020-12-14 11:30:16 +08:00
Tom Dickman 66b3c79275 MDL-67623 block overview: fix pagination regression
Fixed a regression caused by MDL-64194 resulting in Dashboard - Course
overview pagination not working from second page of courses onwards.

Course overview block should now do the following:
- Display no pagination controls when user has no courses
- Display no pagination controls when less than 12 courses to display
- Only display pagination controls up to the number of courses user is
enrolled in
- Work correctly when on a page greater than the second page.
2020-12-14 13:28:11 +11:00
AMOS bot 773db77081 Automatically generated installer lang files 2020-12-13 00:07:25 +00:00
AMOS bot a07acd9464 Automatically generated installer lang files 2020-12-12 00:07:28 +00:00
AMOS bot 12b20cbf3b Merge branch 'MOODLE_310_STABLE' into install_310_STABLE 2020-12-12 00:07:27 +00:00
Mikel Martín fa31950c6a MDL-70322 core_search: consistent search icon 2020-12-11 15:40:45 +01:00
AMOS bot 6ef5f4ced0 Automatically generated installer lang files 2020-12-11 00:07:31 +00:00
Víctor Déniz c537ed7fed weekly release 3.10+ 2020-12-10 21:10:47 +00:00
Víctor Déniz f3b2f604e2 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2020-12-10 21:10:40 +00:00
Huong Nguyen f987001a61 MDL-70426 qtype_ddmarker: infinite markers keep duplicating 2020-12-10 15:52:46 +07:00
Shamim Rezaie f1ec340cca MDL-69301 theme_boost: Remove the special handling of Escape key 2020-12-10 14:59:55 +08:00
Tomo Tsuyuki 6998cbfad4 MDL-70245 core_grade: Fix grade_get_setting unit test failures
To fix the phpunit issue, change from static variable to use cache
2020-12-10 16:47:51 +11:00
Jake Dallimore 655f4d4f3f Merge branch 'MDL-70320-310' of https://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-12-10 12:01:48 +08:00
Andrew Nicols d9e22f40b4 MDL-70320 behat: User full path to page admin node 2020-12-10 07:55:50 +08:00
Bas Brands df8a5aeab5 MDL-70386 theme_boost: quizes correctness badges 2020-12-09 18:07:29 +01:00
Bas Brands 17cc12c381 MDL-70436 theme_boost: closebutton styles in moodle-dialog-fullscreen 2020-12-09 14:59:44 +01:00
Víctor Déniz e76c5c764b Merge branch 'MDL-63683-310' of https://github.com/dravek/moodle into MOODLE_310_STABLE 2020-12-09 12:47:52 +00:00
Jake Dallimore be45f4c47f Merge branch 'MDL-70151-310' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-12-09 14:46:14 +08:00
Shamim Rezaie fa7e218546 MDL-69301 behat: comment a test out
The e.key is not filled correctly by Geckodriver on the verssion of
Firefox that we use.
2020-12-09 13:40:04 +08:00
Andrew Nicols 5c0a5a531d Merge branch 'MDL-70320_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2020-12-09 12:06:22 +08:00
Andrew Nicols 200ec6b6ac Merge branch 'MDL-62707-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-12-09 08:53:27 +08:00
David Mudrák 0e7dc879de MDL-70430 oauth2: Fix storing of the new refresh token
There was a typo - missing underscore. As a result, the new refresh
token was never updated in the database. Depending on the issuer and
whether or when theyu invalidate issued refresh tokens, this might or
might not make the token refresh stop working.
2020-12-08 11:24:27 +01:00
Jake Dallimore 70fe644191 Merge branch 'MDL-70285_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2020-12-08 16:33:43 +08:00
AMOS bot 5178b349e8 Automatically generated installer lang files 2020-12-08 00:07:22 +00:00
Paul Holden c8e335fbe3 MDL-70422 restore: fix for undefined question answer ordering in test. 2020-12-07 10:15:53 +00:00
Adrian Greeve 567e587dbb Merge branch 'MDL-69301-310' of git://github.com/rezaies/moodle into MOODLE_310_STABLE 2020-12-07 09:29:24 +08:00
AMOS bot 37348f1c2e Automatically generated installer lang files 2020-12-06 00:07:27 +00:00
Eric Merrill e2feddadd9 MDL-70409 chat: Use require_once to import lib.php 2020-12-04 10:45:59 -05:00
Paul Holden 0a62138795 MDL-70279 tool_templatelibrary: preserve component search field value. 2020-12-04 14:55:32 +00:00
Paul Holden c24a16a819 MDL-62707 search: account for no matching courses when listing areas.
When limiting the list of courses during retrieval of the search areas
the user can access, make sure we have some contexts before looking
for blocks.
2020-12-04 09:43:17 +00:00
inigozendegi 8091ab8078 MDL-56119 gradingform_rubric: Rubric display layout issue 2020-12-04 09:41:42 +01:00
David Matamoros 12b9c6051e MDL-63683 enrol: Fix plugin settings when no role has student archetype 2020-12-04 09:25:54 +01:00
Andrew Nicols 92e6eb437c MDL-70397 behat: Prevent browser restarting after initial start 2020-12-04 12:07:20 +08:00
Jake Dallimore 32866a1758 weekly release 3.10+ 2020-12-04 08:42:48 +08:00
Jake Dallimore 9ce415b207 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2020-12-04 08:42:45 +08:00
Jake Dallimore ec69ae5929 Merge branch 'MDL-70326-MOODLE_310_STABLE' of https://github.com/durzo/moodle into MOODLE_310_STABLE 2020-12-03 11:54:18 +08:00
Andrew Nicols f5545b5c0e Merge branch 'MDL-70327-310' of git://github.com/cescobedo/moodle into MOODLE_310_STABLE 2020-12-03 11:51:59 +08:00
Andrew Nicols 7c22b71916 Merge branch 'MDL-70321_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE 2020-12-03 11:39:54 +08:00
Jake Dallimore b5414af214 Merge branch 'MDL-69411-310' of git://github.com/dravek/moodle into MOODLE_310_STABLE 2020-12-03 11:37:00 +08:00
Jake Dallimore 686b5beb23 Merge branch 'MDL-67460-310_profile_secure' of https://github.com/beenet-dev/moodle into MOODLE_310_STABLE 2020-12-03 11:16:31 +08:00
Adrian Greeve af87a57052 Merge branch 'wip_MDL-70267_m310' of git://github.com/gjb2048/moodle into MOODLE_310_STABLE 2020-12-03 10:56:37 +08:00
Adrian Greeve dec6e261e2 Merge branch 'MDL-70167-310' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-12-03 09:57:42 +08:00
AMOS bot 24058ace40 Automatically generated installer lang files 2020-12-03 00:07:26 +00:00
Andrew Nicols d552427f61 Merge branch 'MDL-69868-310' of git://github.com/ilya-catalyst/moodle into MOODLE_310_STABLE 2020-12-03 07:47:48 +08:00
Tim Hunt 0eeb391472 MDL-70373 qtype_essay: missing border on atto input 2020-12-02 20:09:57 +00:00
Shamim Rezaie 433556de1f MDL-69301 theme_boost: Use event.key in aria.js
Both event.which and event.keyCode are deprecated. So
We switched to using event.key. We can only do so now
because IE is no longer supported.
2020-12-03 04:22:09 +11:00
Shamim Rezaie b24f13eca2 MDL-69301 course: Remove custom keyboard navigation code 2020-12-03 04:22:09 +11:00
Shamim Rezaie 65a9b26791 MDL-69301 core: Enhanced WAI-ARIA support for tab elements 2020-12-03 04:22:09 +11:00
Shamim Rezaie 2cc04e2b29 MDL-69301 theme_boost: convert aria.js to es6 module 2020-12-03 04:22:09 +11:00
Jake Dallimore 6be44e7d06 Merge branch 'MDL-67514-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-12-02 16:23:54 +08:00
AMOS bot 93b3efa5a7 Automatically generated installer lang files 2020-12-02 00:07:23 +00:00
Thong Bui 2908ed5405 MDL-70324 Question: get_all_response_file_areas() not work correctly 2020-12-01 16:11:21 +07:00
AMOS bot 966c8a37cb Automatically generated installer lang files 2020-12-01 00:07:30 +00:00
Claude Vervoort c8637d645e MDL-70361 mod_lti: deeplinking multiple preserve resourceid and tag 2020-11-30 14:59:54 -05:00
David Mudrák b427f21cca MDL-70357 cron: Catch Throwables not just Exceptions when running tasks
Starting from PHP 7, most language errors throw Error exceptions. We
want to deal with those equally as with any other exception so we need
to catch all Throwables here.
2020-11-30 17:37:25 +01:00
Alexander Bias 25a0001b9f MDL-70342 block_timeline: Get rid of double quotes
This commit gets rid of double quotes around the activity name and course name
which have sneaked into block_timeline's view in MDL-65183.
2020-11-30 13:20:05 +01:00
Gareth Barnard 843cc0ee8d MDL-70267 ux, theme: Course user profile inconsistent page layout. 2020-11-29 23:51:01 +00:00
AMOS bot 0172d13163 Automatically generated installer lang files 2020-11-29 00:07:31 +00:00
Tim Hunt 78bddace2c MDL-54907 quiz unit tests: clean up code style in attempts_test.php 2020-11-27 18:30:43 +00:00
Tim Hunt 779c1687a4 MDL-54907 quiz: better timefinish for attempts finished asynchronously
There are serveral ways a quiz attempt can be submitted:

1. The student click the Submit and finish button. In this case,
   no problem. We record the current time as the finish time
   for the quiz attempt.

2. The student is activly working away at the quiz, and the
   count-down timer reachers zero. In this case, we also record
   the current time. Note that, if the server is under high load,
   then this could well end up being a few seconds after the
   theoretical end time, so you could have a quiz with a 30 minute
   time limit, with an attempt that lasted 30:07. However, this
   is just an accurate reflection of what happened, so should
   be recorded like this.

3. If the student is offline when the time expires, then
   (depending on the quiz settings) the attempt may be
   automatically submitted by cron, but this will happen with
   at least some delay (to prevent race conditions between cron
   and a student working online) and if cron is running slow
   on the server, it could be a lot later. Previously, this led
   to, say, a 30 minute quiz where an attempt seemed to have
   lasted 67 minutes, which confused people.

   Now, in this situation, the finsh time for the quiz attempt is
   recorded as the time when the time limit ran out. This is not
   just less confusing for teachers looking at the quiz report,
   it is also more accurate. That is the latest time at which
   students could have made any changes to their responses.
2020-11-27 18:30:43 +00:00
Tim Hunt c99a83bc5c MDL-54907 quiz generator: defaults should match a new Moodle install 2020-11-27 18:30:43 +00:00
Tim Hunt 0b523e6031 MDL-54907 dml: Correct incorrect PHPdoc 2020-11-27 18:30:42 +00:00
Jun Pataleta 8cd8daa285 MDL-69422 mod_data: Export form accessibility fixes
* Set appropriate heading element IDs
* Replace usages of deprecated HTML tag acronym with abbr instead.
* Add a label for the export fields fieldset.
* Move the CSV delimiter list outside the radio group.
* Fix div under a label element and duplicate labels
for the checkboxes of the fields to be exported by showing the field
name and type together.
* Group the fields to be exported as a fieldset.
* Move unsupported fields into a separate list.
* Move export options into its own section and group the options as a
fieldset.
2020-11-27 23:24:13 +08:00
Jun Pataleta 1bd007e815 MDL-69422 core: Convert required and help button container to div
* A span element cannot have a div as a child.
2020-11-27 23:24:13 +08:00
Sara Arjona 9c35064345 weekly release 3.10+ 2020-11-27 07:50:48 +01:00
Sara Arjona 5945a1a926 Merge branch 'install_310_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_310_STABLE 2020-11-27 07:50:45 +01:00
AMOS bot fac91d11d8 Automatically generated installer lang files 2020-11-27 06:21:03 +00:00
Sara Arjona 9fcd6522ce Merge branch 'MDL-70276_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2020-11-26 15:04:30 +01:00
Andrew Nicols 85673c859e MDL-70153 qtype_essay: Whitespace/behat fixes 2020-11-26 12:54:26 +01:00
Andrew Nicols 4dba8e8359 Merge branch 'MDL-70153-310' of git://github.com/dpalou/moodle into MOODLE_310_STABLE 2020-11-26 12:54:26 +01:00
Andrew Nicols f03c875cf3 Merge branch 'MDL-70237-310' of git://github.com/rezaies/moodle into MOODLE_310_STABLE 2020-11-26 12:54:26 +01:00
Andrew Nicols 9fcb5ece12 Merge branch 'MDL-70242-310' of git://github.com/marinaglancy/moodle into MOODLE_310_STABLE 2020-11-26 12:54:26 +01:00
Andrew Nicols b07833ddf4 Merge branch 'MDL-65852-310' of git://github.com/ilya-catalyst/moodle into MOODLE_310_STABLE 2020-11-26 12:54:26 +01:00
Sara Arjona 333f6cb753 Merge branch 'MDL-70248-310' of https://github.com/HuongNV13/moodle into MOODLE_310_STABLE 2020-11-26 12:54:25 +01:00
Sara Arjona 1c594e729b Merge branch 'MDL-70265_310' of https://github.com/stronk7/moodle into MOODLE_310_STABLE 2020-11-26 12:54:25 +01:00
Ilya Tregubov d8c8f544b3 MDL-69868 h5pactivity: Prevent breaking $USER when seeing
attempt report.
2020-11-26 12:40:28 +02:00
Eloy Lafuente (stronk7) a284ced9a1 MDL-70276 github actions: First cut, phpunit and grunt checks
First working version, supports phpunit (using build matrix):

- php72 (lowest), running mysql.
- php74 (highest), running postgres.

Also verifies that the branch has been "gruntified" and there
isn't any missing change (build js/css files).

TODO: Verify the remaining checks currently in .travis.yml, namely:
 - CITEST
 - Add caching
 - Better health-check for DB images.
 - Support from the tracker (satus badges and enable check).
 - Support from CiBoT (status and enable check).
 - Consider moving both the common setup (git, composer...)
   and the database (mysql, postgres) to own actions for
   easier tweaking.
2020-11-26 00:23:22 +01:00
Tim Hunt cb82824f6a MDL-70320 permission overrides: role names were double-escaped 2020-11-25 21:21:28 +00:00
Claude Vervoort 613c37d54b MDL-70284 mod_lti: dynreg fix response claims 2020-11-25 10:51:08 -05:00
cescobedo 53f9417795 MDL-70327 core_h5p: Add preventredirect to the player 2020-11-25 16:30:46 +01:00
Jordan Tomkinson 407807df6b MDL-70326 antivirus: fixing regression in MDL-66222 2020-11-25 11:28:56 +01:00
Ilya Tregubov 7c80e15392 MDL-65852 user: Fix permission check to download course participants. 2020-11-25 11:27:36 +02:00
Tim Hunt e95c0a90ac MDL-70321 question backup: fix MDL-47178 unit tests
They were failing if you had CodeRunner installed
2020-11-24 15:29:41 +00:00
Simon Mok 48905f6b75 MDL-67460 profile: User profile link to use HTTPS 2020-11-24 20:48:52 +08:00
Tim Hunt b5b562b7ee MDL-70285 completion upgrade: fix performance of the MDL-69687 code 2020-11-23 20:59:08 +00:00
David Matamoros 4a82e72b00 MDL-69411 core_message: Fix return structure for empty result set
Passing a timefrom higher than last message timecreated needs to
return a formatted response so it does not break ws.
2020-11-23 19:25:43 +01:00
Eloy Lafuente (stronk7) ef95f5262f MDL-70265 travis: Completely remove the UPGRADE check
It was broken since ages ago, see MDL-64874, so no sense
to keep it eating minutes for nothing.
2020-11-23 14:28:33 +01:00
Adrian Greeve e2d911c07b Merge branch 'MDL-67668-310-2' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-11-23 15:37:44 +08:00
Jake Dallimore 71bae0da0f Merge branch 'MDL-70160-function-cache-310' of https://github.com/Peterburnett/moodle into MOODLE_310_STABLE 2020-11-23 15:22:49 +08:00
Andrew Nicols e7bfbaf7b2 MDL-70151 assign: Fix bulk change for behat
Behat does not play well with confirmation dialogues and in some
situations it does not wait for the page to reload before starting the
next step.

This change adds a pending_js call which is only resolved if the cancel
button was pressed, otherwise it remains in-progress until the page
reloads resetting the entire state of it.
2020-11-23 11:12:03 +08:00
Andrew Nicols 6882d7399b MDL-70167 behat: Rewrite attribute check steps
This commit updates the following steps to use the
`the_attribute_of_should_be_set` step under the hood:
- the [element] [type] should be disabled
- the [element] [type] should be enabled
- the [element] [type] should be readonly
- the [element] [type] should not be readonly

This reduces unnecssary code duplication.
2020-11-23 11:03:28 +08:00
Andrew Nicols 80bf03d583 MDL-70167 behat: Boolean attributes should either exist or not 2020-11-23 11:03:28 +08:00
Andrew Nicols 1039537d83 MDL-67668 behat: Update tests for inplace editable field type 2020-11-23 09:00:46 +08:00
Andrew Nicols 0214c50b18 MDL-67668 behat: Add inplace editable field type
This commit promotes the Inplace Editable field to a first-class form
element by introducing a new partial selector for inplace editable
fields, and teaching the field manager how to recognise these, then
introducing a new field type which can handle setting values for this
field.
2020-11-23 09:00:46 +08:00
Andrew Nicols e29e8373e6 MDL-67668 behat: Share behat_behat functionality with forms
Behat form fields are implemented in a way completely isolated from the
rest of the Behat Context system. Whereas regular step definitions have
access to execute steps, to call `find`, check for JS running, and other
related functionality, the Moodle implementation of a field type does
not have any access to this.

By moving the core functionality of behat_base to a new trait, and the
constants to a new interface, the functionality can also be used in
behat form fields in the same way as elsewhere.
2020-11-23 09:00:46 +08:00
Andrew Nicols 9e11009eb1 MDL-67668 behat: Correct js pending check
Pending checks should only run when JS is running, but some uses were
not apply this check.
2020-11-23 09:00:46 +08:00
Andrew Nicols a01ca7a600 MDL-67668 behat: Support NodeElement when fetching node in container
This is similar to change made in MDL-69136 to allow an already-fetched
NodeElement to be provided to the get_node_in_container() function and
makes it easier to be deterministic when writing steps.
2020-11-23 09:00:46 +08:00
Eloy Lafuente (stronk7) 6a662825f7 MDL-70265 travis: Only run highest phpunit if configured via env
By default only lowest php version will be executed, and only pgsql.

This default behavior can be changed with a new variable:

MOODLE_PHP = [all]
MOODLE_DATABASE = [pgsql | mysqli | all]
2020-11-21 11:28:31 +01:00
Eloy Lafuente (stronk7) 03e3219884 weekly release 3.10+ 2020-11-20 23:17:06 +01:00
Huong Nguyen 681b7f4e78 MDL-70248 qtype_ddimageortext: Drop zones have UI issue in Editing form 2020-11-19 17:03:49 +07:00
Adrian Greeve f098f28d01 Merge branch 'MOODLE_310_STABLE-MDL-67636' of https://github.com/yao9394/moodle into MOODLE_310_STABLE 2020-11-19 11:57:33 +08:00
John Yao bf17d50cf6 MDL-67636 gradebook: Prevent exposing hidden grade in locked category 2020-11-19 14:33:26 +11:00
Adrian Greeve 8e0f036b29 Merge branch 'MDL-56653-310' of git://github.com/lameze/moodle into MOODLE_310_STABLE 2020-11-19 11:10:48 +08:00
Andrew Nicols 51c6924206 Merge branch 'MDL-69809-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-11-19 10:47:46 +08:00
Jun Pataleta f589a25459 Merge branch 'MDL-70094-310' of https://github.com/SangNguyen2601/moodle into MOODLE_310_STABLE 2020-11-19 09:36:53 +08:00
Eloy Lafuente (stronk7) dee389dff6 Merge branch 'MDL-69201-310' of https://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-11-18 23:00:18 +01:00
Shamim Rezaie a9b83b3c01 MDL-70237 payment: Allow html tags in gateway description 2020-11-18 23:25:06 +11:00
sangnguyen2601 0ab0a293a8 MDL-70094 Question: Technical info section expands if click help icon 2020-11-18 17:32:40 +07:00
Dani Palou b76093e90c MDL-70153 qtype_essay: Add behat test for attachments max size 2020-11-18 10:48:17 +01:00
Dani Palou 8f0d40a39c MDL-70153 qtype_essay: Fix max size displayed for attachments 2020-11-18 10:48:17 +01:00
Vitaly 3a2d8a175e MDL-56653 enrol_meta: a single DB query in edit_instance_validation
The 'edit_instance_validation()' method checks for existing meta enrolment instances.
The fix replaces DB queries in a loop for each course with a single query for all courses.
Also, a new testing method 'test_edit_instance_validation_with_existing_courses()'
was added to /enrol/meta/tests/plugin_test.php to test if the new implementation
returns an error in case of trying to save the already linked courses in the 'customint1' field.
2020-11-18 15:05:42 +08:00
Andrew Nicols ff72ca7340 Merge branch '310_MDL-68896' of git://github.com/danmarsden/moodle into MOODLE_310_STABLE 2020-11-18 09:33:06 +08:00
Eloy Lafuente (stronk7) 4e346470a5 Merge branch 'MDL-70148-310' of git://github.com/andrewnicols/moodle into MOODLE_310_STABLE 2020-11-17 23:13:17 +01:00
Paul Holden 13c76cc295 MDL-67514 customfield: correct external usescategories return type. 2020-11-17 22:13:16 +00:00
Marina Glancy 2c4426bb10 MDL-70242 auth_oauth2: set page context and url 2020-11-17 16:47:59 +01:00
Andrew Nicols d3a9e2935d MDL-70148 gradereport_grader: Improve reliability of keyboard usage
In some browsers the ajax grade select does not properly update the
grade after setting values. The previous solution was to press the
[enter] key, but doing this with the new key type step opens the select
box again. This is what happens when a real user presses enter on the
select.

This is the last possible field in the report, so pressing the tab key
to move to the next gradable element does not work.

The solution uses a shift-tab to move the focus away to the previous
gradale element. In this case it must also be moved to an earlier step
because the previously selected value must be checked in the Then
section of the test and if it is selected then its value cannot be
checked.
2020-11-17 15:14:43 +08:00
Andrew Nicols 2adc010b85 MDL-70148 qtype: Update qtype steps to new key interaction
Note: The ddmarker question type was previously getting the number of
keypresses wrong. This was because it was using both keyDown/keyUp, and
also keyPress. As a result each keypress was essentially happening two
times.
2020-11-17 15:14:43 +08:00
Andrew Nicols c330c9276c MDL-70148 behat: Update steps for keyboard 2020-11-17 15:14:43 +08:00
Andrew Nicols e9b443b3a1 MDL-70148 behat: Add steps to send keys without an element 2020-11-17 15:14:43 +08:00
Andrew Nicols 7bb692666b Merge branch 'MDL-69526-310' of git://github.com/lucaboesch/moodle into MOODLE_310_STABLE 2020-11-17 14:55:10 +08:00
Adrian Greeve 5e924f295a Merge branch 'MDL-50955-310' of git://github.com/peterRd/moodle into MOODLE_310_STABLE 2020-11-17 13:08:48 +08:00
Andrew Nicols 739cbcf7e9 Merge branch 'MDL-69964-310' of git://github.com/paulholden/moodle into MOODLE_310_STABLE 2020-11-17 10:22:38 +08:00
Paul Holden 22df02089a MDL-69964 course: toggle participant checkboxes in root element.
For a given toggleGroup, the relevant action elements are not
necessarily descendants of the same tableRoot element, on the
course participants page.
2020-11-16 17:44:23 +00:00
Andrew Nicols be2afb52c1 MDL-67513 core: Only move modal to body if currently attached
A previous change as part of this commitset was intended to move the
modal to the document.body, but where the modal had been destroyed it
was instead added back to the body.
2020-11-16 09:37:48 +01:00
Peter Dias 09520f8e0d MDL-50955 core: Reset lessons completion criteria if grade type is none 2020-11-16 16:35:33 +08:00
Andrew Nicols d661fbfbc1 Merge branch 'MDL-67513-m310' of https://github.com/NeillM/moodle into MOODLE_310_STABLE 2020-11-16 08:27:35 +08:00
Luca Bösch e29069d45b MDL-69526 block_myoverview: custom course fields natural sorting 2020-11-13 00:57:42 +01:00
Neill Magill a2dcfd5bf6 MDL-67513 forum: View conversations while fullscreen grading
Before this change when a modal was shown and an element on the page
was fullscreen the modal would be created behind it.

This change ensures that the modal will be inside an element that is
fullscreen so that it will be correctly displayed.
2020-11-12 08:30:54 +00:00
Peter Burnett ebe19aa434 MDL-70160 cache: plugin_functions checks for function_exists() 2020-11-10 16:03:53 +10:00
Paul Holden 898dd7bf5b MDL-69201 core: consistent table primary sort column/order. 2020-11-09 19:45:41 +00:00
Neill Magill 4423581f8d MDL-67513 forum: Test that discussions can be viewed while grading 2020-11-09 14:24:56 +00:00
Paul Holden 9597baa6e8 MDL-69809 mod_folder: include forcedownload setting in WS responses. 2020-10-12 12:28:26 +01:00
Sam Hemelryk 04073c7e31 MDL-68896 mod_scorm: improved sendBeacon use when unloading 2020-08-19 20:30:17 +12:00
829 changed files with 8231 additions and 4994 deletions
+71
View File
@@ -0,0 +1,71 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Template configuraton file for github actions CI/CD.
*
* @package core
* @copyright 2020 onwards Eloy Lafuente (stronk7) {@link https://stronk7.com}
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// This cannot be used out from a github actions workflow, so just exit.
getenv('GITHUB_WORKFLOW') || die; // phpcs:ignore moodle.Files.MoodleInternal.MoodleInternalGlobalState
unset($CFG);
global $CFG;
$CFG = new stdClass();
$CFG->dbtype = getenv('dbtype');
$CFG->dblibrary = 'native';
$CFG->dbhost = '127.0.0.1';
$CFG->dbname = 'test';
$CFG->dbuser = 'test';
$CFG->dbpass = 'test';
$CFG->prefix = 'm_';
$CFG->dboptions = ['dbcollation' => 'utf8mb4_bin'];
$host = 'localhost';
$CFG->wwwroot = "http://{$host}";
$CFG->dataroot = realpath(dirname(__DIR__)) . '/moodledata';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
// Debug options - possible to be controlled by flag in future.
$CFG->debug = (E_ALL | E_STRICT); // DEBUG_DEVELOPER.
$CFG->debugdisplay = 1;
$CFG->debugstringids = 1; // Add strings=1 to url to get string ids.
$CFG->perfdebug = 15;
$CFG->debugpageinfo = 1;
$CFG->allowthemechangeonurl = 1;
$CFG->passwordpolicy = 0;
$CFG->cronclionly = 0;
$CFG->pathtophp = getenv('pathtophp');
$CFG->phpunit_dataroot = realpath(dirname(__DIR__)) . '/phpunitdata';
$CFG->phpunit_prefix = 't_';
define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080');
define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080');
define('TEST_SESSION_REDIS_HOST', 'localhost');
define('TEST_CACHESTORE_REDIS_TESTSERVERS', 'localhost');
// TODO: add others (solr, mongodb, memcached, ldap...).
// Too much for now: define('PHPUNIT_LONGTEST', true); // Only leaves a few tests out and they are run later by CI.
require_once(__DIR__ . '/lib/setup.php');
+103
View File
@@ -0,0 +1,103 @@
name: Core
on: [push]
env:
php: 7.4
jobs:
Grunt:
runs-on: ubuntu-18.04
steps:
- name: Checking out code
uses: actions/checkout@v2
- name: Configuring node & npm
shell: bash -l {0}
run: nvm install
- name: Installing node stuff
run: npm install
- name: Running grunt
run: npx grunt
- name: Looking for uncommitted changes
# Add all files to the git index and then run diff --cached to see all changes.
# This ensures that we get the status of all files, including new files.
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
run: |
git add .
git reset -- npm-shrinkwrap.json
git diff --cached --exit-code
PHPUnit:
runs-on: ${{ matrix.os }}
services:
exttests:
image: moodlehq/moodle-exttests
ports:
- 8080:80
redis:
image: redis
ports:
- 6379:6379
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
php: 7.2
db: mysqli
- os: ubuntu-18.04
php: 7.4
db: pgsql
steps:
- name: Setting up DB mysql
if: ${{ matrix.db == 'mysqli' }}
uses: johanmeiring/mysql-action@tmpfs-patch
with:
collation server: utf8mb4_bin
mysql version: 5.7
mysql database: test
mysql user: test
mysql password: test
use tmpfs: true
- name: Setting up DB pgsql
if: ${{ matrix.db == 'pgsql' }}
uses: m4nu56/postgresql-action@v1
with:
postgresql version: 9.6
postgresql db: test
postgresql user: test
postgresql password: test
- name: Configuring git vars
uses: rlespinasse/github-slug-action@v3.x
- name: Setting up PHP ${{ matrix.php }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
uses: actions/checkout@v2
- name: Setting up PHPUnit
env:
dbtype: ${{ matrix.db }}
run: |
echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
cp .github/workflows/config-template.php config.php
mkdir ../moodledata
sudo locale-gen en_AU.UTF-8
php admin/tool/phpunit/cli/init.php --no-composer-self-update
- name: Running PHPUnit tests
env:
dbtype: ${{ matrix.db }}
run: vendor/bin/phpunit -v
+29 -71
View File
@@ -16,31 +16,9 @@ services:
- mysql
- docker
php:
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
- 7.4
- 7.2
addons:
postgresql: "9.6"
env:
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
# start first so that the total run time is not too high.
#
# We only run MySQL on PHP 7.2, so run that first.
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
# Postgres is significantly is pretty reasonable in its run-time.
# Run CI Tests without running PHPUnit.
- DB=none TASK=CITEST
# Run unit tests on Postgres
- DB=pgsql TASK=PHPUNIT
# Perform an upgrade test too.
- DB=pgsql TASK=UPGRADE
jobs:
# Enable fast finish.
# This will fail the build if a single job fails (except those in allow_failures).
@@ -48,12 +26,35 @@ jobs:
fast_finish: true
include:
# Run mysql only on highest - it's just too slow
- php: 7.4
# First all the lowest php ones (7.2)
- php: 7.2
env: DB=none TASK=CITEST
- php: 7.2
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
- if: env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present
php: 7.2
env: DB=pgsql TASK=PHPUNIT
- if: env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all"
php: 7.2
env: DB=mysqli TASK=PHPUNIT
# Then, conditionally, all the highest php ones (7.4)
- if: env(MOODLE_PHP) = "all"
php: 7.4
env: DB=none TASK=CITEST
- if: env(MOODLE_PHP) = "all"
php: 7.4
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present)
php: 7.4
env: DB=pgsql TASK=PHPUNIT
- if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all")
php: 7.4
env: DB=mysqli TASK=PHPUNIT
# Run grunt/npm install on highest version too ('node' is an alias for the latest node.js version.)
- php: 7.4
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
cache:
directories:
@@ -113,7 +114,7 @@ install:
before_script:
- phpenv config-rm xdebug.ini
- >
if [ "$TASK" = 'PHPUNIT' -o "$TASK" = 'UPGRADE' ];
if [ "$TASK" = 'PHPUNIT' ];
then
# Copy generic configuration in place.
cp config-dist.php config.php ;
@@ -224,32 +225,6 @@ before_script:
export phpcmd=`which php`;
fi
########################################################################
# Upgrade test
########################################################################
- >
if [ "$TASK" = 'UPGRADE' ];
then
# We need the official upstream.
git remote add upstream https://github.com/moodle/moodle.git;
# Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
git fetch upstream MOODLE_30_STABLE;
git checkout MOODLE_30_STABLE;
# Perform the upgrade
php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
# Return to the previous commit
git checkout -;
# Perform the upgrade
php admin/cli/upgrade.php --non-interactive --allow-unstable ;
# The local_ci repository can be used to check upgrade savepoints.
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci ;
fi
script:
- >
if [ "$TASK" = 'PHPUNIT' ];
@@ -275,23 +250,6 @@ script:
git diff --cached --exit-code ;
fi
########################################################################
# Upgrade test
########################################################################
- >
if [ "$TASK" = 'UPGRADE' ];
then
cp local/ci/check_upgrade_savepoints/check_upgrade_savepoints.php ./check_upgrade_savepoints.php
result=`php check_upgrade_savepoints.php`;
# Check if there are problems
count=`echo "$result" | grep -P "ERROR|WARN" | wc -l` ;
if (($count > 0));
then
echo "$result"
exit 1 ;
fi
fi
after_script:
- >
if [ "$TASK" = 'PHPUNIT' ];
+182
View File
@@ -3344,4 +3344,186 @@
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.11" requires="3.6">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="10.2.29" />
<VENDOR name="mysql" version="5.7" />
<VENDOR name="postgres" version="9.6" />
<VENDOR name="mssql" version="14.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.3.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="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</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_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="optional">
<FEEDBACK>
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+1
View File
@@ -32,6 +32,7 @@ $result = optional_param('result', null, PARAM_INT);
$pageurl = new \moodle_url('/admin/tasklogs.php');
$pageurl->param('filter', $filter);
$pageurl->param('result', $result);
$PAGE->set_url($pageurl);
$PAGE->set_context(context_system::instance());
@@ -6,14 +6,18 @@ Feature: Edit capabilities
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
| username | firstname | lastname |
| teacher1 | Teacher | 1 |
| tutor | Teaching | Assistant |
| student | Student | One |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| fullname | shortname |
| Course 1 | C1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| user | course | role |
| teacher1 | C1 | editingteacher |
| tutor | C1 | teacher |
| student | C1 | student |
Scenario: Default system capabilities modification
Given I log in as "admin"
@@ -60,3 +64,25 @@ Feature: Edit capabilities
Then "mod/forum:deleteanypost" capability has "Prohibit" permission
And "mod/forum:editanypost" capability has "Prevent" permission
And "mod/forum:addquestion" capability has "Allow" permission
@javascript
Scenario: Edit permissions escapes role names correctly
When I am on the "C1" "Course" page logged in as "admin"
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
| Your word for 'Teacher' | Teacher >= editing |
| Your word for 'Non-editing teacher' | Teacher < "editing" |
| Your word for 'Student' | Studier & 'learner' |
And I press "Save and display"
And I navigate to course participants
Then I should see "Teacher >= editing (Teacher)" in the "Teacher 1" "table_row"
And I should see "Teacher < \"editing\" (Non-editing teacher)" in the "Teaching Assistant" "table_row"
And I should see "Studier & 'learner' (Student)" in the "Student One" "table_row"
And I navigate to "Users > Permissions" in current page administration
And I should see "Teacher >= editing" in the "mod/forum:replypost" "table_row"
And I should see "Teacher < \"editing\"" in the "mod/forum:replypost" "table_row"
And I should see "Studier & 'learner'" in the "mod/forum:replypost" "table_row"
And I follow "Prohibit"
And "Teacher >= editing" "button" in the "Prohibit role" "dialogue" should be visible
And "Teacher < \"editing\"" "button" in the "Prohibit role" "dialogue" should be visible
And "Studier & 'learner'" "button" in the "Prohibit role" "dialogue" should be visible
@@ -0,0 +1,30 @@
@tool_behat
Feature: Verify that the inplace editable field works as expected
In order to use behat step definitions
As a test write
I need to ensure that the inplace editable works in forms
Background:
Given the following "course" exists:
| fullname | Course 1 |
| shortname | C1 |
And the following "activities" exist:
| activity | course | name | idnumber |
| forum | C1 | My first forum | forum1 |
| assign | C1 | My first assignment | assign1 |
| quiz | C1 | My first quiz | quiz1 |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
@javascript
Scenario: Using an inplace editable updates the name of an activity
When I set the field "Edit title" in the "My first assignment" "activity" to "Coursework submission"
Then I should see "Coursework submission"
And I should not see "My first assignment"
But I should see "My first forum"
And I should see "My first quiz"
And I set the field "Edit title" in the "Coursework submission" "activity" to "My first assignment"
And I should not see "Coursework submission"
But I should see "My first assignment"
And I should see "My first forum"
And I should see "My first quiz"
@@ -0,0 +1,53 @@
@tool_behat
Feature: Verify that keyboard steps work as expected
In order to use behat step definitions
As a test writer
I need to verify that the keyboard steps work as expected
@javascript
Scenario: Typing keys into a field causes them to be input
Given the following "users" exist:
| username | email | firstname | lastname | password |
| saffronr | saffron.rutledge@example.com | Saffron | Rutledge | flowerpower |
Given I click on "Log in" "link"
And I click on "Username" "field"
When I type "saffronr"
And I press the tab key
And I type "flowerpower"
And I press enter
Then I should see "You are logged in as Saffron Rutledge"
@javascript
Scenario: Using tab changes focus to the next or previous field
Given I click on "Log in" "link"
And I click on "Username" "field"
And the focused element is "Username" "field"
When I press the tab key
Then the focused element is "Password" "field"
And I press the shift tab key
And the focused element is "Username" "field"
# TODO: Uncomment the following when MDL-66979 is integrated.
# @javascript
# Scenario: Using the arrow keys allows me to navigate through menus
# Given the following "users" exist:
# | username | email | firstname | lastname |
# | saffronr | saffron.rutledge@example.com | Saffron | Rutledge |
# And I log in as "saffronr"
# And I click on "Saffron Rutledge" "link" in the ".usermenu" "css_element"
# When I press the up key
# Then the focused element is "Log out" "link"
@javascript
Scenario: The escape key can be used to close a dialogue
Given the following "course" exists:
| fullname | C1|
| shortname | C1 |
And I log in as "admin"
And I am on "C1" course homepage
And I navigate to course participants
And I press "Enrol users"
And "Enrol users" "dialogue" should be visible
When I press the escape key
Then "Enrol users" "dialogue" should not be visible
@@ -46,7 +46,7 @@ Feature: Manage data requests
And I open the action menu in "John Doe" "table_row"
And I should see "View the request"
But I should not see "Mark as complete"
And I press key "27" in ".moodle-actionmenu" "css_element"
And I press the escape key
And I open the action menu in "Jane Doe" "table_row"
And I choose "Mark as complete" in the open action menu
And I should see "Do you really want to mark this user enquiry as complete?"
@@ -10,16 +10,12 @@ Feature: Manage data storage purposes
And I open the action menu in "region-main" "region"
And I choose "Purposes" in the open action menu
And I press "Add purpose"
And I set the field "Name" to "Purpose 1"
And I set the field "Description" to "Purpose 1 description"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Lawful bases" "form_row"
And I click on "Contract (GDPR Art. 6.1(b))" "list_item"
And I click on "Legal obligation (GDPR Art 6.1(c))" "list_item"
And I press key "27" in the field "Lawful bases"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Sensitive personal data processing reasons" "form_row"
And I click on "Explicit consent (GDPR Art. 9.2(a))" "list_item"
And I press key "27" in the field "Sensitive personal data processing reasons"
And I set the field "retentionperiodnumber" to "2"
And I set the following fields to these values:
| Name | Purpose 1 |
| Description | Purpose 1 description |
| Lawful bases | Contract (GDPR Art. 6.1(b)),Legal obligation (GDPR Art 6.1(c)) |
| Sensitive personal data processing reasons | Explicit consent (GDPR Art. 9.2(a)) |
| retentionperiodnumber | 2 |
When I press "Save"
Then I should see "Purpose 1" in the "List of data purposes" "table"
And I should see "Contract (GDPR Art. 6.1(b))" in the "Purpose 1" "table_row"
@@ -31,14 +27,13 @@ Feature: Manage data storage purposes
Scenario: Update a data storage purpose
Given I open the action menu in "Purpose 1" "table_row"
And I choose "Edit" in the open action menu
And I set the field "Name" to "Purpose 1 edited"
And I set the field "Description" to "Purpose 1 description edited"
And I click on "Legal obligation (GDPR Art 6.1(c))" "text" in the ".form-autocomplete-selection" "css_element"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Lawful bases" "form_row"
And I click on "Vital interests (GDPR Art. 6.1(d))" "list_item"
And I press key "27" in the field "Lawful bases"
And I set the field "retentionperiodnumber" to "3"
And I click on "protected" "checkbox"
And I set the following fields to these values:
| Name | Purpose 1 edited |
| Description | Purpose 1 description edited |
| Lawful bases | Contract (GDPR Art. 6.1(b)), Vital interests (GDPR Art. 6.1(d)) |
| Sensitive personal data processing reasons | Explicit consent (GDPR Art. 9.2(a)) |
| retentionperiodnumber | 3 |
| protected | 1 |
When I press "Save changes"
Then I should see "Purpose 1 edited" in the "List of data purposes" "table"
And I should see "Purpose 1 description edited" in the "Purpose 1 edited" "table_row"
@@ -22,8 +22,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_langimport\output;
defined('MOODLE_INTERNAL') || die();
use core_collator;
use moodle_url;
use renderable;
use renderer_base;
@@ -95,6 +95,8 @@ class langimport_page implements renderable, templatable {
if (!empty($this->availablelanguages)) {
$data->toinstalloptions = [];
core_collator::asort($this->availablelanguages);
foreach ($this->availablelanguages as $code => $language) {
$option = new stdClass();
$option->value = $code;
@@ -53,11 +53,11 @@ Feature: See the competencies for an activity on the course competencies page.
Then I should see "Test-Comp1"
And I should see "Test-Comp2"
And I set the field "Filter competencies by resource or activity" to "PageName1"
And I press key "13" in the field "Filter competencies by resource or activity"
And I press the enter key
And I should see "Test-Comp1"
And I should not see "Test-Comp2"
And I set the field "Filter competencies by resource or activity" to "PageName2"
And I press key "13" in the field "Filter competencies by resource or activity"
And I press the enter key
And I should not see "Test-Comp1"
And I should not see "Test-Comp2"
And I should see "No competencies have been linked to this activity or resource."
+2 -4
View File
@@ -30,7 +30,7 @@ Feature: Manage plearning plan
And I click on ".template-userplans" "css_element" in the "Science template" "table_row"
And I open the autocomplete suggestions list
And I click on "Admin User" item in the autocomplete list
And I press key "27" in the field "Select users to create learning plans for"
And I press the escape key
When I click on "Create learning plans" "button"
Then I should see "A learning plan was created"
And I should see "Admin User" in the "Science template" "table_row"
@@ -53,9 +53,7 @@ Feature: Manage plearning plan
And I follow "Home"
And I navigate to "Competencies > Learning plan templates" in site administration
And I click on ".template-cohorts" "css_element" in the "Science template cohort" "table_row"
And I click on ".form-autocomplete-downarrow" "css_element"
And I click on "cohort plan" item in the autocomplete list
And I press key "27" in the field "Select cohorts to sync"
And I set the field "Select cohorts to sync" to "cohort plan"
When I click on "Add cohorts" "button"
Then I should see "2 learning plans were created."
And I follow "Learning plan templates"
+1 -1
View File
@@ -1,2 +1,2 @@
define ("tool_templatelibrary/search",["jquery","core/ajax","core/log","core/notification","core/templates","core/config"],function(a,b,c,d,e,f){var g=function(b){e.render("tool_templatelibrary/search_results",{templates:b}).done(function(b,c){e.replaceNode(a("[data-region=\"searchresults\"]"),b,c)}).fail(d.exception)},h=function(c){var e=a("[data-field=\"component\"]").val(),f=a("[data-region=\"list-templates\"] [data-region=\"input\"]").val();if(""!==f){a("[data-region=\"list-templates\"] [data-action=\"clearsearch\"]").removeClass("d-none")}else{a("[data-region=\"list-templates\"] [data-action=\"clearsearch\"]").addClass("d-none")}document.location.hash=f;b.call([{methodname:"tool_templatelibrary_list_templates",args:{component:e,search:f,themename:c},done:g,fail:d.exception}],!0,!1)},i=null,j=function(a,b){if(null!==i){window.clearTimeout(i)}i=window.setTimeout(function(){a();i=null},b)},k=function(){j(h.bind(this,f.theme),400)};a("[data-region=\"list-templates\"]").on("change","[data-field=\"component\"]",k);a("[data-region=\"list-templates\"]").on("input","[data-region=\"input\"]",k);a("[data-action=\"clearsearch\"]").on("click",function(){a("[data-region=\"input\"]").val("");h(f.theme);a(this).addClass("d-none")});a("[data-region=\"input\"]").val(document.location.hash.replace("#",""));h(f.theme);return{}});
define ("tool_templatelibrary/search",["jquery","core/ajax","core/log","core/notification","core/templates","core/config"],function(a,b,c,d,e,f){var g=function(b){e.render("tool_templatelibrary/search_results",{templates:b}).done(function(b,c){e.replaceNode(a("[data-region=\"searchresults\"]"),b,c)}).fail(d.exception)},h=function(c){var e=a("[data-field=\"component\"]").val(),f=a("[data-region=\"list-templates\"] [data-region=\"input\"]").val();if(""!==f){a("[data-region=\"list-templates\"] [data-action=\"clearsearch\"]").removeClass("d-none")}else{a("[data-region=\"list-templates\"] [data-action=\"clearsearch\"]").addClass("d-none")}b.call([{methodname:"tool_templatelibrary_list_templates",args:{component:e,search:f,themename:c},done:g,fail:d.exception}],!0,!1)},i=null,j=function(a,b){if(null!==i){window.clearTimeout(i)}i=window.setTimeout(function(){a();i=null},b)},k=function(){j(h.bind(this,f.theme),400)};a("[data-region=\"list-templates\"]").on("change","[data-field=\"component\"]",k);a("[data-region=\"list-templates\"]").on("input","[data-region=\"input\"]",k);a("[data-action=\"clearsearch\"]").on("click",function(){a("[data-region=\"input\"]").val("");h(f.theme);a(this).addClass("d-none")});h(f.theme);return{}});
//# sourceMappingURL=search.min.js.map
File diff suppressed because one or more lines are too long
+1 -3
View File
@@ -52,9 +52,8 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
} else {
$('[data-region="list-templates"] [data-action="clearsearch"]').addClass('d-none');
}
// Trigger the search.
document.location.hash = searchStr;
// Trigger the search.
ajax.call([
{methodname: 'tool_templatelibrary_list_templates',
args: {component: componentStr, search: searchStr, themename: themename},
@@ -96,7 +95,6 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
$(this).addClass('d-none');
});
$('[data-region="input"]').val(document.location.hash.replace('#', ''));
refreshSearch(config.theme);
return {};
});
@@ -38,6 +38,22 @@ use tool_templatelibrary\api;
*/
class list_templates_page implements renderable, templatable {
/** @var string $component The currently selected component */
protected $component;
/** @var string $search The current search */
protected $search;
/**
* Template page constructor
*
* @param string $component
* @param string $search
*/
public function __construct(string $component = '', string $search = '') {
$this->component = $component;
$this->search = $search;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
@@ -46,6 +62,7 @@ class list_templates_page implements renderable, templatable {
public function export_for_template(renderer_base $output) {
$data = new stdClass();
$data->allcomponents = array();
$data->search = $this->search;
$fulltemplatenames = api::list_templates();
$pluginmanager = core_plugin_manager::instance();
$components = array();
@@ -59,6 +76,7 @@ class list_templates_page implements renderable, templatable {
foreach ($components as $component) {
$info = new stdClass();
$info->component = $component;
$info->selected = ($component === $this->component);
if (strpos($component, 'core') === 0) {
$info->name = get_string('coresubsystem', 'tool_templatelibrary', $component);
} else {
@@ -72,10 +72,10 @@
{{/label}}
{{$element}}
<select id="selectcomponent" class="form-control" data-field="component">
<select id="selectcomponent" name="component" class="form-control" data-field="component">
<option value="">{{#str}}all, tool_templatelibrary{{/str}}</option>
{{#allcomponents}}
<option value="{{component}}">{{name}}</option>
<option value="{{component}}" {{#selected}}selected{{/selected}}>{{name}}</option>
{{/allcomponents}}
</select>
{{/element}}
@@ -84,10 +84,10 @@
{{< core_form/element-template }}
{{$element}}
{{< core/search_input_auto }}
{{$label}}{{{ searchstring }}}{{/label}}
{{$placeholder}}{{#str}}
search, core
{{/str}}{{/placeholder}}
{{$label}}
{{#str}} search, tool_templatelibrary {{/str}}
{{/label}}
{{$value}}{{ search }}{{/value}}
{{/ core/search_input_auto }}
{{/element}}
{{/ core_form/element-template }}
+1 -4
View File
@@ -55,10 +55,7 @@ Feature: Manage analytics models
And I choose "Create model" in the open action menu
And I set the field "Enabled" to "Enable"
And I select "__core_course__analytics__target__course_completion" from the "target" singleselect
And I open the autocomplete suggestions list
And I click on "Read actions amount" item in the autocomplete list
And I open the autocomplete suggestions list
And I click on "Any write action in the course" item in the autocomplete list
And I set the field "Indicators" to "Read actions amount, Any write action in the course"
And I select "__core__analytics__time_splitting__single_range" from the "timesplitting" singleselect
And I press "Save changes"
Then I should see "No predictions available yet" in the "Students at risk of not meeting the course completion conditions" "table_row"
+3
View File
@@ -27,6 +27,9 @@ require_once('../../config.php');
$issuerid = required_param('id', PARAM_INT);
$wantsurl = new moodle_url(optional_param('wantsurl', '', PARAM_URL));
$PAGE->set_context(context_system::instance());
$PAGE->set_url(new moodle_url('/auth/oauth2/login.php', ['id' => $issuerid]));
require_sesskey();
if (!\auth_oauth2\api::is_enabled()) {
+2 -1
View File
@@ -182,7 +182,8 @@ How to customize the way the Shibboleth user data is used in Moodle
Among the Shibboleth settings in Moodle there is a field that should contain a
path to a php file that can be used as data manipulation hook.
You can use this if you want to further process the way your Shibboleth
attributes are used in Moodle.
attributes are used in Moodle. Due to security reasons this file cannot be
located within the current site data directory ($CFG->dataroot).
Example 1: Your Shibboleth federation uses an attribute that specifies the
user's preferred language, but the content of this attribute is not
@@ -0,0 +1,75 @@
<?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/>.
/**
* Special setting for auth_shibboleth convert_data.
*
* @package auth_shibboleth
* @copyright 2020 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Admin settings class for the convert_data option.
*
* @package auth_shibboleth
* @copyright 2020 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_shibboleth_admin_setting_convert_data extends admin_setting_configfile {
/**
* Constructor.
*
* @param string $name
* @param string $visiblename
* @param string $description
* @param mixed $defaultdirectory
*/
public function __construct($name, $visiblename, $description, $defaultdirectory) {
parent::__construct($name, $visiblename, $description, $defaultdirectory);
}
/**
* Validate the file path (location).
*
* This method ensures that the file defined as a data modification API exists and is not located in the site
* data directory ($CFG->dataroot). We should prohibit using files from the site data directory as this introduces
* security vulnerabilities.
*
* @param string $filepath The path to the file.
* @return mixed bool true for success or string:error on failure.
*/
public function validate($filepath) {
global $CFG;
if (empty($filepath)) {
return true;
}
// Fail if the file does not exist or it is not readable by the webserver process.
if (!is_readable($filepath)) {
return get_string('auth_shib_convert_data_warning', 'auth_shibboleth');
}
// Fail if the absolute file path matches the currently defined dataroot path.
if (preg_match('/' . preg_quote($CFG->dataroot, '/') . '/', realpath($filepath))) {
return get_string('auth_shib_convert_data_filepath_warning', 'auth_shibboleth');
}
return true;
}
}
+23 -1
View File
@@ -30,7 +30,7 @@ defined('MOODLE_INTERNAL') || die();
* @return bool result
*/
function xmldb_auth_shibboleth_upgrade($oldversion) {
global $CFG, $DB;
global $CFG, $DB, $OUTPUT;
// Automatically generated Moodle v3.5.0 release upgrade line.
// Put any upgrade step following this.
@@ -50,5 +50,27 @@ function xmldb_auth_shibboleth_upgrade($oldversion) {
// Automatically generated Moodle v3.10.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2020110901) {
// The 'Data modification API' setting in the Shibboleth authentication plugin can no longer be configured
// to use files located within the site data directory, as it exposes the site to security risks. Therefore,
// we need to find every existing case and reset the 'Data modification API' setting to its default value.
$convertdataconfig = get_config('auth_shibboleth', 'convert_data');
if (preg_match('/' . preg_quote($CFG->dataroot, '/') . '/', realpath($convertdataconfig))) {
set_config('convert_data', '', 'auth_shibboleth');
$warn = 'Your \'Data modification API\' setting in the Shibboleth authentication plugin is currently
configured to use a file located within the current site data directory ($CFG->dataroot). You are no
longer able to use files from within this directory for this purpose as it exposes your site to security
risks. This setting has been reset to its default value. Please reconfigure it by providing a path
to a file which is not located within the site data directory.';
echo $OUTPUT->notification($warn, 'notifyproblem');
}
upgrade_plugin_savepoint(true, 2020110901, 'auth', 'shibboleth');
}
return true;
}
@@ -38,6 +38,7 @@ $string['auth_shibboleth_select_organization'] = 'For authentication via Shibbol
$string['auth_shib_convert_data'] = 'Data modification API';
$string['auth_shib_convert_data_description'] = 'You can use this API to further modify the data provided by Shibboleth. Read the <a href="{$a}">README</a> for further instructions.';
$string['auth_shib_convert_data_warning'] = 'The file does not exist or is not readable by the webserver process!';
$string['auth_shib_convert_data_filepath_warning'] = 'You cannot use a file that is located within the current site data directory ($CFG->dataroot) as the data modification API.';
$string['auth_shib_changepasswordurl'] = 'Password-change URL';
$string['auth_shib_idp_list'] = 'Identity providers';
$string['auth_shib_idp_list_description'] = 'Provide a list of Identity Provider entityIDs to let the user choose from on the login page.<br />On each line there must be a comma-separated tuple for entityID of the IdP (see the Shibboleth metadata file) and Name of IdP as it shall be displayed in the drop-down list.<br />As an optional third parameter you can add the location of a Shibboleth session initiator that shall be used in case your Moodle installation is part of a multi federation setup.';
+3 -2
View File
@@ -28,6 +28,7 @@ if ($ADMIN->fulltree) {
// We use a couple of custom admin settings since we need to massage the data before it is inserted into the DB.
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_wayf_select.php');
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_idp_configtextarea.php');
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_convert_data_configfile.php');
// Introductory explanation.
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
@@ -38,8 +39,8 @@ if ($ADMIN->fulltree) {
$settings->add(new admin_setting_configtext('auth_shibboleth/user_attribute', get_string('username'),
get_string('auth_shib_username_description', 'auth_shibboleth'), '', PARAM_RAW));
// COnvert Data configuration file.
$settings->add(new admin_setting_configfile('auth_shibboleth/convert_data',
// Convert Data configuration file.
$settings->add(new auth_shibboleth_admin_setting_convert_data('auth_shibboleth/convert_data',
get_string('auth_shib_convert_data', 'auth_shibboleth'),
get_string('auth_shib_convert_data_description', 'auth_shibboleth', $readmeurl), ''));
+5
View File
@@ -1,6 +1,11 @@
This files describes API changes in /auth/shibboleth/*,
information provided here is intended especially for developers.
=== 3.10.1 ===
* The 'Data modification API' (convert_data) setting can no longer be configured to use files located within the
current site data directory ($CFG->dataroot), as it exposes the site to security risks.
=== 3.5.2 ===
* Moved the public function unserializesession in auth/shibboleth/logout.php to auth/shibboleth/classes/helper.php and
+1 -1
View File
@@ -25,6 +25,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2020110900; // The current plugin version (Date: YYYYMMDDXX)
$plugin->version = 2020110901; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2020110300; // Requires this Moodle version
$plugin->component = 'auth_shibboleth'; // Full name of the plugin (used for diagnostics)
@@ -82,16 +82,17 @@ class restore_quiz_decode_testcase extends \core_privacy\tests\provider_testcase
$newcm = duplicate_module($course, get_fast_modinfo($course)->get_cm($quiz->cmid));
$sql = "SELECT qa.answer
$sql = "SELECT qa.id, qa.answer
FROM {quiz} q
LEFT JOIN {quiz_slots} qs ON qs.quizid = q.id
LEFT JOIN {question_answers} qa ON qa.question = qs.questionid
WHERE q.id = :quizid";
$params = array('quizid' => $newcm->instance);
$answers = $DB->get_fieldset_sql($sql, $params);
$this->assertEquals($CFG->wwwroot . '/course/view.php?id=' . $course->id, $answers[0]);
$this->assertEquals($CFG->wwwroot . '/mod/quiz/view.php?id=' . $quiz->cmid, $answers[1]);
$this->assertEquals($CFG->wwwroot . '/grade/report/index.php?id=' . $quiz->cmid, $answers[2]);
$this->assertEquals($CFG->wwwroot . '/mod/quiz/index.php?id=' . $quiz->cmid, $answers[3]);
$answers = $DB->get_records_sql_menu($sql, $params);
$this->assertEquals($CFG->wwwroot . '/course/view.php?id=' . $course->id, $answers[$firstanswer->id]);
$this->assertEquals($CFG->wwwroot . '/mod/quiz/view.php?id=' . $quiz->cmid, $answers[$secondanswer->id]);
$this->assertEquals($CFG->wwwroot . '/grade/report/index.php?id=' . $quiz->cmid, $answers[$thirdanswer->id]);
$this->assertEquals($CFG->wwwroot . '/mod/quiz/index.php?id=' . $quiz->cmid, $answers[$fourthanswer->id]);
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7 -8
View File
@@ -543,11 +543,9 @@ function(
// Filter out all pagination options which are too large for the amount of courses user is enrolled in.
var totalCourseCount = parseInt(root.find(Selectors.courseView.region).attr('data-totalcoursecount'), 10);
if (totalCourseCount) {
itemsPerPage = itemsPerPage.filter(function(pagingOption) {
return pagingOption.value < totalCourseCount;
});
}
itemsPerPage = itemsPerPage.filter(function(pagingOption) {
return pagingOption.value < totalCourseCount || pagingOption.value === 0;
});
var filters = getFilterValues(root);
var config = $.extend({}, DEFAULT_PAGED_CONTENT_CONFIG);
@@ -602,7 +600,8 @@ function(
pageCourses = $.merge(loadedPages[currentPage].courses, courses.slice(0, nextPageStart));
}
} else {
nextPageStart = pageData.limit;
// When the page limit is zero, there is only one page of courses, no start for next page.
nextPageStart = pageData.limit || false;
pageCourses = (pageData.limit > 0) ? courses.slice(0, pageData.limit) : courses;
}
@@ -611,8 +610,8 @@ function(
courses: pageCourses
};
// Set up the next page
var remainingCourses = nextPageStart ? courses.slice(nextPageStart, courses.length) : [];
// Set up the next page (if there is more than one page).
var remainingCourses = nextPageStart !== false ? courses.slice(nextPageStart, courses.length) : [];
if (remainingCourses.length) {
loadedPages[currentPage + 1] = {
courses: remainingCourses
+5 -3
View File
@@ -202,8 +202,9 @@ class main implements renderable, templatable {
// Check and remember the given view.
$this->view = $view ? $view : BLOCK_MYOVERVIEW_VIEW_CARD;
// Check and remember the given page size.
if ($paging == BLOCK_MYOVERVIEW_PAGING_ALL) {
// Check and remember the given page size, `null` indicates no page size set
// while a `0` indicates a paging size of `All`.
if (!is_null($paging) && $paging == BLOCK_MYOVERVIEW_PAGING_ALL) {
$this->paging = BLOCK_MYOVERVIEW_PAGING_ALL;
} else {
$this->paging = $paging ? $paging : BLOCK_MYOVERVIEW_PAGING_12;
@@ -370,8 +371,9 @@ class main implements renderable, templatable {
$select = "instanceid $csql AND fieldid = :fieldid";
$params['fieldid'] = $fieldid;
$distinctablevalue = $DB->sql_compare_text('value');
$values = $DB->get_records_select_menu('customfield_data', $select, $params, $DB->sql_order_by_text('value'),
$values = $DB->get_records_select_menu('customfield_data', $select, $params, '',
"DISTINCT $distinctablevalue, $distinctablevalue AS value2");
\core_collator::asort($values, \core_collator::SORT_NATURAL);
$values = array_filter($values);
if (!$values) {
return [];
@@ -7,30 +7,30 @@ Feature: The my overview block allows users to persistence of their page limits
| student1 | Student | X | student1@example.com | S1 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| Course 2 | C2 | 0 |
| Course 3 | C3 | 0 |
| Course 4 | C4 | 0 |
| Course 5 | C5 | 0 |
| Course 6 | C6 | 0 |
| Course 7 | C7 | 0 |
| Course 8 | C8 | 0 |
| Course 9 | C9 | 0 |
| Course 1 | C01 | 0 |
| Course 2 | C02 | 0 |
| Course 3 | C03 | 0 |
| Course 4 | C04 | 0 |
| Course 5 | C05 | 0 |
| Course 6 | C06 | 0 |
| Course 7 | C07 | 0 |
| Course 8 | C08 | 0 |
| Course 9 | C09 | 0 |
| Course 10 | C10 | 0 |
| Course 11 | C11 | 0 |
| Course 12 | C12 | 0 |
| Course 13 | C13 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C01 | student |
| student1 | C02 | student |
| student1 | C03 | student |
| student1 | C04 | student |
| student1 | C05 | student |
| student1 | C06 | student |
| student1 | C07 | student |
| student1 | C08 | student |
| student1 | C09 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
@@ -38,8 +38,8 @@ Feature: The my overview block allows users to persistence of their page limits
Scenario: Toggle the page limit between page reloads
Given I log in as "student1"
When I click on "[data-toggle='dropdown']" "css_element" in the "Course overview" "block"
And I click on "All" "link"
When I click on "[data-action='limit-toggle']" "css_element" in the "Course overview" "block"
And I click on "All" "link" in the ".dropdown-menu.show" "css_element"
Then I should see "Course 13"
And I reload the page
Then I should see "Course 13"
@@ -47,8 +47,8 @@ Feature: The my overview block allows users to persistence of their page limits
Scenario: Toggle the page limit between grouping changes
Given I log in as "student1"
When I click on "[data-toggle='dropdown']" "css_element" in the "Course overview" "block"
And I click on "All" "link"
When I click on "[data-action='limit-toggle']" "css_element" in the "Course overview" "block"
And I click on "All" "link" in the ".dropdown-menu.show" "css_element"
And I click on "All (except removed from view)" "button" in the "Course overview" "block"
And I click on "In progress" "link" in the "Course overview" "block"
Then I should see "Course 13"
@@ -0,0 +1,191 @@
@block @block_myoverview @javascript
Feature: My overview block pagination
Background:
Given the following "users" exist:
| username | firstname | lastname | email | idnumber |
| student1 | Student | X | student1@example.com | S1 |
And the following "courses" exist:
| fullname | shortname | category |
| Course 01 | C1 | 0 |
| Course 02 | C2 | 0 |
| Course 03 | C3 | 0 |
| Course 04 | C4 | 0 |
| Course 05 | C5 | 0 |
| Course 06 | C6 | 0 |
| Course 07 | C7 | 0 |
| Course 08 | C8 | 0 |
| Course 09 | C9 | 0 |
| Course 10 | C10 | 0 |
| Course 11 | C11 | 0 |
| Course 12 | C12 | 0 |
| Course 13 | C13 | 0 |
| Course 14 | C14 | 0 |
| Course 15 | C15 | 0 |
| Course 16 | C16 | 0 |
| Course 17 | C17 | 0 |
| Course 18 | C18 | 0 |
| Course 19 | C19 | 0 |
| Course 20 | C20 | 0 |
| Course 21 | C21 | 0 |
| Course 22 | C22 | 0 |
| Course 23 | C23 | 0 |
| Course 24 | C24 | 0 |
| Course 25 | C25 | 0 |
Scenario: The pagination controls should be hidden if I am not enrolled in any courses
When I log in as "student1"
Then I should see "No courses" in the "Course overview" "block"
And I should not see "Show" in the "Course overview" "block"
And ".block_myoverview .dropdown-menu.show" "css_element" should not be visible
And ".block_myoverview [data-control='next']" "css_element" should not be visible
And ".block_myoverview [data-control='previous']" "css_element" should not be visible
And I log out
Scenario: The pagination controls should be hidden if I am enrolled in 12 courses or less
Given the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
When I log in as "student1"
Then I should not see "Show" in the "Course overview" "block"
And ".block_myoverview .dropdown-menu.show" "css_element" should not be visible
And ".block_myoverview [data-control='next']" "css_element" should not be visible
And ".block_myoverview [data-control='previous']" "css_element" should not be visible
And I log out
Scenario: The default pagination should be 12 courses
Given the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
| student1 | C13 | student |
When I log in as "student1"
Then I should see "12" in the "[data-action='limit-toggle']" "css_element"
And I log out
Scenario: I should only see pagination limit options less than total number of enrolled courses
Given the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
| student1 | C13 | student |
And I log in as "student1"
When I click on "[data-action='limit-toggle']" "css_element" in the "Course overview" "block"
Then I should see "All" in the ".dropdown-menu.show" "css_element"
And I should see "12" in the ".dropdown-menu.show" "css_element"
And ".block_myoverview [data-control='next']" "css_element" should be visible
And ".block_myoverview [data-control='previous']" "css_element" should be visible
But I should not see "24" in the ".block_myoverview .dropdown-menu.show" "css_element"
And I log out
Scenario: Previous page button should be disabled when on the first page of courses
Given the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
| student1 | C13 | student |
When I log in as "student1"
Then the "class" attribute of ".block_myoverview [data-control='previous']" "css_element" should contain "disabled"
And I log out
Scenario: Next page button should be disabled when on the last page of courses
Given the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
| student1 | C13 | student |
When I log in as "student1"
And I click on "[data-control='next']" "css_element" in the "Course overview" "block"
And I wait until ".block_myoverview [data-control='next']" "css_element" exists
Then the "class" attribute of ".block_myoverview [data-control='next']" "css_element" should contain "disabled"
And I log out
Scenario: Next and previous page buttons should both be enabled when not on last or first page of courses
Given the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
| student1 | C6 | student |
| student1 | C7 | student |
| student1 | C8 | student |
| student1 | C9 | student |
| student1 | C10 | student |
| student1 | C11 | student |
| student1 | C12 | student |
| student1 | C13 | student |
| student1 | C14 | student |
| student1 | C15 | student |
| student1 | C16 | student |
| student1 | C17 | student |
| student1 | C18 | student |
| student1 | C19 | student |
| student1 | C20 | student |
| student1 | C21 | student |
| student1 | C22 | student |
| student1 | C23 | student |
| student1 | C24 | student |
| student1 | C25 | student |
When I log in as "student1"
And I click on "[data-control='next']" "css_element" in the "Course overview" "block"
And I wait until ".block_myoverview [data-control='next']" "css_element" exists
Then the "class" attribute of ".block_myoverview [data-control='next']" "css_element" should not contain "disabled"
And the "class" attribute of ".block_myoverview [data-control='previous']" "css_element" should not contain "disabled"
And I should see "Course 13" in the "Course overview" "block"
And I should see "Course 24" in the "Course overview" "block"
But I should not see "Course 12" in the "Course overview" "block"
And I should not see "Course 25" in the "Course overview" "block"
And I log out
@@ -150,4 +150,17 @@ class behat_block_site_main_menu extends behat_base {
$xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., $activityname)]";
$this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
}
/**
* Return the list of partial named selectors.
*
* @return array
*/
public static function get_partial_named_selectors(): array {
return [
new behat_component_named_selector('Activity', [
"//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., %locator%)]"
]),
];
}
}
@@ -6,15 +6,16 @@ Feature: Edit activities in main menu block
@javascript
Scenario: Edit name of acitivity in-place in site main menu block
Given I log in as "admin"
Given the following "activity" exists:
| activity | forum |
| course | Acceptance test site |
| name | My forum name |
| idnumber | forum |
And I log in as "admin"
And I am on site homepage
And I navigate to "Turn editing on" in current page administration
And I add the "Main menu" block
When I add a "Forum" to section "0" and I fill the form with:
| Forum name | My forum name |
And I click on "Edit title" "link" in the "My forum name" activity in site main menu block
And I set the field "New name for activity My forum name" to "New forum name"
And I press key "13" in the field "New name for activity My forum name"
When I set the field "Edit title" in the "My forum name" "block_site_main_menu > Activity" to "New forum name"
Then I should not see "My forum name"
And I should see "New forum name"
And I follow "New forum name"
@@ -158,4 +158,17 @@ class behat_block_social_activities extends behat_base {
$xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., $activityname)]";
$this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
}
/**
* Return the list of partial named selectors.
*
* @return array
*/
public static function get_partial_named_selectors(): array {
return [
new behat_component_named_selector('Activity', [
"//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., %locator%)]",
]),
];
}
}
@@ -25,9 +25,7 @@ Feature: Edit activities in social activities block
And I click on "Add a new Forum" "link" in the "Add an activity or resource" "dialogue"
And I set the field "Forum name" to "My forum name"
And I press "Save and return to course"
And I click on "Edit title" "link" in the "My forum name" activity in social activities block
And I set the field "New name for activity My forum name" to "New forum name"
And I press key "13" in the field "New name for activity My forum name"
When I set the field "Edit title" in the "My forum name" "block_social_activities > Activity" to "New forum name"
Then I should not see "My forum name" in the "Social activities" "block"
And I should see "New forum name"
And I follow "New forum name"
@@ -84,4 +82,3 @@ Feature: Edit activities in social activities block
And I should not see "My forum name" in the "Social activities" "block"
And I click on "My forum name" "link" in the "Recent activity" "block"
And I should see "My forum name" in the ".breadcrumb" "css_element"
And I log out
@@ -52,9 +52,9 @@
<a href="{{url}}"
title={{#quote}}{{{name}}}{{/quote}}
aria-label='{{#str}} ariaeventlistitem, block_timeline, { "name": {{#quote}}{{{name}}}{{/quote}}, "course": {{#quote}}{{{course.fullnamedisplay}}}{{/quote}}, "date": "{{#userdate}} {{timesort}}, {{#str}} strftimedatetime, core_langconfig {{/str}} {{/userdate}}" } {{/str}}'
><h6 class="event-name text-truncate mb-0">{{#quote}}{{{name}}}{{/quote}}</h6></a>
><h6 class="event-name text-truncate mb-0">{{{name}}}</h6></a>
{{#course.fullnamedisplay}}
<small class="text-muted text-truncate mb-0">{{#quote}}{{{course.fullnamedisplay}}}{{/quote}}</small>
<small class="text-muted text-truncate mb-0">{{{course.fullnamedisplay}}}</small>
{{/course.fullnamedisplay}}
{{#action.actionable}}
<h6 class="mb-0 pt-2">
+5 -1
View File
@@ -116,7 +116,11 @@ class calendar_event_exporter extends event_exporter_base {
$values['islastday'] = false;
$today = $this->related['type']->timestamp_to_date_array($this->related['today']);
$values['popupname'] = $this->event->get_name();
if ($hascourse) {
$values['popupname'] = external_format_string($this->event->get_name(), \context_course::instance($course->id), true);
} else {
$values['popupname'] = external_format_string($this->event->get_name(), \context_system::instance(), true);
}
$times = $this->event->get_times();
if ($duration = $times->get_duration()) {
+6 -3
View File
@@ -115,11 +115,14 @@ if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) {
</td>
<td id="buttonscell">
<div id="addcontrols">
<input name="add" id="add" type="submit" value="<?php echo $OUTPUT->larrow().'&nbsp;'.s(get_string('add')); ?>" title="<?php p(get_string('add')); ?>" /><br />
<input class="btn btn-secondary" name="add" id="add" type="submit" value="<?php echo $OUTPUT->larrow() . '&nbsp;' .
s(get_string('add')); ?>" title="<?php p(get_string('add')); ?>" /><br />
</div>
<div id="removecontrols">
<input name="remove" id="remove" type="submit" value="<?php echo s(get_string('remove')).'&nbsp;'.$OUTPUT->rarrow(); ?>" title="<?php p(get_string('remove')); ?>" />
<input class="btn btn-secondary" name="remove" id="remove" type="submit"
value="<?php echo s(get_string('remove')) . '&nbsp;' . $OUTPUT->rarrow(); ?>"
title="<?php p(get_string('remove')); ?>" />
</div>
</td>
<td id="potentialcell">
@@ -128,7 +131,7 @@ if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) {
</td>
</tr>
<tr><td colspan="3" id='backcell'>
<input type="submit" name="cancel" value="<?php p(get_string('backtocohorts', 'cohort')); ?>" />
<input class="btn btn-secondary" type="submit" name="cancel" value="<?php p(get_string('backtocohorts', 'cohort')); ?>" />
</td></tr>
</table>
</div></form>
+1 -3
View File
@@ -62,9 +62,7 @@ Feature: Add cohorts of users
@javascript
Scenario: Edit cohort name in-place
When I follow "Cohorts"
And I click on "Edit cohort name" "link" in the "Test cohort name" "table_row"
And I set the field "New name for cohort Test cohort name" to "Students cohort"
And I press key "13" in the field "New name for cohort Test cohort name"
And I set the field "Edit cohort name" to "Students cohort"
Then I should not see "Test cohort name"
And I should see "Students cohort"
And I follow "Cohorts"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,2 +1,2 @@
define ("core_course/local/activitychooser/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={regions:{chooser:b("region","chooser-container"),getSectionChooserOptions:function getSectionChooserOptions(a){return"".concat(a," ").concat(b("region","chooser-options-container"))},chooserOption:{container:b("region","chooser-option-container"),actions:b("region","chooser-option-actions-container"),info:b("region","chooser-option-info-container")},chooserSummary:{container:b("region","chooser-option-summary-container"),content:b("region","chooser-option-summary-content-container"),header:b("region","summary-header"),actions:b("region","chooser-option-summary-actions-container")},carousel:b("region","carousel"),help:b("region","help"),modules:b("region","modules"),favouriteTabNav:b("region","favourite-tab-nav"),recommendedTabNav:b("region","recommended-tab-nav"),defaultTabNav:b("region","default-tab-nav"),activityTabNav:b("region","activity-tab-nav"),resourceTabNav:b("region","resources-tab-nav"),favouriteTab:b("region","favourites"),recommendedTab:b("region","recommended"),defaultTab:b("region","default"),activityTab:b("region","activity"),resourceTab:b("region","resources"),getModuleSelector:function getModuleSelector(a){return"[role=\"menuitem\"][data-modname=\"".concat(a,"\"]")},searchResults:b("region","search-results-container"),searchResultItems:b("region","search-result-items-container")},actions:{optionActions:{showSummary:b("action","show-option-summary"),manageFavourite:b("action","manage-module-favourite")},addChooser:b("action","add-chooser-option"),closeOption:b("action","close-chooser-option-summary"),hide:b("action","hide"),search:b("action","search"),clearSearch:b("action","clearsearch")},render:{favourites:b("render","favourites-area")},elements:{section:".section",sectionmodchooser:"button.section-modchooser-link",sitemenu:".block_site_main_menu",sitetopic:"div.sitetopic",tab:"a[data-toggle=\"tab\"]",activetab:"a[data-toggle=\"tab\"][aria-selected=\"true\"]",visibletabs:"a[data-toggle=\"tab\"]:not(.d-none)"}};a.default=c;return a.default});
define ("core_course/local/activitychooser/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={regions:{chooser:b("region","chooser-container"),getSectionChooserOptions:function getSectionChooserOptions(a){return"".concat(a," ").concat(b("region","chooser-options-container"))},chooserOption:{container:b("region","chooser-option-container"),actions:b("region","chooser-option-actions-container"),info:b("region","chooser-option-info-container")},chooserSummary:{container:b("region","chooser-option-summary-container"),content:b("region","chooser-option-summary-content-container"),header:b("region","summary-header"),actions:b("region","chooser-option-summary-actions-container")},carousel:b("region","carousel"),help:b("region","help"),modules:b("region","modules"),favouriteTabNav:b("region","favourite-tab-nav"),defaultTabNav:b("region","default-tab-nav"),activityTabNav:b("region","activity-tab-nav"),favouriteTab:b("region","favourites"),recommendedTab:b("region","recommended"),defaultTab:b("region","default"),activityTab:b("region","activity"),resourceTab:b("region","resources"),getModuleSelector:function getModuleSelector(a){return"[role=\"menuitem\"][data-modname=\"".concat(a,"\"]")},searchResults:b("region","search-results-container"),searchResultItems:b("region","search-result-items-container")},actions:{optionActions:{showSummary:b("action","show-option-summary"),manageFavourite:b("action","manage-module-favourite")},addChooser:b("action","add-chooser-option"),closeOption:b("action","close-chooser-option-summary"),hide:b("action","hide"),search:b("action","search"),clearSearch:b("action","clearsearch")},render:{favourites:b("render","favourites-area")},elements:{section:".section",sectionmodchooser:"button.section-modchooser-link",sitemenu:".block_site_main_menu",sitetopic:"div.sitetopic",tab:"a[data-toggle=\"tab\"]",activetab:"a[data-toggle=\"tab\"][aria-selected=\"true\"]",visibletabs:"a[data-toggle=\"tab\"]:not(.d-none)"}};a.default=c;return a.default});
//# sourceMappingURL=selectors.min.js.map
File diff suppressed because one or more lines are too long
@@ -216,7 +216,6 @@ const registerListenerEvents = (modal, mappedModules, partialFavourite, footerDa
const firstChooserOption = sectionChooserOptions.querySelector(selectors.regions.chooserOption.container);
toggleFocusableChooserOption(firstChooserOption, true);
initTabsKeyboardNavigation(body);
initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions, modal);
return body;
@@ -235,77 +234,6 @@ const registerListenerEvents = (modal, mappedModules, partialFavourite, footerDa
.catch();
};
/**
* Initialise the keyboard navigation controls for the tab list items.
*
* @method initTabsKeyboardNavigation
* @param {HTMLElement} body Our modal that we are working with
*/
const initTabsKeyboardNavigation = (body) => {
// Set up the tab handlers.
const favTabNav = body.querySelector(selectors.regions.favouriteTabNav);
const recommendedTabNav = body.querySelector(selectors.regions.recommendedTabNav);
const defaultTabNav = body.querySelector(selectors.regions.defaultTabNav);
const activityTabNav = body.querySelector(selectors.regions.activityTabNav);
const resourceTabNav = body.querySelector(selectors.regions.resourceTabNav);
const tabNavArray = [favTabNav, recommendedTabNav, defaultTabNav, activityTabNav, resourceTabNav];
tabNavArray.forEach((element) => {
return element.addEventListener('keydown', (e) => {
// The first visible navigation tab link.
const firstLink = e.target.parentElement.querySelector(selectors.elements.visibletabs);
// The last navigation tab link. It would always be the default activities tab link.
const lastLink = e.target.parentElement.lastElementChild;
if (e.keyCode === arrowRight) {
const nextLink = e.target.nextElementSibling;
if (nextLink === null) {
e.target.tabIndex = -1;
firstLink.tabIndex = 0;
firstLink.focus();
} else if (nextLink.classList.contains('d-none')) {
e.target.tabIndex = -1;
lastLink.tabIndex = 0;
lastLink.focus();
} else {
e.target.tabIndex = -1;
nextLink.tabIndex = 0;
nextLink.focus();
}
}
if (e.keyCode === arrowLeft) {
const previousLink = e.target.previousElementSibling;
if (previousLink === null) {
e.target.tabIndex = -1;
lastLink.tabIndex = 0;
lastLink.focus();
} else if (previousLink.classList.contains('d-none')) {
e.target.tabIndex = -1;
firstLink.tabIndex = 0;
firstLink.focus();
} else {
e.target.tabIndex = -1;
previousLink.tabIndex = 0;
previousLink.focus();
}
}
if (e.keyCode === home) {
e.target.tabIndex = -1;
firstLink.tabIndex = 0;
firstLink.focus();
}
if (e.keyCode === end) {
e.target.tabIndex = -1;
lastLink.tabIndex = 0;
lastLink.focus();
}
if (e.keyCode === space) {
e.preventDefault();
e.target.click();
}
});
});
};
/**
* Initialise the keyboard navigation controls for the chooser options.
*
@@ -52,10 +52,8 @@ export default {
help: getDataSelector('region', 'help'),
modules: getDataSelector('region', 'modules'),
favouriteTabNav: getDataSelector('region', 'favourite-tab-nav'),
recommendedTabNav: getDataSelector('region', 'recommended-tab-nav'),
defaultTabNav: getDataSelector('region', 'default-tab-nav'),
activityTabNav: getDataSelector('region', 'activity-tab-nav'),
resourceTabNav: getDataSelector('region', 'resources-tab-nav'),
favouriteTab: getDataSelector('region', 'favourites'),
recommendedTab: getDataSelector('region', 'recommended'),
defaultTab: getDataSelector('region', 'default'),
@@ -102,8 +102,13 @@ class course_handler extends \core_customfield\handler {
has_capability('moodle/course:changelockedcustomfields', $context));
} else {
$context = $this->get_parent_context();
return (!$field->get_configdata_property('locked') ||
guess_if_creator_will_have_course_capability('moodle/course:changelockedcustomfields', $context));
if ($context->contextlevel == CONTEXT_SYSTEM) {
return (!$field->get_configdata_property('locked') ||
has_capability('moodle/course:changelockedcustomfields', $context));
} else {
return (!$field->get_configdata_property('locked') ||
guess_if_creator_will_have_course_capability('moodle/course:changelockedcustomfields', $context));
}
}
}
@@ -53,9 +53,7 @@ Feature: Sections can be edited and deleted in topics format
@javascript
Scenario: Inline edit section name in topics format
When I click on "Edit topic name" "link" in the "li#section-1" "css_element"
And I set the field "New name for topic Topic 1" to "Midterm evaluation"
And I press key "13" in the field "New name for topic Topic 1"
When I set the field "Edit topic name" in the "li#section-1" "css_element" to "Midterm evaluation"
Then I should not see "Topic 1" in the "region-main" "region"
And "New name for topic" "field" should not exist
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
@@ -54,9 +54,7 @@ Feature: Sections can be edited and deleted in weeks format
@javascript
Scenario: Inline edit section name in weeks format
When I click on "Edit week name" "link" in the "li#section-1" "css_element"
And I set the field "New name for week 1 May - 7 May" to "Midterm evaluation"
And I press key "13" in the field "New name for week 1 May - 7 May"
When I set the field "Edit week name" in the "li#section-1" "css_element" to "Midterm evaluation"
Then I should not see "1 May - 7 May" in the "region-main" "region"
And "New name for week" "field" should not exist
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
+9
View File
@@ -60,6 +60,15 @@ if (!empty($add)) {
// will be the closest match we have.
navigation_node::override_active_url(course_get_url($course, $section));
// MDL-69431 Validate that $section (url param) does not exceed the maximum for this course / format.
// If too high (e.g. section *id* not number) non-sequential sections inserted in course_sections table.
// Then on import, backup fills 'gap' with empty sections (see restore_rebuild_course_cache). Avoid this.
$courseformat = course_get_format($course);
$maxsections = $courseformat->get_max_sections();
if ($section > $maxsections) {
print_error('maxsectionslimit', 'moodle', '', $maxsections);
}
list($module, $context, $cw, $cm, $data) = prepare_new_moduleinfo_data($course, $add, $section);
$data->return = 0;
$data->sr = $sectionreturn;
@@ -15,15 +15,16 @@ Feature: Edit activity name in-place
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activity" exists:
| course | C1 |
| activity | forum |
| name | Test forum name |
| description | Test forum description |
| idnumber | forum1 |
When I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I add a "Forum" to section "1" and I fill the form with:
| Forum name | Test forum name |
| Description | Test forum description |
# Rename activity
And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Test forum name')]" "xpath_element"
And I set the field "New name for activity Test forum name" to "Good news"
And I press key "13" in the field "New name for activity Test forum name"
And I set the field "Edit title" in the "Test forum name" "activity" to "Good news"
Then I should not see "Test forum name" in the ".course-content" "css_element"
And "New name for activity Test forum name" "field" should not exist
And I should see "Good news"
@@ -32,12 +33,11 @@ Feature: Edit activity name in-place
And I should not see "Test forum name"
# Cancel renaming
And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Good news')]" "xpath_element"
And I set the field "New name for activity Good news" to "Terrible news"
And I press key "27" in the field "New name for activity Good news"
And I type "Terrible news"
And I press the escape key
And "New name for activity Good news" "field" should not exist
And I should see "Good news"
And I should not see "Terrible news"
And I am on "Course 1" course homepage
And I should see "Good news"
And I should not see "Terrible news"
And I log out
+6 -16
View File
@@ -852,22 +852,12 @@ class behat_course extends behat_base {
* @param string $newactivityname
*/
public function i_change_activity_name_to($activityname, $newactivityname) {
if (!$this->running_javascript()) {
throw new DriverException('Change activity name step is not available with Javascript disabled');
}
$activity = $this->escape($activityname);
$this->execute('behat_course::i_click_on_in_the_activity',
array(get_string('edittitle'), "link", $activity)
);
// Adding chr(10) to save changes.
$this->execute('behat_forms::i_set_the_field_to',
array('title', $this->escape($newactivityname) . chr(10))
);
$this->execute('behat_forms::i_set_the_field_in_container_to', [
get_string('edittitle'),
$activityname,
'activity',
$newactivityname
]);
}
/**
+2 -2
View File
@@ -38,7 +38,7 @@ Feature: Tagging courses
And I expand all fieldsets
Then "Mathematics" "autocomplete_suggestions" should exist
And I set the following fields to these values:
| Tags | Algebra |
| Tags | Mathematics, Algebra |
And I press "Save and display"
And I am on "Course 2" course homepage
And I navigate to "Edit settings" in current page administration
@@ -75,7 +75,7 @@ Feature: Tagging courses
And I navigate to "Course tags" in current page administration
Then I should see "Mathematics" in the ".form-autocomplete-selection" "css_element"
And I set the following fields to these values:
| Tags | Algebra |
| Tags | Mathematics, Algebra |
And I press "Save changes"
And I am on "Course 2" course homepage
And I navigate to "Course tags" in current page administration
+5 -3
View File
@@ -31,9 +31,11 @@ Feature: Rename roles within a course
And "Learner" "button" should exist
And I navigate to course participants
And I set the field "type" in the "Filter 1" "fieldset" to "Roles"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Filter 1" "fieldset"
And I should see "Tutor (Non-editing teacher)" in the ".form-autocomplete-suggestions" "css_element"
And I open the autocomplete suggestions list in the "Filter 1" "fieldset"
And I should see "Learner (Student)" in the ".form-autocomplete-suggestions" "css_element"
And I press the escape key
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Tutor (Non-editing teacher)"
And I click on "Student 1's role assignments" "link"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Student 1" "table_row"
And "Tutor (Non-editing teacher)" "autocomplete_suggestions" should exist
@@ -53,6 +55,6 @@ Feature: Rename roles within a course
And "Learner" "button" should not exist
And I navigate to course participants
And I set the field "type" in the "Filter 1" "fieldset" to "Roles"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Filter 1" "fieldset"
And I open the autocomplete suggestions list in the "Filter 1" "fieldset"
And I should see "Non-editing teacher" in the ".form-autocomplete-suggestions" "css_element"
And I should see "Student" in the ".form-autocomplete-suggestions" "css_element"
@@ -121,7 +121,8 @@ class services_content_item_service_testcase extends \advanced_testcase {
// The call to get_all_content_items() should return the same items as for the course,
// given the user in an editing teacher and can add manual lti instances.
$this->assertEquals(array_column($allcontentitems, 'name'), array_column($coursecontentitems, 'name'));
$this->assertContains('lti', array_column($coursecontentitems, 'name'));
$this->assertContains('lti', array_column($allcontentitems, 'name'));
// Now removing the cap 'mod/lti:addinstance'. This will restrict those items returned by the course-specific method.
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
+1 -1
View File
@@ -118,7 +118,7 @@ class core_customfield_external extends external_api {
'component' => new external_value(PARAM_COMPONENT, 'component'),
'area' => new external_value(PARAM_ALPHANUMEXT, 'area'),
'itemid' => new external_value(PARAM_INT, 'itemid'),
'usescategories' => new external_value(PARAM_INT, 'view has categories'),
'usescategories' => new external_value(PARAM_BOOL, 'view has categories'),
'categories' => new external_multiple_structure(
new external_single_structure(
array(
@@ -12,7 +12,6 @@ Feature: Managers can manage categories for course custom fields
Then I should see "Other fields" in the "#customfield_catlist" "css_element"
And I navigate to "Reports > Logs" in site administration
And I press "Get these logs"
And I log out
Scenario: Edit a category name for custom course fields
Given the following "custom field categories" exist:
@@ -20,15 +19,12 @@ Feature: Managers can manage categories for course custom fields
| Category for test | core_course | course | 0 |
And I log in as "admin"
And I navigate to "Courses > Course custom fields" in site administration
And I click on "Edit category name" "link" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element"
And I set the field "New value for Category for test" to "Good fields"
And I press key "13" in the field "New value for Category for test"
And I set the field "Edit category name" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element" to "Good fields"
Then I should not see "Category for test" in the "#customfield_catlist" "css_element"
And "New value for Category for test" "field" should not exist
And I should see "Good fields" in the "#customfield_catlist" "css_element"
And I navigate to "Reports > Logs" in site administration
And I press "Get these logs"
And I log out
Scenario: Delete a category for custom course fields
Given the following "custom field categories" exist:
@@ -46,7 +42,6 @@ Feature: Managers can manage categories for course custom fields
Then I should not see "Test category" in the "#customfield_catlist" "css_element"
And I navigate to "Reports > Logs" in site administration
And I press "Get these logs"
And I log out
Scenario: Move field in the course custom fields to another category
Given the following "custom field categories" exist:
@@ -78,7 +73,6 @@ Feature: Managers can manage categories for course custom fields
And I press "Move \"Field1\""
And I follow "After field Field2"
And "Field1" "text" should appear after "Field2" "text"
And I log out
Scenario: Reorder course custom field categories
Given the following "custom field categories" exist:
@@ -108,4 +102,3 @@ Feature: Managers can manage categories for course custom fields
And "Field1" "text" should appear after "Category1" "text"
And "Category2" "text" should appear after "Field1" "text"
And "Category3" "text" should appear after "Category2" "text"
And I log out
+1 -1
View File
@@ -36,7 +36,7 @@ if ($ADMIN->fulltree) {
$student = get_archetype_roles('student');
$student = reset($student);
$settings->add(new admin_setting_configselect('enrol_cohort/roleid',
get_string('defaultrole', 'role'), '', $student->id, $options));
get_string('defaultrole', 'role'), '', $student->id ?? null, $options));
$options = array(
ENROL_EXT_REMOVED_UNENROL => get_string('extremovedunenrol', 'enrol'),
+5 -1
View File
@@ -86,7 +86,11 @@ if ($ADMIN->fulltree) {
$options = get_default_enrol_roles(context_system::instance());
$student = get_archetype_roles('student');
$student = reset($student);
$settings->add(new admin_setting_configselect('enrol_database/defaultrole', get_string('defaultrole', 'enrol_database'), get_string('defaultrole_desc', 'enrol_database'), $student->id, $options));
$settings->add(new admin_setting_configselect('enrol_database/defaultrole',
get_string('defaultrole', 'enrol_database'),
get_string('defaultrole_desc', 'enrol_database'),
$student->id ?? null,
$options));
}
$settings->add(new admin_setting_configcheckbox('enrol_database/ignorehiddencourses', get_string('ignorehiddencourses', 'enrol_database'), get_string('ignorehiddencourses_desc', 'enrol_database'), 0));
+4
View File
@@ -45,6 +45,10 @@ class enrol_fee_plugin extends enrol_plugin {
$currencies[$c] = new lang_string($c, 'core_currencies');
}
uasort($currencies, function($a, $b) {
return strcmp($a, $b);
});
return $currencies;
}
+1 -1
View File
@@ -71,7 +71,7 @@ if ($ADMIN->fulltree) {
$student = get_archetype_roles('student');
$student = reset($student);
$settings->add(new admin_setting_configselect('enrol_fee/roleid',
get_string('defaultrole', 'enrol_fee'), get_string('defaultrole_desc', 'enrol_fee'), $student->id, $options));
get_string('defaultrole', 'enrol_fee'), get_string('defaultrole_desc', 'enrol_fee'), $student->id ?? null, $options));
}
$settings->add(new admin_setting_configduration('enrol_fee/enrolperiod',
+1 -1
View File
@@ -63,7 +63,7 @@ if ($ADMIN->fulltree) {
$student = get_archetype_roles('student');
$student = reset($student);
$settings->add(new admin_setting_configselect('enrol_manual/roleid',
get_string('defaultrole', 'role'), '', $student->id, $options));
get_string('defaultrole', 'role'), '', $student->id ?? null, $options));
}
$options = array(2 => get_string('coursestart'), 3 => get_string('today'), 4 => get_string('now', 'enrol_manual'));
+15 -16
View File
@@ -130,18 +130,17 @@ Feature: Teacher can search and enrol users one by one into the course
Scenario: Searching for a non-existing user
Given I navigate to course participants
And I press "Enrol users"
And I set the field "Select users" to "qwertyuiop"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
And I click on "Select users" "field"
And I type "qwertyuiop"
Then I should see "No suggestions"
@javascript
Scenario: If there are less than 100 matching users, all are displayed for selection
Given I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "example.com"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
And I click on "Student 099" item in the autocomplete list
Then I should see "Student 099"
When I click on "Select users" "field"
And I type "example.com"
Then "Student 099" "autocomplete_suggestions" should exist
@javascript
Scenario: If there are more than 100 matching users, inform there are too many.
@@ -151,8 +150,8 @@ Feature: Teacher can search and enrol users one by one into the course
| student101 | Student | 101 | student101@example.com |
And I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "example.com"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
When I click on "Select users" "field"
And I type "example.com"
Then I should see "Too many users (>100) to show"
@javascript
@@ -161,8 +160,8 @@ Feature: Teacher can search and enrol users one by one into the course
| maxusersperpage | 5 |
And I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "student00"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
When I click on "Select users" "field"
And I type "student00"
Then I should see "Too many users (>5) to show"
@javascript
@@ -177,18 +176,18 @@ Feature: Teacher can search and enrol users one by one into the course
When I am on "Course 001" course homepage
Then I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "student100@example.com"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
And I click on "Select users" "field"
And I type "student100@example.com"
Then I should see "student100@example.com, CITY1, GB, 1234567892, 1234567893, ABC1, ABC2"
# Remove identity field in setting User policies
And the following config values are set as admin:
| showuseridentity | idnumber,email,phone1,phone2,department,institution |
When I am on "Course 001" course homepage
And I am on "Course 001" course homepage
And I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "student100@example.com"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
Then I should see "student100@example.com, 1234567892, 1234567893, ABC1, ABC2"
And I click on "Select users" "field"
And I type "student100@example.com"
And I should see "student100@example.com, 1234567892, 1234567893, ABC1, ABC2"
# The following tests are commented out as a result of MDL-66339.
# @javascript
+31 -17
View File
@@ -328,31 +328,45 @@ class enrol_meta_plugin extends enrol_plugin {
*/
public function edit_instance_validation($data, $files, $instance, $context) {
global $DB;
$errors = array();
$thiscourseid = $context->instanceid;
$c = false;
if (!empty($data['customint1'])) {
$courses = is_array($data['customint1']) ? $data['customint1'] : [$data['customint1']];
foreach ($courses as $courseid) {
$c = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$coursecontext = context_course::instance($c->id);
$coursesidarr = is_array($data['customint1']) ? $data['customint1'] : [$data['customint1']];
list($coursesinsql, $coursesinparams) = $DB->get_in_or_equal($coursesidarr, SQL_PARAMS_NAMED, 'metacourseid');
if ($coursesrecords = $DB->get_records_select('course', "id {$coursesinsql}",
$coursesinparams, '', 'id,visible')) {
// Cast NULL to 0 to avoid possible mess with the SQL.
$instanceid = $instance->id ?? 0;
$sqlexists = 'enrol = :meta AND courseid = :currentcourseid AND customint1 = :courseid AND id != :id';
$existing = $DB->record_exists_select('enrol', $sqlexists, [
$existssql = "enrol = :meta AND courseid = :currentcourseid AND id != :id AND customint1 {$coursesinsql}";
$existsparams = [
'meta' => 'meta',
'currentcourseid' => $thiscourseid,
'courseid' => $c->id,
'id' => $instance->id
]);
if (!$c->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
$errors['customint1'] = get_string('error');
} else if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) {
$errors['customint1'] = get_string('error');
} else if ($c->id == SITEID or $c->id == $thiscourseid or $existing) {
$errors['customint1'] = get_string('error');
'id' => $instanceid
];
$existsparams += $coursesinparams;
if ($DB->record_exists_select('enrol', $existssql, $existsparams)) {
// We may leave right here as further checks do not make sense in case we have existing enrol records
// with the parameters from above.
$errors['customint1'] = get_string('invalidcourseid', 'error');
} else {
foreach ($coursesrecords as $coursesrecord) {
$coursecontext = context_course::instance($coursesrecord->id);
if (!$coursesrecord->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
$errors['customint1'] = get_string('nopermissions', 'error',
'moodle/course:viewhiddencourses');
} else if (!has_capability('enrol/meta:selectaslinked', $coursecontext)) {
$errors['customint1'] = get_string('nopermissions', 'error',
'enrol/meta:selectaslinked');
} else if ($coursesrecord->id == SITEID or $coursesrecord->id == $thiscourseid) {
$errors['customint1'] = get_string('invalidcourseid', 'error');
}
}
}
} else {
$errors['customint1'] = get_string('invalidcourseid', 'error');
}
} else {
$errors['customint1'] = get_string('required');
+142
View File
@@ -922,4 +922,146 @@ class enrol_meta_plugin_testcase extends advanced_testcase {
// Meta-link enrolment has enrol actions for suspended students -- unenrol.
$this->assertCount(1, $actions);
}
/**
* Test how data for instance editing is validated.
*/
public function test_edit_instance_validation() {
global $DB;
$this->resetAfterTest();
$metaplugin = enrol_get_plugin('meta');
// A course with meta enrolment.
$course = $this->getDataGenerator()->create_course();
$coursecontext = context_course::instance($course->id);
// Create a meta enrolment instance.
$instance = (object)$metaplugin->get_instance_defaults();
$instance->id = null;
$instance->courseid = $course->id;
$instance->status = ENROL_INSTANCE_ENABLED;
// Emulate the form data.
$data = [
'customint1' => 0,
'customint2' => 0
];
// Test when no valid 'customint1' field (meta courses links) is provided.
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
// We're going to check the string contents of the errors returned as this is the only way
// to differentiate the errors produced by the 'edit_instance_validation()' method somehow.
// The method always returns what the edit instance form expects and this is an array of form fields
// with the corresponding errors messages.
$this->assertEquals('Required', $errors['customint1']);
// Test when 'customint1' contains an unknown course.
// Fetch the max course id from the courses table and increment it to get
// the course id which surely doesn't exist.
$maxid = $DB->get_field_sql('SELECT MAX(id) FROM {course}');
// Use the same instance as before but set another data.
$data = [
'customint1' => [$maxid + 1],
'customint2' => 0
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
// Test when 'customint1' field already contains courses meta linked with the current one.
$metacourse1 = $this->getDataGenerator()->create_course();
$metaplugin->add_instance($course, array('customint1' => $metacourse1->id));
// Use the same instance as before but set another data.
$data = [
'customint1' => [$metacourse1->id],
'customint2' => 0
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
// Test when a course is set as a not visible and a user doesn't have the capability to use it here.
$metacourse2record = new stdClass();
$metacourse2record->visible = 0;
$metacourse2 = $this->getDataGenerator()->create_course($metacourse2record);
$metacourse2context = context_course::instance($metacourse2->id);
$user = $this->getDataGenerator()->create_user();
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
role_assign($teacherrole->id, $user->id, $metacourse2context->id);
unassign_capability('moodle/course:viewhiddencourses', $teacherrole->id);
$this->setUser($user);
// Use the same instance as before but set another data.
$data = [
'customint1' => [$metacourse2->id],
'customint2' => 0
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertEquals('Sorry, but you do not currently have permissions to do that (moodle/course:viewhiddencourses).',
$errors['customint1']);
// Revert some changes from the last assertion to reuse the course.
$metacourse2->visible = 1;
$DB->update_record('course', $metacourse2);
assign_capability('moodle/course:viewhiddencourses', CAP_ALLOW,
$teacherrole->id, context_course::instance($metacourse2->id));
// Test with no 'enrol/meta:selectaslinked' capability.
unassign_capability('enrol/meta:selectaslinked', $teacherrole->id);
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertEquals('Sorry, but you do not currently have permissions to do that (enrol/meta:selectaslinked).',
$errors['customint1']);
// Back to admin user to regain the capabilities quickly.
$this->setAdminUser();
// Test when meta course id is the site id.
$site = $DB->get_record('course', ['id' => SITEID]);
// Use the same instance as before but set another data.
$data = [
'customint1' => [$site->id],
'customint2' => 0
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
// Test when meta course id is id of the current course.
// Use the same instance as before but set another data.
$data = [
'customint1' => [$course->id],
'customint2' => 0
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertEquals('You are trying to use an invalid course ID', $errors['customint1']);
// Test with the 'customint2' field set (which is groups).
// Prepare some groups data.
$this->getDataGenerator()->create_group(array('courseid' => $course->id));
$this->getDataGenerator()->create_group(array('courseid' => $course->id));
$groups = [];
foreach (groups_get_all_groups($course->id) as $group) {
$groups[$group->id] = format_string($group->name, true, array('context' => $coursecontext));
}
// Use the same instance as before but set another data.
// Use a non-existing group id.
if (!$maxid = $DB->get_field_sql('SELECT MAX(id) FROM {groups}')) {
$maxid = 0;
}
$data = [
'customint1' => [$metacourse2->id],
'customint2' => [$maxid + 1]
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertArrayHasKey('customint2', $errors);
// Test with valid data.
$validgroup = reset($groups);
$data = [
'customint1' => [$metacourse2->id],
'customint2' => $validgroup
];
$errors = $metaplugin->edit_instance_validation($data, [], $instance, $coursecontext);
$this->assertArrayNotHasKey('customint1', $errors);
$this->assertArrayNotHasKey('customint2', $errors);
}
}
+1 -1
View File
@@ -36,6 +36,6 @@ if ($ADMIN->fulltree) {
$student = reset($student);
$settings->add(new admin_setting_configselect_with_advanced('enrol_mnet/roleid',
get_string('defaultrole', 'role'), '',
array('value'=>$student->id, 'adv'=>true), $options));
array('value' => $student->id ?? null, 'adv' => true), $options));
}
}
+4 -1
View File
@@ -66,7 +66,10 @@ if ($ADMIN->fulltree) {
$student = get_archetype_roles('student');
$student = reset($student);
$settings->add(new admin_setting_configselect('enrol_paypal/roleid',
get_string('defaultrole', 'enrol_paypal'), get_string('defaultrole_desc', 'enrol_paypal'), $student->id, $options));
get_string('defaultrole', 'enrol_paypal'),
get_string('defaultrole_desc', 'enrol_paypal'),
$student->id ?? null,
$options));
}
$settings->add(new admin_setting_configduration('enrol_paypal/enrolperiod',
+4 -1
View File
@@ -79,7 +79,10 @@ if ($ADMIN->fulltree) {
$student = get_archetype_roles('student');
$student = reset($student);
$settings->add(new admin_setting_configselect('enrol_self/roleid',
get_string('defaultrole', 'enrol_self'), get_string('defaultrole_desc', 'enrol_self'), $student->id, $options));
get_string('defaultrole', 'enrol_self'),
get_string('defaultrole_desc', 'enrol_self'),
$student->id ?? null,
$options));
}
$settings->add(new admin_setting_configduration('enrol_self/enrolperiod',
+1 -1
View File
@@ -32,6 +32,6 @@ Feature: Users can be added to multiple groups at once
And I click on "Group 1" item in the autocomplete list
And I click on ".form-autocomplete-downarrow" "css_element" in the "student1" "table_row"
And I click on "Group 2" item in the autocomplete list
And I press key "27" in the field "Edit groups for \"Student 1\""
And I press the escape key
And I click on "Save changes" "link" in the "student1" "table_row"
Then I should see "Group 1, Group 2"
+3
View File
@@ -189,6 +189,9 @@ class filter_tex extends moodle_text_filter {
continue;
}
// Sanitize the decoded string, because filter_text_image() injects the final string between script tags.
$texexp = clean_param($texexp, PARAM_TEXT);
$md5 = md5($texexp);
if (!$DB->record_exists("cache_filters", array("filter"=>"tex", "md5key"=>$md5))) {
$texcache = new stdClass();
@@ -128,7 +128,13 @@ class fetch extends external_api {
}
// Fetch the actual data.
$gradeduser = \core_user::get_user($gradeduserid);
$gradeduser = \core_user::get_user($gradeduserid, '*', MUST_EXIST);
// One can access its own grades. Others just if they're graders.
if ($gradeduserid != $USER->id) {
$gradeitem->require_user_can_grade($gradeduser, $USER);
}
$hasgrade = $gradeitem->user_has_grade($gradeduser);
$grade = $gradeitem->get_grade_for_user($gradeduser, $USER);
@@ -127,7 +127,12 @@ class fetch extends external_api {
throw new moodle_exception("The {$itemname} item in {$component}/{$contextid} is not configured for grading with scales");
}
$gradeduser = \core_user::get_user($gradeduserid);
$gradeduser = \core_user::get_user($gradeduserid, '*', MUST_EXIST);
// One can access its own grades. Others just if they're graders.
if ($gradeduserid != $USER->id) {
$gradeitem->require_user_can_grade($gradeduser, $USER);
}
// Set up some items we need to return on other interfaces.
$gradegrade = \grade_grade::fetch(['itemid' => $gradeitem->get_grade_item()->id, 'userid' => $gradeduser->id]);
@@ -100,7 +100,7 @@ class fetch extends external_api {
* @since Moodle 3.8
*/
public static function execute(string $component, int $contextid, string $itemname, int $gradeduserid): array {
global $CFG;
global $CFG, $USER;
require_once("{$CFG->libdir}/gradelib.php");
[
'component' => $component,
@@ -133,7 +133,12 @@ class fetch extends external_api {
}
// Fetch the actual data.
$gradeduser = core_user::get_user($gradeduserid);
$gradeduser = core_user::get_user($gradeduserid, '*', MUST_EXIST);
// One can access its own grades. Others just if they're graders.
if ($gradeduserid != $USER->id) {
$gradeitem->require_user_can_grade($gradeduser, $USER);
}
return self::get_fetch_data($gradeitem, $gradeduser);
}
+3 -2
View File
@@ -657,8 +657,9 @@ class gradingform_guide_controller extends gradingform_controller {
}
$returnvalue['maxscore'] = $maxscore;
$returnvalue['minscore'] = 0;
if (!empty($this->moduleinstance->grade)) {
$graderange = make_grades_menu($this->moduleinstance->grade);
$fieldname = \core_grades\component_gradeitems::get_field_name_for_itemname($this->component, $this->area, 'grade');
if (!empty($this->moduleinstance->{$fieldname})) {
$graderange = make_grades_menu($this->moduleinstance->{$fieldname});
$returnvalue['modulegrade'] = count($graderange) - 1;
}
return $returnvalue;
@@ -178,8 +178,6 @@ class fetch_test extends advanced_testcase {
*/
public function test_execute_fetch_graded(): void {
$this->resetAfterTest();
$generator = \testing_util::get_data_generator();
$guidegenerator = $generator->get_plugin_generator('gradingform_guide');
[
'forum' => $forum,
@@ -189,23 +187,74 @@ class fetch_test extends advanced_testcase {
'teacher' => $teacher,
] = $this->get_test_data();
$this->setUser($teacher);
$this->execute_and_assert_fetch($forum, $controller, $definition, $teacher, $teacher, $student);
}
/**
* Class mates should not get other's grades.
*/
public function test_execute_fetch_does_not_return_data_to_other_students(): void {
$this->resetAfterTest();
[
'forum' => $forum,
'controller' => $controller,
'definition' => $definition,
'student' => $student,
'teacher' => $teacher,
'course' => $course,
] = $this->get_test_data();
$evilstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->expectException(\required_capability_exception::class);
$this->execute_and_assert_fetch($forum, $controller, $definition, $evilstudent, $teacher, $student);
}
/**
* Grades can be returned to graded user.
*/
public function test_execute_fetch_return_data_to_graded_user(): void {
$this->resetAfterTest();
[
'forum' => $forum,
'controller' => $controller,
'definition' => $definition,
'student' => $student,
'teacher' => $teacher,
] = $this->get_test_data();
$this->execute_and_assert_fetch($forum, $controller, $definition, $student, $teacher, $student);
}
/**
* Executes and performs all the assertions of the fetch method with the given parameters.
*/
private function execute_and_assert_fetch ($forum, $controller, $definition, $fetcheruser, $grader, $gradeduser) {
$generator = \testing_util::get_data_generator();
$guidegenerator = $generator->get_plugin_generator('gradingform_guide');
$this->setUser($grader);
$gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
$grade = $gradeitem->get_grade_for_user($student, $teacher);
$instance = $gradeitem->get_advanced_grading_instance($teacher, $grade);
$grade = $gradeitem->get_grade_for_user($gradeduser, $grader);
$instance = $gradeitem->get_advanced_grading_instance($grader, $grade);
$submissiondata = $guidegenerator->get_test_form_data($controller, (int) $student->id,
$submissiondata = $guidegenerator->get_test_form_data($controller, (int) $gradeduser->id,
10, 'Propper good speling',
0, 'ASCII art is not a picture'
);
$gradeitem->store_grade_from_formdata($student, $teacher, (object) [
$gradeitem->store_grade_from_formdata($gradeduser, $grader, (object) [
'instanceid' => $instance->get_id(),
'advancedgrading' => $submissiondata,
]);
$this->setUser($fetcheruser);
// Set up some items we need to return on other interfaces.
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id);
$result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
$this->assertIsArray($result);
@@ -233,7 +282,7 @@ class fetch_test extends advanced_testcase {
$this->assertEquals(100, $result['grade']['maxgrade']);
$this->assertArrayHasKey('gradedby', $result['grade']);
$this->assertEquals(fullname($teacher), $result['grade']['gradedby']);
$this->assertEquals(fullname($grader), $result['grade']['gradedby']);
$this->assertArrayHasKey('criterion', $result['grade']);
$criteria = $result['grade']['criterion'];
@@ -326,6 +375,7 @@ class fetch_test extends advanced_testcase {
'definition' => $definition,
'student' => $student,
'teacher' => $teacher,
'course' => $course,
];
}
@@ -93,7 +93,7 @@ class fetch extends external_api {
* @since Moodle 3.8
*/
public static function execute(string $component, int $contextid, string $itemname, int $gradeduserid): array {
global $CFG;
global $CFG, $USER;
require_once("{$CFG->libdir}/gradelib.php");
[
'component' => $component,
@@ -126,7 +126,12 @@ class fetch extends external_api {
}
// Fetch the actual data.
$gradeduser = \core_user::get_user($gradeduserid);
$gradeduser = \core_user::get_user($gradeduserid, '*', MUST_EXIST);
// One can access its own grades. Others just if they're graders.
if ($gradeduserid != $USER->id) {
$gradeitem->require_user_can_grade($gradeduser, $USER);
}
return self::get_fetch_data($gradeitem, $gradeduser);
}
+1 -1
View File
@@ -101,7 +101,7 @@
}
.gradingform_rubric .criterion .description {
width: 150px;
min-width: 150px;
font-weight: bold;
}
@@ -186,8 +186,6 @@ class fetch_test extends advanced_testcase {
*/
public function test_execute_fetch_graded(): void {
$this->resetAfterTest();
$generator = \testing_util::get_data_generator();
$rubricgenerator = $generator->get_plugin_generator('gradingform_rubric');
[
'forum' => $forum,
@@ -197,23 +195,73 @@ class fetch_test extends advanced_testcase {
'teacher' => $teacher,
] = $this->get_test_data();
$this->setUser($teacher);
$this->execute_and_assert_fetch($forum, $controller, $definition, $teacher, $teacher, $student);
}
/**
* Class mates should not get other's grades.
*/
public function test_execute_fetch_does_not_return_data_to_other_students(): void {
$this->resetAfterTest();
[
'forum' => $forum,
'controller' => $controller,
'definition' => $definition,
'student' => $student,
'teacher' => $teacher,
'course' => $course,
] = $this->get_test_data();
$evilstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->expectException(\required_capability_exception::class);
$this->execute_and_assert_fetch($forum, $controller, $definition, $evilstudent, $teacher, $student);
}
/**
* Grades can be returned to graded user.
*/
public function test_execute_fetch_return_data_to_graded_user(): void {
$this->resetAfterTest();
[
'forum' => $forum,
'controller' => $controller,
'definition' => $definition,
'student' => $student,
'teacher' => $teacher,
] = $this->get_test_data();
$this->execute_and_assert_fetch($forum, $controller, $definition, $student, $teacher, $student);
}
/**
* Executes and performs all the assertions of the fetch method with the given parameters.
*/
private function execute_and_assert_fetch ($forum, $controller, $definition, $fetcheruser, $grader, $gradeduser) {
$generator = \testing_util::get_data_generator();
$rubricgenerator = $generator->get_plugin_generator('gradingform_rubric');
$this->setUser($grader);
$gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
$grade = $gradeitem->get_grade_for_user($student, $teacher);
$instance = $gradeitem->get_advanced_grading_instance($teacher, $grade);
$grade = $gradeitem->get_grade_for_user($gradeduser, $grader);
$instance = $gradeitem->get_advanced_grading_instance($grader, $grade);
$submissiondata = $rubricgenerator->get_test_form_data($controller, (int) $student->id,
$submissiondata = $rubricgenerator->get_test_form_data($controller, (int) $gradeduser->id,
0, 'Too many mistakes. Please try again.',
2, 'Great number of pictures. Well done.'
);
$gradeitem->store_grade_from_formdata($student, $teacher, (object) [
$gradeitem->store_grade_from_formdata($gradeduser, $grader, (object) [
'instanceid' => $instance->get_id(),
'advancedgrading' => $submissiondata,
]);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
$this->setUser($fetcheruser);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id);
$result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
$this->assertIsArray($result);
@@ -241,7 +289,7 @@ class fetch_test extends advanced_testcase {
$this->assertEquals(100, $result['grade']['maxgrade']);
$this->assertArrayHasKey('gradedby', $result['grade']);
$this->assertEquals(fullname($teacher), $result['grade']['gradedby']);
$this->assertEquals(fullname($grader), $result['grade']['gradedby']);
$this->assertArrayHasKey('criteria', $result['grade']);
$criteria = $result['grade']['criteria'];
@@ -348,6 +396,7 @@ class fetch_test extends advanced_testcase {
'definition' => $definition,
'student' => $student,
'teacher' => $teacher,
'course' => $course,
];
}
/**
@@ -59,18 +59,18 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
Then I should see a grade field for "Student 2" and grade item "Item VU"
And I should not see a feedback field for "Student 2" and grade item "Item VU"
And I set the field "ajaxgrade" to "33"
And I press key "13" in the field "ajaxgrade"
And I press the enter key
And I should not see a grade field for "Student 2" and grade item "Item VU"
And I should not see a feedback field for "Student 2" and grade item "Item VU"
And I click on student "Student 3" for grade item "Item VU"
And I set the field "ajaxgrade" to "50"
And I press key "13" in the field "ajaxgrade"
And I click on student "Student 3" for grade item "Item 1"
And I set the field "ajaxgrade" to "80"
And I press key "13" in the field "ajaxgrade"
And I click on student "Student 3" for grade item "Item SU"
And I set the field "ajaxgrade" to "Very good"
And I press key "13" in the field "ajaxgrade"
And I press the shift tab key
And I click on student "Student 3" for grade item "Item VU"
And I set the field "ajaxgrade" to "50"
And I press the enter key
And I click on student "Student 3" for grade item "Item 1"
And I set the field "ajaxgrade" to "80"
And I press the enter key
And the following should exist in the "user-grades" table:
| -1- | -6- | -7- | -13- | -16- |
| Student 2 | - | 33.00 | - | 33.00 |
@@ -88,7 +88,7 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I should see a grade field for "Student 1" and grade item "Course total"
And I should not see a feedback field for "Student 1" and grade item "Course total"
And I set the field "ajaxgrade" to "90"
And I press key "13" in the field "ajaxgrade"
And I press the enter key
And the following should exist in the "user-grades" table:
| -1- | -16- |
| Student 1 | 90.00 |
@@ -112,7 +112,7 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I should see a feedback field for "Student 2" and grade item "Item VU"
And I set the field "ajaxgrade" to "33"
And I set the field "ajaxfeedback" to "Student 2 VU feedback"
And I press key "13" in the field "ajaxfeedback"
And I press the enter key
And I click on student "Student 3" for grade item "Item VL"
And I should not see a grade field for "Student 3" and grade item "Item VL"
And I should not see a feedback field for "Student 3" and grade item "Item VL"
@@ -120,11 +120,11 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I should not see a grade field for "Student 3" and grade item "Item TU"
And I should see a feedback field for "Student 3" and grade item "Item TU"
And I set the field "ajaxfeedback" to "Student 3 TU feedback"
And I press key "13" in the field "ajaxfeedback"
And I press the enter key
And I click on student "Student 2" for grade item "Item SU"
And I set the field "ajaxgrade" to "Very good"
And I set the field "ajaxfeedback" to "Student 2 SU feedback"
And I press key "13" in the field "ajaxfeedback"
And I press the enter key
# Reload grader report:
And I navigate to "View > User report" in the course gradebook
And I navigate to "View > Grader report" in the course gradebook
@@ -148,7 +148,7 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
Then I should see a grade field for "Student 2" and grade item "Item VU"
And I should see a feedback field for "Student 2" and grade item "Item VU"
And I set the field "ajaxgrade" to "33"
And I press key "13" in the field "ajaxgrade"
And I press the enter key
And I click on student "Student 2" for grade item "Course total"
And I should not see a grade field for "Student 3" and grade item "Course total"
And I should not see a feedback field for "Student 3" and grade item "Course total"
@@ -0,0 +1,92 @@
@core @core_grades
Feature: Hidden grade items should be hidden when grade category is locked, but should be visible in overridden category
In order to verify existing grades items display as expected
As an teacher
I need to modify grade items and grade categories
I need to ensure existing grades display in an expected manner
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
And I log in as "admin"
And I am on "Course 1" course homepage
And I navigate to "Setup > Gradebook setup" in the course gradebook
And I press "Add category"
And I set the following fields to these values:
| Category name | Test locked category |
And I press "Save changes"
And I press "Add grade item"
And I set the following fields to these values:
| Item name | Hidden item |
| Hidden | 1 |
| Grade category | Test locked category |
And I press "Save changes"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "View > Grader report" in the course gradebook
And I turn editing mode on
And I give the grade "50.00" to the user "Student 1" for the grade item "Hidden item"
And I press "Save changes"
And I navigate to "Setup > Gradebook setup" in the course gradebook
And I set the following settings for grade item "Test locked category":
| Locked | 1 |
And I press "Save changes"
And I log out
Scenario: Hidden grade items in locked category is hidden for teacher
Given I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "View > User report" in the course gradebook
And I select "Myself" from the "View report as" singleselect
When I select "Student 1" from the "Select all or one user" singleselect
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test locked category total | 100.00 % | 50.00 | 0100 | 50.00 % | - |
| Course total | - | 50.00 | 0100 | 50.00 % | - |
Scenario: Hidden grade items in locked category is hidden for student
Given I log in as "student1"
And I am on "Course 1" course homepage
When I navigate to "User report" in the course gradebook
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test locked category total | 100.00 % | - | 0100 | - | - |
| Course total | - | - | 0100 | - | - |
And I should not see "Hidden item"
Scenario: Hidden grade items in overridden category should show
Given I log in as "teacher1"
And I am on "Course 1" course homepage
And I navigate to "Setup > Gradebook setup" in the course gradebook
And I press "Add category"
And I set the following fields to these values:
| Category name | Test overridden category B|
And I press "Save changes"
And I press "Add grade item"
And I set the following fields to these values:
| Item name | Cat b item |
| Grade category | Test overridden category B |
And I press "Save changes"
When I navigate to "View > Grader report" in the course gradebook
And I turn editing mode on
And I give the grade "50.00" to the user "Student 1" for the grade item "Test overridden category B total"
And I press "Save changes"
And I log out
And I log in as "student1"
And I am on "Course 1" course homepage
And I navigate to "User report" in the course gradebook
Then the following should exist in the "user-grade" table:
| Grade item | Calculated weight | Grade | Range | Percentage | Contribution to course total |
| Test locked category total | 50.00 % | - | 0100 | - | - |
| Test overridden category B total | 50.00 % | 50.00 | 0100 | 50.00 % | - |
| Course total | - | - | 0200 | - | - |
+1 -1
View File
@@ -209,7 +209,7 @@ Feature: We can set the grade to pass value
| Ratings > Grade to pass | 90 |
And I navigate to "View > Grader report" in the course gradebook
And I turn editing mode on
And I click on "Edit forum Rating grade for Test Forum 1" "link"
And I click on "Edit forum Test Forum 1 rating" "link"
And I expand all fieldsets
Then the field "Grade to pass" matches value "90"
And I set the field "Grade to pass" to "80"
@@ -161,14 +161,60 @@ class fetch_test extends advanced_testcase {
$course = $forum->get_course_record();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->setUser($teacher);
$this->execute_and_assert_fetch($forum, $teacher, $teacher, $student);
}
/**
* Class mates should not get other's grades.
*/
public function test_execute_fetch_does_not_return_data_to_other_students(): void {
$this->resetAfterTest();
$forum = $this->get_forum_instance([
// Negative numbers mean a scale.
'grade_forum' => 5,
]);
$course = $forum->get_course_record();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$evilstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->expectException(\required_capability_exception::class);
$this->execute_and_assert_fetch($forum, $evilstudent, $teacher, $student);
}
/**
* Grades can be returned to graded user.
*/
public function test_execute_fetch_return_data_to_graded_user(): void {
$this->resetAfterTest();
$forum = $this->get_forum_instance([
// Negative numbers mean a scale.
'grade_forum' => 5,
]);
$course = $forum->get_course_record();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->execute_and_assert_fetch($forum, $student, $teacher, $student);
}
/**
* Executes the fetch method with the given users and returns the result.
*/
private function execute_and_assert_fetch ($forum, $fetcheruser, $grader, $gradeduser) {
$this->setUser($grader);
$gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
$gradeitem->store_grade_from_formdata($student, $teacher, (object) [
$gradeitem->store_grade_from_formdata($gradeduser, $grader, (object) [
'grade' => 4,
]);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
$this->setUser($fetcheruser);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id);
$result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
$this->assertIsArray($result);
@@ -200,7 +246,9 @@ class fetch_test extends advanced_testcase {
$this->assertEquals(5, $result['grade']['maxgrade']);
$this->assertArrayHasKey('gradedby', $result['grade']);
$this->assertEquals(fullname($teacher), $result['grade']['gradedby']);
$this->assertEquals(fullname($grader), $result['grade']['gradedby']);
return $result;
}
/**
@@ -189,14 +189,75 @@ class fetch_test extends advanced_testcase {
$course = $forum->get_course_record();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->setUser($teacher);
$this->execute_and_assert_fetch($forum, $options, $scale, $teacher, $teacher, $student);
}
/**
* Class mates should not get other's grades.
*/
public function test_execute_fetch_does_not_return_data_to_other_students(): void {
$this->resetAfterTest();
$options = [
'A',
'B',
'C'
];
$scale = $this->getDataGenerator()->create_scale(['scale' => implode(',', $options)]);
$forum = $this->get_forum_instance([
// Negative numbers mean a scale.
'grade_forum' => -1 * $scale->id
]);
$course = $forum->get_course_record();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$evilstudent = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->expectException(\required_capability_exception::class);
$this->execute_and_assert_fetch($forum, $options, $scale, $evilstudent, $teacher, $student);
}
/**
* Grades can be returned to graded user.
*/
public function test_execute_fetch_return_data_to_graded_user(): void {
$this->resetAfterTest();
$options = [
'A',
'B',
'C'
];
$scale = $this->getDataGenerator()->create_scale(['scale' => implode(',', $options)]);
$forum = $this->get_forum_instance([
// Negative numbers mean a scale.
'grade_forum' => -1 * $scale->id
]);
$course = $forum->get_course_record();
$teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
$student = $this->getDataGenerator()->create_and_enrol($course, 'student');
$this->execute_and_assert_fetch($forum, $options, $scale, $student, $teacher, $student);
}
/**
* Executes the fetch method with the given users and returns the result.
*/
private function execute_and_assert_fetch ($forum, $options, $scale, $fetcheruser, $grader, $gradeduser) {
$this->setUser($grader);
$gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
$gradeitem->store_grade_from_formdata($student, $teacher, (object) [
$gradeitem->store_grade_from_formdata($gradeduser, $grader, (object) [
'grade' => 2,
]);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
$this->setUser($fetcheruser);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id);
$result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
$this->assertIsArray($result);
@@ -204,7 +265,7 @@ class fetch_test extends advanced_testcase {
$this->assertEquals('core_grades/grades/grader/gradingpanel/scale', $result['templatename']);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id);
$result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id);
$result = external_api::clean_returnvalue(fetch::execute_returns(), $result);
$this->assertIsArray($result);
@@ -232,7 +293,7 @@ class fetch_test extends advanced_testcase {
$this->assertEquals(3, $result['grade']['maxgrade']);
$this->assertArrayHasKey('gradedby', $result['grade']);
$this->assertEquals(fullname($teacher), $result['grade']['gradedby']);
$this->assertEquals(fullname($grader), $result['grade']['gradedby']);
$this->assertArrayHasKey('options', $result['grade']);
$this->assertCount(count($options), $result['grade']['options']);
+2 -5
View File
@@ -50,15 +50,12 @@ Feature: Organize students into groups
And the "members" select box should not contain "Student 1 (student1@example.com)"
And I navigate to course participants
And I set the field "type" in the "Filter 1" "fieldset" to "Groups"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Filter 1" "fieldset"
And I click on "Group 1" "list_item"
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Group 1"
And I click on "Apply filters" "button"
And I should see "Student 0"
And I should see "Student 1"
And I should not see "Student 2"
And I click on "Group 1" "autocomplete_selection"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Filter 1" "fieldset"
And I click on "Group 2" "list_item"
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Group 2"
And I click on "Apply filters" "button"
And I should see "Student 2"
And I should see "Student 3"
+2 -4
View File
@@ -46,8 +46,7 @@ Feature: The description of a group can be viewed by students and teachers
And I should see "Description for Group A"
And ".groupinfobox" "css_element" should exist
And I set the field "type" in the "Filter 1" "fieldset" to "Groups"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Filter 1" "fieldset"
And I click on "Group B" "list_item"
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Group B"
And I click on "Apply filters" "button"
And I click on "Student 2" "link" in the "participants" "table"
And I click on "Group B" "link"
@@ -96,8 +95,7 @@ Feature: The description of a group can be viewed by students and teachers
And I should see "Description for Group A"
And ".groupinfobox" "css_element" should exist
And I set the field "type" in the "Filter 1" "fieldset" to "Groups"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Filter 1" "fieldset"
And I click on "Group B" "list_item"
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Group B"
And I click on "Apply filters" "button"
And I click on "Student 2" "link" in the "participants" "table"
And I click on "Group B" "link"
+64 -13
View File
@@ -194,7 +194,10 @@ class api {
global $DB;
// Deconstruct the URL and get the pathname associated.
$pathnamehash = self::get_pluginfile_hash($url, $preventredirect);
if (self::can_access_pluginfile_hash($url, $preventredirect)) {
$pathnamehash = self::get_pluginfile_hash($url);
}
if (!$pathnamehash) {
return [false, false];
}
@@ -337,22 +340,28 @@ class api {
* @param factory $factory The \core_h5p\factory object
*/
public static function delete_content_from_pluginfile_url(string $url, factory $factory): void {
global $DB;
// Get the H5P to delete.
list($file, $h5p) = self::get_content_from_pluginfile_url($url);
$pathnamehash = self::get_pluginfile_hash($url);
$h5p = $DB->get_record('h5p', ['pathnamehash' => $pathnamehash]);
if ($h5p) {
self::delete_content($h5p, $factory);
}
}
/**
* Get the pathnamehash from an H5P internal URL.
* If user can access pathnamehash from an H5P internal URL.
*
* @param string $url H5P pluginfile URL poiting to an H5P file.
* @param bool $preventredirect Set to true in scripts that can not redirect (CLI, RSS feeds, etc.), throws exceptions
*
* @return string|false pathnamehash for the file in the internal URL.
* @return bool if user can access pluginfile hash.
* @throws \moodle_exception
* @throws \coding_exception
* @throws \require_login_exception
*/
protected static function get_pluginfile_hash(string $url, bool $preventredirect = true) {
protected static function can_access_pluginfile_hash(string $url, bool $preventredirect = true): bool {
global $USER, $CFG;
// Decode the URL before start processing it.
@@ -365,7 +374,6 @@ class api {
// We only need the slasharguments.
$path = substr($path, strpos($path, '.php/') + 5);
$parts = explode('/', $path);
$filename = array_pop($parts);
// If the request is made by tokenpluginfile.php we need to avoid userprivateaccesskey.
if (strpos($url, '/tokenpluginfile.php')) {
@@ -377,11 +385,6 @@ class api {
$component = array_shift($parts);
$filearea = array_shift($parts);
// Ignore draft files, because they are considered temporary files, so shouldn't be displayed.
if ($filearea == 'draft') {
return false;
}
// Get the context.
try {
list($context, $course, $cm) = get_context_info_array($contextid);
@@ -415,7 +418,7 @@ class api {
$parentcontext = $context->get_parent_context();
if ($parentcontext->contextlevel === CONTEXT_COURSECAT) {
// Check if category is visible and user can view this category.
if (!core_course_category::get($parentcontext->instanceid, IGNORE_MISSING)) {
if (!\core_course_category::get($parentcontext->instanceid, IGNORE_MISSING)) {
send_file_not_found();
}
} else if ($parentcontext->contextlevel === CONTEXT_USER && $parentcontext->instanceid != $USER->id) {
@@ -431,7 +434,7 @@ class api {
// For CONTEXT_MODULE and CONTEXT_COURSE check if the user is enrolled in the course.
// And for CONTEXT_MODULE has permissions view this .h5p file.
if ($context->contextlevel == CONTEXT_MODULE ||
$context->contextlevel == CONTEXT_COURSE) {
$context->contextlevel == CONTEXT_COURSE) {
// Require login to the course first (without login to the module).
require_course_login($course, true, null, !$preventredirect, $preventredirect);
@@ -448,6 +451,54 @@ class api {
}
}
return true;
}
/**
* Get the pathnamehash from an H5P internal URL.
*
* @param string $url H5P pluginfile URL poiting to an H5P file.
*
* @return string|false pathnamehash for the file in the internal URL.
*
* @throws \moodle_exception
*/
protected static function get_pluginfile_hash(string $url) {
// Decode the URL before start processing it.
$url = new \moodle_url(urldecode($url));
// Remove params from the URL (such as the 'forcedownload=1'), to avoid errors.
$url->remove_params(array_keys($url->params()));
$path = $url->out_as_local_url();
// We only need the slasharguments.
$path = substr($path, strpos($path, '.php/') + 5);
$parts = explode('/', $path);
$filename = array_pop($parts);
// If the request is made by tokenpluginfile.php we need to avoid userprivateaccesskey.
if (strpos($url, '/tokenpluginfile.php')) {
array_shift($parts);
}
// Get the contextid, component and filearea.
$contextid = array_shift($parts);
$component = array_shift($parts);
$filearea = array_shift($parts);
// Ignore draft files, because they are considered temporary files, so shouldn't be displayed.
if ($filearea == 'draft') {
return false;
}
// Get the context.
try {
list($context, $course, $cm) = get_context_info_array($contextid);
} catch (\moodle_exception $e) {
throw new \moodle_exception('invalidcontextid', 'core_h5p');
}
// Some components, such as mod_page or mod_resource, add the revision to the URL to prevent caching problems.
// So the URL contains this revision number as itemid but a 0 is always stored in the files table.
// In order to get the proper hash, a callback should be done (looking for those exceptions).
+2 -1
View File
@@ -127,7 +127,8 @@ class player {
$url,
$config,
$this->factory,
$this->messages
$this->messages,
$this->preventredirect
);
if ($file) {
$this->context = \context::instance_by_id($file->get_contextid());
+32
View File
@@ -0,0 +1,32 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
*
* Do not edit this file manually! It contains just a subset of strings
* needed during the very first steps of installation. This file was
* generated automatically by export-installer.php (which is part of AMOS
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
* list of strings defined in /install/stringnames.txt.
*
* @package installer
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['thislanguage'] = 'Аԥсуа бызшәа';
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+47
View File
@@ -0,0 +1,47 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
*
* Do not edit this file manually! It contains just a subset of strings
* needed during the very first steps of installation. This file was
* generated automatically by export-installer.php (which is part of AMOS
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
* list of strings defined in /install/stringnames.txt.
*
* @package installer
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['cannotcreatedboninstall'] = '<p>Kon nie die databasis skep nie.</p>
<p>Die gespesifiseerde databasis bestaan nie en die aangetoonde gebruiker het nie toestemming om die databasis te skep nie.</p>
<p>Die werf se administrateur moet die konfigurasie van databasisse verifieer.</p>';
$string['cannotcreatelangdir'] = 'Kan nie taalgids skep nie';
$string['cannotcreatetempdir'] = 'Kan nie tydelike gids skep nie';
$string['cannotdownloadcomponents'] = 'Kan nie komponente aflaai nie';
$string['cannotdownloadzipfile'] = 'Kan nie ZIP-lêer aflaai nie';
$string['cannotfindcomponent'] = 'Kan nie komponent vind nie';
$string['cannotsavemd5file'] = 'Kan nie md5-lêer stoor nie';
$string['cannotsavezipfile'] = 'Kan nie ZIP-lêer stoor nie';
$string['cannotunzipfile'] = 'Kan nie lêer uitpak nie';
$string['componentisuptodate'] = 'Komponent is bygewerk';
$string['dmlexceptiononinstall'] = '<p>\'n Databasisfout het opgeduik [{$a->errorcode}].<br />{$a->debuginfo}</p>';
$string['downloadedfilecheckfailed'] = 'Kontrolering van afgelaaide lêer het misluk';
$string['invalidmd5'] = 'Die kontroleveranderlike was verkeerd - probeer weer';
$string['missingrequiredfield'] = 'Een of ander verlangde veld ontbreek';
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
+2 -3
View File
@@ -1,6 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -13,7 +12,7 @@
// 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/>.
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer

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