Compare commits

..

255 Commits

Author SHA1 Message Date
Sara Arjona 805361d871 Moodle release 3.7.5 2020-03-06 12:34:06 +01:00
AMOS bot 8d68b0b251 Automatically generated installer lang files 2020-03-06 00:10:59 +00:00
Sara Arjona efc431ba0d weekly release 3.7.4+ 2020-03-05 17:31:24 +01:00
Sara Arjona 9df4aa7210 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-03-05 17:31:20 +01:00
Michael Hawkins 8481609ba4 MDL-67861 core: Fix getremoteaddr unit test to match new proxy setup 2020-03-05 14:39:55 +08:00
Brendan Heywood 194406e923 MDL-67861 core: Added $CFG->reverseproxyignore IP subnet list
If your server is behind multiple reverse proxies that append to the
X-Forwarded-For header then you will need to specify a comma separated
list of ip addresses or subnets of the reverse proxies to be ignored
in order to find the users correct IP address.
2020-03-05 01:27:48 +01:00
Brendan Heywood c4665bcf95 MDL-67861 libraries: Refactor is_ip_in_subnet_list in ip_utils 2020-03-05 01:27:48 +01:00
Brendan Heywood c70d7d0386 MDL-67861 admin: Default $CFG->getremoteaddrconf to only use REMOTE_ADDR 2020-03-05 01:27:48 +01:00
Brendan Heywood 4a3a673d1e MDL-67861 core: Use last ip in X-Forwarded-For list 2020-03-05 01:27:48 +01:00
Andrew Nicols 31260f8667 MDL-65106 theme_classic: Remove unused variable 2020-03-05 08:17:03 +08:00
Andrew Nicols cb3deb89c1 Merge branch 'MDL-65106-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2020-03-05 08:16:45 +08:00
Eloy Lafuente (stronk7) b21aad0837 Merge branch 'MDL-62768-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-03-04 18:37:28 +01:00
Sara Arjona 8ba10c6666 Merge branch 'MDL-67767-37' of git://github.com/dpalou/moodle into MOODLE_37_STABLE 2020-03-04 15:05:07 +01:00
Dani Palou b7b45f8c0b MDL-67767 tool_mobile: Allow using more characters in forcedurlscheme 2020-03-04 14:25:25 +01:00
Sara Arjona a2ff87ba44 Merge branch 'MDL-67863-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2020-03-04 14:06:34 +01:00
Sara Arjona 53a3991927 Merge branch 'MDL-67969-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2020-03-04 12:58:27 +01:00
Marina Glancy 6b502fbc2b MDL-56287 gradereport_history: Separate groups queries improved 2020-03-04 11:47:33 +01:00
Jun Pataleta 8509f1feb4 MDL-56287 gradereport_history: Show users from groups that can be viewed 2020-03-04 11:47:33 +01:00
Eloy Lafuente (stronk7) b692832347 Merge branch 'MDL-67641-37' of git://github.com/dpalou/moodle into MOODLE_37_STABLE 2020-03-04 10:48:05 +01:00
Sara Arjona a5a6a9c91c Merge branch 'MDL-68008-37' of git://github.com/ferranrecio/moodle into MOODLE_37_STABLE 2020-03-04 08:41:43 +01:00
Dani Palou 25c09b1b1d MDL-67641 auth: Fix shortname type in get_signup_settings WS 2020-03-04 08:12:13 +01:00
AMOS bot f00ddea3fc Automatically generated installer lang files 2020-03-04 00:11:19 +00:00
Eloy Lafuente (stronk7) 4caf331102 Merge branch 'MDL-67728-37' of git://github.com/crazyserver/moodle into MOODLE_37_STABLE 2020-03-03 19:50:26 +01:00
Eloy Lafuente (stronk7) 0705bb0c07 Merge branch 'MDL-67971-37' of git://github.com/sarjona/moodle into MOODLE_37_STABLE 2020-03-03 19:02:38 +01:00
Sara Arjona 4748f89945 Merge branch 'MDL-67993-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2020-03-03 18:06:50 +01:00
Ferran Recio f0abaec208 MDL-68008 tool_capability: shows multiple contexts when overrides exists 2020-03-03 17:54:26 +01:00
Sara Arjona 2933c4e061 Merge branch 'MDL-68048-37-behatnotfound' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-03-03 17:02:11 +01:00
Sara Arjona b808efac50 Merge branch 'MDL-68060-37-huburlcompare' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-03-03 13:10:24 +01:00
Sara Arjona 0df30e445f Merge branch 'MDL-67891-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-03-03 12:48:35 +01:00
Bas Brands d4f03eb0b1 MDL-65106 theme_classic: set custom navigationitem icon 2020-03-03 11:53:48 +01:00
Sara Arjona 635b4db751 Merge branch 'MDL-63316-37' of https://github.com/azito122/moodle into MOODLE_37_STABLE 2020-03-03 11:11:05 +01:00
Sara Arjona 1821997b7c Merge branch 'MDL-67945-37' of git://github.com/ferranrecio/moodle into MOODLE_37_STABLE 2020-03-03 10:10:58 +01:00
Sara Arjona a97fde462d Merge branch 'MDL-67749-37' of git://github.com/dpalou/moodle into MOODLE_37_STABLE 2020-03-03 09:30:50 +01:00
Adrian Hutchinson 9bcfb74256 MDL-67988 mod_lti: remove padding from JWS base64url encoding 2020-03-02 14:01:36 +01:00
Paul Holden c0fdc91ea3 MDL-67891 tool_cohortroles: move upgrade step inside plugin.
The step added in MDL-67458 was added to core, which broke the upgrade
process if this plugin had been uninstalled prior.
2020-03-02 08:50:27 +00:00
Sara Arjona da1d1af843 MDL-67971 core_badges: review issuer URL 2020-03-02 08:02:40 +01:00
Andrew Zito 85d5216840 MDL-63316 participants: lastname sort for participants table 2020-02-28 14:33:27 -05:00
Eloy Lafuente (stronk7) 95eb7d8343 weekly release 3.7.4+ 2020-02-28 12:22:35 +01:00
Bas Brands 720a26266a MDL-67863 theme_boost: change keyboard tab order
Move navdrawer up in the dom for a more logical tab order
Hide navdrawer links for tab / screenreader when navdrawer is closed
2020-02-27 17:12:47 +01:00
Eloy Lafuente (stronk7) 37906d63f9 Merge branch 'MDL-67865-37' of git://github.com/rezaies/moodle into MOODLE_37_STABLE 2020-02-26 23:37:10 +01:00
Eloy Lafuente (stronk7) 870e202546 Merge branch 'MDL-64686-37' of git://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2020-02-26 23:27:44 +01:00
Eloy Lafuente (stronk7) 50a72fbcd6 Merge branch 'MDL-67758-37' of git://github.com/dpalou/moodle into MOODLE_37_STABLE 2020-02-26 17:36:07 +01:00
Claude Vervoort b3172cc0fd MDL-67132 mod_lti: document new param
(amended to move the upgrade.txt info to correct 3.7.5)
2020-02-26 17:29:21 +01:00
Claude Vervoort dc39cee4f9 MDL-67132 mod_lti: call grade api to trigger course total computation 2020-02-26 17:27:33 +01:00
Eloy Lafuente (stronk7) f05ff7a66d Merge branch 'MDL-67979-37-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-02-26 17:13:47 +01:00
Anthony Forth cb2a49009c MDL-67945 enrol: missing $DB in edit_instance_form 2020-02-26 16:37:14 +01:00
David Mudrák b541ee20fb MDL-68060 registration: Improve the sites directory location check
This allows to define the custom HUB_MOODLEORGHUBURL with HTTP Basic
Auth credentials so that the registration features can be tested against
our staging site.
2020-02-26 10:59:27 +01:00
Jun Pataleta c975694cf5 Merge branch 'MOODLE_37_MDL-67980' of https://github.com/golenkovm/moodle into MOODLE_37_STABLE 2020-02-26 14:30:30 +08:00
Shamim Rezaie 8c39267d92 MDL-67969 lib: Fix duplicate blockinstanceid for fake blocks 2020-02-26 16:38:52 +11:00
David Balch b74030550e MDL-67993 roles: Fix pix_icon() calls. 2020-02-26 12:15:42 +08:00
Eloy Lafuente (stronk7) 2cfcae67a0 Merge branch 'MDL-67644-37' of git://github.com/dpalou/moodle into MOODLE_37_STABLE 2020-02-26 00:10:24 +01:00
Eloy Lafuente (stronk7) dbb784d1ab Merge branch 'MDL-67806-37' of git://github.com/dpalou/moodle into MOODLE_37_STABLE 2020-02-25 23:58:17 +01:00
Paul Holden be941e5a05 MDL-62768 tool_policy: add page title & breadcrumb navigation. 2020-02-25 22:06:04 +00:00
Paul Holden 87080161e0 MDL-62768 tool_dataprivacy: add page breadcrumbs to navigation. 2020-02-25 21:36:46 +00:00
Helen Foster 62931543fb MDL-67979 lang: Import fixed English strings (en_fix)
Significant string changes:

* configcustommenuitems,core_admin - corrected example
* custommenuitems_desc,tool_mobile - fallback behaviour of custom menu
  items in the app
2020-02-25 12:24:44 +01:00
Eloy Lafuente (stronk7) 3cb6a5a3b2 Merge branch 'MDL-67862-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-02-25 12:09:58 +01:00
Eloy Lafuente (stronk7) 765aef276c Merge branch 'MDL-67364-37' of git://github.com/mickhawkins/moodle into MOODLE_37_STABLE 2020-02-25 12:05:57 +01:00
David Mudrák 2da65dae97 MDL-68048 behat: Fix the ElementNotFoundException message wording
The exception class itself adds the "not found" to the error message.
2020-02-25 11:55:59 +01:00
Mikhail Golenkov 4be6148785 MDL-67980 tasks: Sort ad-hoc tasks by nextruntime. 2020-02-24 09:36:57 +11:00
Pau Ferrer Ocaña 5e4ffd0559 MDL-67728 behat: Increase app start timeout 2020-02-21 12:45:58 +01:00
Pau Ferrer Ocaña 99d5aff09b MDL-67728 behat: Improve behat app selectors 2020-02-21 12:45:58 +01:00
Luca Bösch ae31e9dfa8 MDL-64686 theme: align course search form for small screens sizes. 2020-02-21 06:35:11 +01:00
Jun Pataleta d077ffd3a5 weekly release 3.7.4+ 2020-02-21 11:03:08 +08:00
Jun Pataleta c61f9a4484 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-02-21 11:02:29 +08:00
Eloy Lafuente (stronk7) 37ef74572d Merge branch 'MDL-67727-37' of git://github.com/crazyserver/moodle into MOODLE_37_STABLE 2020-02-20 16:13:02 +01:00
Luke Tucker d08e7b7e8a MDL-50455: tool_capability: Use static cache when loading context data 2020-02-20 00:30:16 +01:00
Eloy Lafuente (stronk7) 4441cfe9ce Merge branch 'MDL-67942-37' of https://github.com/HuongNV13/moodle into MOODLE_37_STABLE 2020-02-19 19:18:58 +01:00
Eloy Lafuente (stronk7) 9dd7ac3bc3 Merge branch 'MDL-67947_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2020-02-19 17:48:50 +01:00
Tim Hunt 2a912052bc MDL-67947 questions: questions_in_use should ask all components
Previously it was only checking mods.
2020-02-19 11:56:31 +00:00
Dani Palou addc07be5a MDL-67749 ws: Set private token when reset or manual create token 2020-02-19 12:05:05 +01:00
Huong Nguyen 6aaa78f044 MDL-67942 Quiz: Quiz attempt report delete_selected_attempts issue 2020-02-19 15:36:38 +07:00
Eloy Lafuente (stronk7) 6ffe3ecc9f Merge branch 'MDL-67471_37' of https://github.com/t-schroeder/moodle into MOODLE_37_STABLE 2020-02-18 23:54:55 +01:00
Eloy Lafuente (stronk7) c4b472700b Merge branch 'MDL-61390-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-02-18 19:06:39 +01:00
Eloy Lafuente (stronk7) 414a461e41 Merge branch 'MDL-67953-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2020-02-18 18:07:45 +01:00
Shamim Rezaie 952d572921 MDL-67865 output: Fix id of the dropdown trigger 2020-02-18 16:20:15 +11:00
Andrew Nicols fc01f863d3 MDL-67953 grunt: Spawn new process for gherkinlint
Gherkinlint stores the list of processed features for duplicate
detection in an Object which is statically defined.
This causes it to bleed between runs.

To alleviate this we must spawn a new process.

Prior to this patchset we were calling a new Gherkinlint process which
had the same effect anyway.
2020-02-18 08:24:13 +08:00
Eloy Lafuente (stronk7) 1b43f6b06d Merge branch 'MDL-61389-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-02-17 23:30:17 +01:00
Eloy Lafuente (stronk7) 86f297c7c2 Merge branch 'MDL-67817-m37-master' of https://github.com/dthies/moodle into MOODLE_37_STABLE 2020-02-17 22:09:39 +01:00
Tim Schroeder 21bac71bef MDL-67471 message: fixed mark_notification_read with messaging disabled 2020-02-17 09:16:57 +01:00
Jun Pataleta b400040cff MDL-61390 mod_forum: Create template for forum search results 2020-02-17 15:58:16 +08:00
Jun Pataleta 0846b4af08 MDL-61389 mod_forum: Descriptive aria-label for "Discuss this topic" 2020-02-17 15:52:20 +08:00
AMOS bot d927703799 Automatically generated installer lang files 2020-02-16 00:11:18 +00:00
Daniel Thies 8fedcb49a5 MDL-67817 core_date: Add test for timezone localization strings 2020-02-14 11:54:55 -06:00
Daniel Thies 0c9fe38643 MDL-67817 core_lang: Update timezone strings 2020-02-14 11:54:55 -06:00
Sara Arjona 5c7966eacf weekly release 3.7.4+ 2020-02-14 12:12:07 +01:00
Sara Arjona 0ee03dd15a Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-02-14 12:12:05 +01:00
Jun Pataleta 6dbf1dee71 Merge branch 'MDL-67965-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2020-02-14 13:25:01 +08:00
Andrew Nicols a884eea913 MDL-67965 behat: Get theme-specific context classes correctly 2020-02-14 10:15:49 +08:00
Michael Hawkins b41b74aacb MDL-67364 output: Add unit testing for editor_scss_to_css 2020-02-13 22:53:31 +08:00
Michael Hawkins fa0e63f9da MDL-67364 output: Allow child themes to use parent editor_scss config
This still allows child themes to override editor_scss, but will fall
back to what the parent is using if they do not specify it. This
negates the need for every child them to have the config duplicated
in order to utilise it.
2020-02-13 22:53:31 +08:00
Pau Ferrer Ocaña 306eaa606f MDL-67727 behat: Reset ionic app properly 2020-02-13 08:37:22 +01:00
Andrew Nicols 9ff79ab562 MDL-67953 grunt: Work around spawn length limits 2020-02-13 14:21:49 +08:00
Eloy Lafuente (stronk7) 4011bfc71f Merge branch 'MDL-67876_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2020-02-12 15:49:47 +01:00
Dani Palou dedb1592cb MDL-67644 tool_mobile: Add OAuth 2 providers in disabled features 2020-02-12 14:13:19 +01:00
Tim Hunt 603e31b820 MDL-67876 forms: not all field types need validation JS 2020-02-12 10:04:20 +00:00
Eloy Lafuente (stronk7) 3dab17b872 Merge branch 'MDL-67532-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-02-11 23:08:18 +01:00
Sara Arjona e81b6194e6 Merge branch 'MDL-59303-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-02-11 13:52:41 +01:00
Sara Arjona b54c18392f Merge branch 'MDL-66847-37' of git://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2020-02-11 12:28:56 +01:00
Sara Arjona 7960af6567 Merge branch 'MDL-66834-MOODLE_37_STABLE' of https://github.com/kepeter/moodle into MOODLE_37_STABLE 2020-02-11 11:54:31 +01:00
Sara Arjona f24cc998f0 Merge branch 'mdl67142-moodle37' of https://github.com/AngadSethi/moodle into MOODLE_37_STABLE 2020-02-11 10:19:10 +01:00
Sara Arjona 07265da01c Merge branch 'MDL-67894-37' of https://github.com/grabs/moodle into MOODLE_37_STABLE 2020-02-11 08:20:49 +01:00
Dani Palou 6b2bbcbb0e MDL-67758 airnotifier: Send wwwroot to airnotifier 2020-02-10 11:55:52 +01:00
Dani Palou c1bc5df576 MDL-67806 tool_mobile: Add Dark mode option in disabled features
We must allow site admins to remotely disable that feature in the app
2020-02-10 11:53:52 +01:00
Jun Pataleta 18aabbd5d5 MDL-67862 message: Render dialogue header only when necessary 2020-02-10 13:16:19 +08:00
Angad Sethi 4f5e2fc266 MDL-67142 quiz: fixed error when deleting saved questions long-name-quiz
An error was showing up while deleting questions
(in the question_save_from_deletion method) which had been saved
and which belonged to a quiz with a super long name, not exceeding 255
characters, as the 'name' field in 'question_categories' table had a
max size of 255 characters. The shorten_text function was used to
shorten the string to 255 characters and a unit test was added with
the name test_question_save_from_deletion_quiz_with_long_name to test
the patch.
2020-02-08 19:49:57 +05:30
AMOS bot ba801e68d7 Automatically generated installer lang files 2020-02-08 00:12:03 +00:00
Andreas Grabs fbd65fabb2 MDL-67894 mod_feedback: database error on show responses 2020-02-07 18:48:24 +01:00
Paul Holden ee0f61cde4 MDL-59303 auth_shibboleth: consistent readme URL. 2020-02-07 14:25:35 +00:00
Luca Bösch 5779862ee7 MDL-66847 webservice: Correct breadcrumb + title for ws documentation. 2020-02-07 14:38:35 +01:00
Paul Holden 9a49f51b15 MDL-67532 badges: better default for new badge language. 2020-02-07 09:47:13 +00:00
Sara Arjona 59f947667a weekly release 3.7.4+ 2020-02-07 09:44:52 +01:00
Sara Arjona 6733f41ed1 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-02-07 09:44:49 +01:00
Brendan Heywood 867d9497f3 MDL-67726 tool_phpunit: add missing input escaping 2020-02-06 19:45:50 +01:00
Andrew Nicols a9895627a4 Merge branch 'MDL-67175-37' of git://github.com/ferranrecio/moodle into MOODLE_37_STABLE 2020-02-06 10:21:33 +08:00
Eloy Lafuente (stronk7) 1a75be0645 Merge branch 'MDL-67832_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE
(fixed a couple of typos in the merge commit)
2020-02-06 00:03:16 +01:00
Eloy Lafuente (stronk7) 53c3b1bacc Merge branch 'MDL-67732-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-02-05 20:05:58 +01:00
Eloy Lafuente (stronk7) 730714bc78 Merge branch 'MDL-67830_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2020-02-05 19:08:25 +01:00
Tim Hunt 4a0abc17d4 MDL-67876 forms: scroll to any invalid element if form cannot submit 2020-02-05 12:22:12 +00:00
Andrew Nicols 7eaadb4bdb Merge branch 'MDL-49103-37' of git://github.com/sarjona/moodle into MOODLE_37_STABLE 2020-02-05 13:52:36 +08:00
Eloy Lafuente (stronk7) 2f88edd0c9 Merge branch 'MDL-67842_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2020-02-04 22:46:37 +01:00
Eloy Lafuente (stronk7) 03721f06fb Merge branch 'MDL-63424-37' of git://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2020-02-04 19:28:53 +01:00
Eloy Lafuente (stronk7) c0b25af986 Merge branch 'MDL-66875-37' of git://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2020-02-04 19:02:41 +01:00
Sara Arjona d869324747 MDL-49103 badges: bake badges with iTXt chunk instead of tEXt
The final OB 1.0 specification changed the baking badges method
from tEXt to iTXt. Besides, the iTXt chunk should be a signed
assertion or the raw JSON (instead of the assertion URL).
This has been changed in order to make Moodle OB compliant.

Yuliya Bozhko, thanks for the patch! :-)
2020-02-04 18:49:55 +01:00
Ferran Recio 1b1cf1b950 MDL-67175 mod_scorm: fixing js eslint errors 2020-02-04 12:37:31 +01:00
Sam Hemelryk d66d85a4d7 MDL-67175 mod_scorm: sync XHR requests use sendBeacon when available
Totara reference TL-22621 (original code by Sam Hemelryk)
https://github.com/moodle/moodle/commit/2add402f8183c50bc1238ef2da5ea9cd06cb1dd9
2020-02-04 12:37:31 +01:00
Brendan Cox 67d4f4ea65 MDL-67175 session: set SameSite=None for Chrome 78 and above
Totara reference TL-22311 (original code by Brendan Cox and Sam Hemelryk)
https://github.com/moodle/moodle/commit/a3f4de2b7efe66de6617a67ce7c87f2862e76ac6
2020-02-04 12:37:15 +01:00
Andrew Nicols fe1b4bee20 Merge branch 'MDL-60126-37-3' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2020-02-04 14:40:48 +08:00
Peter 6292c6299b MDL-60126 competency: Unit tests 2020-02-04 08:55:51 +08:00
Simey Lameze 22177c5c3e MDL-60126 core: upgrade step to clean user comp 2020-02-04 08:55:42 +08:00
Simey Lameze 9f2e264fd8 MDL-60126 competency: delete content upon user delete 2020-02-04 08:40:31 +08:00
AMOS bot e1b1a447b5 Automatically generated installer lang files 2020-02-04 00:11:23 +00:00
Peter Eliyahu Kornfeld eaf2d6a809 MDL-66834 Questions: add transaction, move trigger 2020-02-03 12:26:36 +02:00
Tim Hunt a8e2b5cea1 MDL-67842 questions: Cannot remove the idnumber from a question 2020-02-03 09:49:50 +00:00
Tim Hunt 7fda2e9bac MDL-67832 quiz: fix lots of PHPdoc in attemptlib.php 2020-01-31 19:09:44 +00:00
Paul Holden ea01c38f2c MDL-67732 group: observe viewfullnames capability.
Backport from MDL-67245.
2020-01-31 16:48:15 +00:00
Eloy Lafuente (stronk7) ee0a8161dd weekly release 3.7.4+ 2020-01-30 16:11:20 +01:00
Eloy Lafuente (stronk7) 8adff28414 Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-01-30 16:11:17 +01:00
Jun Pataleta 020810aea0 Merge branch 'MDL-67353_reset_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2020-01-30 12:35:00 +08:00
Eloy Lafuente (stronk7) 56930d1d67 MDL-67353 course: move form tearDown() to reset_all_data()
We are already cleaning all sort of caches, statics, singletons
there and it's better to ensure they are always reset to avoid
myterious failures @ distance.
2020-01-30 00:02:03 +01:00
Michelle Melton 2ec76277dc MDL-64169 course: fix padding when display on one section per page
(amended to keep the $o.= consistent with surrounding code)
2020-01-29 22:36:16 +01:00
Tim Hunt bfff57b297 MDL-67830 quiz: notice in grade details redirect script 2020-01-29 18:35:17 +00:00
Jun Pataleta 5e7c5b9cec Merge branch 'MDL-67626_37' of git://github.com/adpe/moodle into MOODLE_37_STABLE 2020-01-29 21:36:41 +08:00
Adrian Greeve caa236c415 Merge branch 'MDL-67768-37-componentdirs' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-01-29 10:04:13 +08:00
Eloy Lafuente (stronk7) 52a77683aa Merge branch 'MDL-67472-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2020-01-28 22:59:36 +01:00
Eloy Lafuente (stronk7) 6afb3736f8 Merge branch 'MDL-52189_37' of https://github.com/jonof/moodle into MOODLE_37_STABLE 2020-01-28 22:45:34 +01:00
Eloy Lafuente (stronk7) 96582b63db Merge branch 'MDL-67447-37-autocomplete' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-01-28 22:24:43 +01:00
Eloy Lafuente (stronk7) a5e149a1b7 Merge branch 'MDL-67722-37' of git://github.com/mickhawkins/moodle into MOODLE_37_STABLE 2020-01-28 20:13:52 +01:00
Eloy Lafuente (stronk7) 7cf3a406ff Merge branch 'MDL-57755_37' of https://github.com/t-schroeder/moodle into MOODLE_37_STABLE 2020-01-28 10:35:07 +01:00
David Mudrák 25d1533b27 MDL-67768 core: Add some common dirs to core_component::$ignoreddirs
The core_component::$ignoreddirs lists all directories that are reserved
and cannot be used as valid plugin names. This is particularly important
for some plugin types such as 'webservice' that share the same root
location as the core subsystem of the same name.
2020-01-28 10:34:38 +01:00
Adrian Greeve 462c6e9e2c Merge branch 'MDL-67740-37-behatstepsfilter' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-01-28 15:08:59 +08:00
Adrian Greeve 1db5a1205e Merge branch 'MOODLE_37_MDL-67746' of https://github.com/golenkovm/moodle into MOODLE_37_STABLE 2020-01-28 13:14:55 +08:00
AMOS bot c3c7b02867 Automatically generated installer lang files 2020-01-28 00:11:49 +00:00
Adrian Greeve 7d1af3ec1d Merge branch 'MDL-67691_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2020-01-28 07:54:31 +08:00
Eloy Lafuente (stronk7) 5efefd458e Merge branch 'MDL-64531-37-questiondeletejson' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-01-27 17:08:20 +01:00
Eloy Lafuente (stronk7) ebc198cfb8 Merge branch 'MDL-67577-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2020-01-27 16:20:26 +01:00
Eloy Lafuente (stronk7) 1c348b2e8d Merge branch 'm37_MDL-67414_Add_PostgreSQL_12x_Support' of https://github.com/scara/moodle into MOODLE_37_STABLE 2020-01-27 12:16:27 +01:00
Bas Brands f18444a5d1 MDL-67577 core_message: navbar_output order
* moved the logic from core_message_popup_render_navbar_output to
message_popup_render_navbar_output in message/output/popup/lib.php

* using float: left instead of float: right in theme
2020-01-27 12:15:26 +01:00
Tim Schroeder 6fd48eff30 MDL-57755 message: fix notificaiton read status when messaging disabled 2020-01-27 09:17:31 +01:00
Matteo Scaramuccia 68082ac364 MDL-67414 adodb: Backport upstream fix for PostgreSQL 12.x
Upstream: https://github.com/ADOdb/ADOdb/commit/a4876f100602c2ce4760bb72d3050f73387adcca
          pgsql: stop using obsolete pg_attrdef.adsrc column
2020-01-26 09:42:24 +01:00
Matteo Scaramuccia 9edebd4951 MDL-67414 database: Fixed PostgreSQL 12.x support 2020-01-26 09:42:24 +01:00
David Mudrák adfe298af8 MDL-67447 form: Fix the duplicate autocomplete selection node
When the autocomplete selection is updated, the content of the selection
wrapper is replaced with the new list of selected items. We must replace
only the content of the selection wrapper and not to nest it into
itself.
2020-01-25 05:45:39 +01:00
AMOS bot cd6c7e0068 Automatically generated installer lang files 2020-01-25 00:11:49 +00:00
Luca Bösch d11806d957 MDL-66875 calendar: allow the use of day, mon and year again. 2020-01-25 01:01:45 +01:00
Luca Bösch 6a5c1ab6f8 MDL-63424 form: allow checkboxes to have req icon. 2020-01-24 17:38:11 +01:00
Eloy Lafuente (stronk7) e453665f7d MDL-67353 filters: fix filterlib tests
- move resetAfterTest() to test units.
- remove setUp(), moving code to remove_all_filters_from_config().
- remove class properties, moving to return values of own setup_xxx() methods.
2020-01-24 11:27:05 +01:00
Eloy Lafuente (stronk7) 3f73b4f487 MDL-67353 favourites: Random DB id matching solved
Depending on the tests executed it was possible to arrive
to favourites tests with 2 "concepts" (say userid and contextid,
or userid and itemid) having the same ID.

Then, the array_diff() operations used by some mock stuff in the
tests wrongly was returning matches by value, ultimately causing
the test to fail.

Now, the matching is performed using array_diff_assoc() that takes
keys into considation when performing the match.
2020-01-24 11:27:05 +01:00
Andrew Nicols 4dbc8e7655 MDL-67353 course: Fix more broken unit tests 2020-01-24 11:27:05 +01:00
Andrew Nicols 1fb38c5cf6 MDL-67353 course: Fix broken unit test 2020-01-24 11:27:05 +01:00
David Mudrák 71b452912a MDL-67740 behat: Show info as collapsed at the acceptance testing page
The static information with the links to Behat documentation is quite
long an irrelevant for experienced developers returning to this page. No
need to waste the prominent screen place with it - better to offer it
only when needed via collapsible form section.
2020-01-24 10:44:40 +01:00
David Mudrák 1c9edf3920 MDL-67740 behat: Improve the layout of the acceptance testing page
- The CSS contains more specific selectors.
- Make use of the whole screen width for the list of found steps.
- Visually distinguish found steps from each other.
- Make it look less like a unicorn rainbow.
2020-01-24 10:44:39 +01:00
David Mudrák c4f7a4bc62 MDL-67740 behat: Fix the name of the class in the inline documentation
The said class is provided by the moodlehq/behat-extension composer
package and was renamed as a part of upgrade to Behat 3.0.x (MDL-46891).
2020-01-24 10:44:39 +01:00
David Mudrák 9d72d1a9e6 MDL-67740 behat: Allow multiple words filter at acceptance testing page
Because of the too strict input param type, the form did not allow to
search for Behat steps containing the given phrase. The patch sets the
param type to match the one in the form definition, and makes sure that
the submitted value can be safely used as a CLI script argument.
2020-01-24 10:44:38 +01:00
Mikhail Golenkov 198b653bf7 MDL-67746 Tasks: Cleanup task logs in chunks. 2020-01-24 13:59:04 +11:00
Adrian Greeve 77a359ca7b weekly release 3.7.4+ 2020-01-24 10:17:27 +08:00
Adrian Greeve bf1e44117b Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-01-24 10:17:18 +08:00
Eloy Lafuente (stronk7) f8df624e37 Merge branch 'MDL-51225-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-01-23 11:14:27 +01:00
Jun Pataleta 704c30b1fb MDL-51225 mod_forum: Revert @javascript tag removal
Put back the removed  @javascript tag to prevent random goutte
fails.
2020-01-23 15:32:59 +08:00
Jun Pataleta a178e09bfb Merge branch 'MDL-65952_m37' of https://github.com/fabiendallet/moodle into MOODLE_37_STABLE 2020-01-23 10:43:32 +08:00
Jun Pataleta 48096011e3 Merge branch 'MDL-66897-37-1' of git://github.com/mihailges/moodle into MOODLE_37_STABLE 2020-01-22 23:16:56 +08:00
Mihail Geshoski 7ef572d39e MDL-66897 mod_assign: Properly display error messages in quick grading 2020-01-22 13:52:08 +08:00
Adrian Greeve 75ab679716 Merge branch 'MDL-67653_37' of https://github.com/timhunt/moodle into MOODLE_37_STABLE 2020-01-22 11:05:17 +08:00
Adrian Greeve 2dc1afe547 Merge branch 'MDL-67660-37-v2' of https://github.com/TobiGa/moodle into MOODLE_37_STABLE 2020-01-22 10:43:24 +08:00
Jun Pataleta 115f4461ce Merge branch 'MDL-67684-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2020-01-22 10:37:34 +08:00
Colin Campbell c0cf6abf34 MDL-52189 file: skip deleting temp files that appear during cleanup 2020-01-22 12:07:57 +10:00
Adrian Greeve ff6ea1e369 Merge branch 'MDL-67656-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2020-01-22 09:47:01 +08:00
Eloy Lafuente (stronk7) c5c42e96d2 Merge branch 'MDL-66858_37' of https://github.com/stronk7/moodle into MOODLE_37_STABLE 2020-01-22 01:57:39 +01:00
Michael Milette 39fd21e4ff MDL-66858 master: Enable <header> tags in Atto editor.
(amended to add the src/editor/js/clean.js
file that was originally missing)
2020-01-22 00:12:55 +01:00
Eloy Lafuente (stronk7) 49f70858e9 Merge branch 'MDL-51225-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-01-21 23:40:32 +01:00
Adrian Greeve 64d75c9a1a Merge branch 'MDL-66237-37' of git://github.com/mickhawkins/moodle into MOODLE_37_STABLE 2020-01-21 11:24:01 +08:00
Jun Pataleta 695499c681 Merge branch 'MDL-66108-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-01-21 09:50:47 +08:00
Eloy Lafuente (stronk7) d8c3b7e662 Merge branch 'MDL-66024-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-01-20 22:48:42 +01:00
Eloy Lafuente (stronk7) 6adc5e89b0 Merge branch 'MDL-66220-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-01-20 22:34:34 +01:00
Eloy Lafuente (stronk7) c9eeb1a7c1 Merge branch 'MDL-66712-37-selfautounenrol' of git://github.com/mudrd8mz/moodle into MOODLE_37_STABLE 2020-01-20 22:29:11 +01:00
Eloy Lafuente (stronk7) 68e4a7dac8 Merge branch 'MDL-65884-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-01-20 20:37:00 +01:00
David Mudrák 73bbb3e7a8 MDL-64531 course: Add Behat test for deleting a quiz with own questions
Teachers can delete Quiz activities that have a question in their own
context via AJAX request with the course recycle bin disabled. This used
to lead to "Unexpected token < in JSON" because of the extra HTML in the
output.
2020-01-20 18:19:45 +01:00
Tim Hunt d00045e8f5 MDL-64531 course: course_delete_module shouldn't output during AJAX
Committer's note: This change was originally part of a bigger patchset
submitted by the author. This is a stripped-down version that does not
use phpunit tests for the new behaviour.
2020-01-20 18:07:25 +01:00
Eloy Lafuente (stronk7) 7a8b3702e3 Merge branch 'MDL-67724-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-01-20 10:53:37 +01:00
Sara Arjona 887f9c3fc6 Merge branch 'MDL-67312-37' of git://github.com/lameze/moodle into MOODLE_37_STABLE 2020-01-20 08:05:16 +01:00
Adrian Greeve 28b0d9256f Merge branch 'MDL-67583-37' of https://github.com/KietChan/moodle into MOODLE_37_STABLE 2020-01-20 13:40:27 +08:00
Simey Lameze 2e6729e923 MDL-67312 core_user: clean subs events on user deletion 2020-01-20 08:54:32 +08:00
Simey Lameze d3a2788437 MDL-67312 calendar: upgrade step to delete orphaned events 2020-01-20 08:54:30 +08:00
Simey Lameze c04559ccb6 MDL-67312 core: change db upgrade step to use get_fieldset_sql 2020-01-20 08:52:59 +08:00
Eloy Lafuente (stronk7) a6e4fbe122 MDL-67691 behat: inform about the_following_exist() removal
behat_data_generators::the_following_exist() has been removed, please use
behat_data_generators::the_following_entities_exist() instead.

See MDL-67691 for more info.
2020-01-20 00:13:01 +01:00
Adrian Perez c1ed11df7a MDL-67626 assign: fix view full/view summary control in IE 2020-01-18 14:16:30 +01:00
AMOS bot 1edd36e905 Automatically generated installer lang files 2020-01-18 00:10:56 +00:00
fdallet 91aee9939b MDL-65952 mod_scorm: Fix unwanted changes to require status 2020-01-17 17:25:03 +01:00
Paul Holden a585ee9432 MDL-66108 course: fix false positives when bulk moving categories. 2020-01-17 16:19:26 +00:00
Jun Pataleta bb0acb3e9c MDL-67724 mod_glossary: Improve Behat test
Improve the "Glossary entries are not always editable" scenario by:
* No need to use the @javascript tag
* The maxediting time can be set to a lower value to
reduce the overall wait time.
2020-01-17 17:48:06 +08:00
Tobias Garske 02f08b16c5 MDL-67660 core_message: Messages search change input focus 2020-01-17 09:39:11 +01:00
Michael Hawkins e206c3b8f2 MDL-67722 mod_forum: Reduce wait time on time limit expires behat test 2020-01-17 15:46:56 +08:00
Jun Pataleta 3246d41cb2 MDL-51225 mod_forum: Use can_view_post to determine whether to show post
Use \mod_forum\local\managers\capability::can_view_post() to
consistently determine whether a forum post will be rendered in the
recent activity block.
This helps the recent activity block to provide a more consistent
behaviour with the forum's discussion view itself.
2020-01-17 14:51:47 +08:00
Jun Pataleta 8594f5e8ae MDL-51225 mod_forum: Create behat tests for forum recent activity 2020-01-17 14:45:36 +08:00
Jun Pataleta c0842ca500 MDL-51225 mod_forum: New behat step for creating question discussion 2020-01-17 14:45:36 +08:00
AMOS bot c670210a1d Automatically generated installer lang files 2020-01-17 00:12:28 +00:00
Sara Arjona fd908d09fd weekly release 3.7.4+ 2020-01-16 17:19:15 +01:00
Sara Arjona d859e8774c Merge branch 'install_37_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_37_STABLE 2020-01-16 17:19:13 +01:00
David Mudrák a86318bd92 MDL-66712 enrol: Fix the reported days of inactivity on unenrolment
There were two problems here. Firstly, the $days was not correctly
calculated due to missing parentheses. Secondly, the sentence had
grammar issues.
2020-01-16 13:44:31 +01:00
Jun Pataleta 77b19b828b MDL-66220 mod_forum: Prevent from replying to a post the user can't see 2020-01-16 15:06:25 +08:00
Jun Pataleta d046109d4d MDL-66220 mod_forum: Cache result of forum_user_can_see_post()
* Cache the result of this function to avoid doing multiple DB calls
for the same post when loading posts in a discussion.
2020-01-16 15:06:25 +08:00
Jun Pataleta bc8d03c68d MDL-66220 mod_forum: Additional unit test for can_reply_to_post 2020-01-16 15:06:25 +08:00
Andrew Nicols f394d9efae Merge branch 'wip-MDL-66918-37stable' of https://github.com/Beedell/moodle into MOODLE_37_STABLE 2020-01-16 11:44:38 +08:00
Eloy Lafuente (stronk7) b67c73c86b Merge branch 'MDL-67625-37' of git://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2020-01-16 00:27:06 +01:00
Sara Arjona 9941fbdae4 Merge branch 'MDL-67617-37' of git://github.com/lucaboesch/moodle into MOODLE_37_STABLE 2020-01-15 12:43:19 +01:00
Sara Arjona aa23048889 Merge branch 'MDL-67638-37' of https://github.com/nguyenphuctien/moodle into MOODLE_37_STABLE 2020-01-15 12:20:00 +01:00
Andrew Nicols c4b8e4ca14 Merge branch 'MDL-67486-swap-cron-lock-MOODLE_37_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_37_STABLE 2020-01-15 13:54:26 +08:00
Mark Johnson e5ec4988b6 MDL-67674 Cache: Lock rebuilding of the course category tree cache 2020-01-15 00:02:22 +01:00
Sara Arjona 35ce17025a Merge branch 'MDL-65573-37-2' of git://github.com/peterRd/moodle into MOODLE_37_STABLE 2020-01-14 12:20:59 +01:00
Andrew Nicols fc1ddb3289 Merge branch 'MDL-66721-37' of git://github.com/bmbrands/moodle into MOODLE_37_STABLE 2020-01-14 14:10:39 +08:00
Andrew Nicols 85b9cf9ce4 MDL-67684 core: Add missing li tag 2020-01-14 08:47:20 +08:00
Andrew Nicols 05bb501b4f Merge branch 'MDL-35971-37' of git://github.com/junpataleta/moodle into MOODLE_37_STABLE 2020-01-14 08:33:48 +08:00
AMOS bot 116d41cdfd Automatically generated installer lang files 2020-01-14 00:10:31 +00:00
Peter a5cff8a55b MDL-65573 mod_forum: Set userid properly after split
* Set the discussion's userid properly when splitting a discussion.
* Update step to correct existing incorrect records.
2020-01-14 07:42:19 +08:00
Eloy Lafuente (stronk7) 06e0263936 Merge branch 'MDL-65649-37' of https://github.com/paulholden/moodle into MOODLE_37_STABLE 2020-01-13 18:57:02 +01:00
Eloy Lafuente (stronk7) de98c397f3 Merge branch 'MDL-65987-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2020-01-13 18:42:26 +01:00
Sara Arjona f091f67f81 Merge branch 'MDL-59817-37' of git://github.com/andrewnicols/moodle into MOODLE_37_STABLE 2020-01-13 14:27:01 +01:00
Kiet Chan 7cfbdd0422 MDL-67583 themes: Popover placement should react to scroll event 2020-01-13 17:27:31 +07:00
Bas Brands 089100fdb3 MDL-67472 theme_boost: configurable sass variable for drawer bgcolour 2020-01-13 09:16:44 +01:00
Tien Nguyen Phuc 68e85534a8 MDL-67638 Course: update course timemodified on bulk category move 2020-01-13 10:41:36 +07:00
Andrew Nicols 0f41a0280d Merge branch 'MDL-67204-37' of https://github.com/mwehr/moodle into MOODLE_37_STABLE 2020-01-13 08:54:46 +08:00
Brendan Heywood fd9466fceb MDL-67486 cron: Improve throughput by holding cron lock for less time 2020-01-12 00:48:25 +11:00
Tim Hunt 6cb1f99459 MDL-67653 questions: prevent the flag flickering as the page loads 2020-01-10 14:28:34 +00:00
Andrew Nicols 8bc3576bb3 MDL-59817 atto_accessibilitychecker: Handle transparency properly
Some browsers, notably Firefox, do not return the computed style for
background colour in a computed RGB format. Instead they return the RGBA
where the alpha channel is set to fully transparent.

To solve this we need to work up the hierarchy and compute the
background colour for each parent node until we reach full alpha (1).

We can use a standard calculation to approximate the value for the
resultant element background by multiplying the alpha of the current
transparent (or semi-transparent) node with the R, G, or B channel in
question, and that of the parent node's background colour.

There are cases where this will not be 100% accurate - notably where
there is some additional content in addition to the parent background,
but this gives us a reasoable approximation for the majority of cases.
Additionally the code has never considered the full set of node content
when calculating this information.
2020-01-10 15:26:51 +08:00
Andrew Nicols 4158b39809 MDL-67656 behat: Removed nested spin 2020-01-10 13:40:32 +08:00
Andrew Nicols c7afe02401 MDL-67656 behat: Fix usleep call in spin 2020-01-10 13:40:31 +08:00
Luca Bösch 37524fa1e6 MDL-67625 quiz: only section titles should be large when editing. 2020-01-09 17:23:02 +01:00
Luca Bösch 44c7386d16 MDL-67617 gradereport_singleview: Style the form element with bs classes 2020-01-09 17:22:09 +01:00
Mario Wehr c3f4abed6f MDL-67204 assign task: Use lastruntime from task_scheduled 2020-01-09 17:12:34 +01:00
John Beedell 2acb24d84e MDL-66918 behat: Behat app step failing 2020-01-09 15:59:25 +00:00
Jun Pataleta 6783597dc0 MDL-35971 mod_forum: Add proper discussion list table description 2020-01-08 15:45:47 +08:00
Paul Holden 8c3f81aa69 MDL-66237 message_popup: Get redirecturl from notification contexturl 2020-01-07 11:24:37 +08:00
Bas Brands 3dd509b06b MDL-66721 core_chooser: height correction for chooser modal 2020-01-06 10:13:19 +01:00
Luca Bösch da1a4189e1 MDL-65987 mod_forum: Add string 'Advanced' for the advanced editor.
AMOS BEGIN
    CPY [advanced,moodle],[showadvancededitor,moodle]
   AMOS END
2020-01-06 09:41:23 +08:00
Paul Holden 213abaaf97 MDL-65649 backup: ensure valid course URL for async mode. 2019-12-09 23:34:37 +00:00
Paul Holden 9e9c0912e3 MDL-66024 tool_uploadcourse: validate shortname/fullname field length. 2019-12-05 23:11:14 +00:00
Paul Holden ad7d0f05de MDL-65884 filters: update exclusive separator characters for tags.
The previous characters mangled the output of filtered text, exhibited
in the activity names filter for activities named '-' (single hyphen).
2019-06-12 17:10:21 +01:00
223 changed files with 3647 additions and 1045 deletions
+27 -12
View File
@@ -151,6 +151,9 @@ module.exports = function(grunt) {
tasks: ['yui']
},
gherkinlint: {
options: {
nospawn: false,
},
files: ['**/tests/behat/*.feature'],
tasks: ['gherkinlint']
}
@@ -293,19 +296,31 @@ module.exports = function(grunt) {
};
tasks.gherkinlint = function() {
var done = this.async(),
options = grunt.config('gherkinlint.options');
const done = this.async();
const options = grunt.config('gherkinlint.options');
var args = grunt.file.expand(options.files);
args.unshift(path.normalize(__dirname + '/node_modules/.bin/gherkin-lint'));
grunt.util.spawn({
cmd: 'node',
args: args,
opts: {stdio: 'inherit', env: process.env}
}, function(error, result, code) {
// Propagate the exit code.
done(code === 0);
});
// Grab the gherkin-lint linter and required scaffolding.
const linter = require('gherkin-lint/src/linter.js');
const featureFinder = require('gherkin-lint/src/feature-finder.js');
const configParser = require('gherkin-lint/src/config-parser.js');
const formatter = require('gherkin-lint/src/formatters/stylish.js');
// Run the linter.
const results = linter.lint(
featureFinder.getFeatureFiles(grunt.file.expand(options.files)),
configParser.getConfiguration(configParser.defaultConfigFileName)
);
// Print the results out uncondtionally.
formatter.printResults(results);
// Report on the results.
// We exit 1 if there is at least one error, otherwise we exit cleanly.
if (results.some(result => result.errors.length > 0)) {
done(1);
} else {
done(0);
}
};
tasks.startup = function() {
+1 -1
View File
@@ -45,7 +45,7 @@ $error = optional_param('error', '', PARAM_ALPHANUM);
admin_externalpage_setup('registrationmoodleorg');
if ($url !== HUB_MOODLEORGHUBURL) {
if (parse_url($url, PHP_URL_HOST) !== parse_url(HUB_MOODLEORGHUBURL, PHP_URL_HOST)) {
// Allow other plugins to confirm registration on custom hubs. Plugins implementing this
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
$callbacks = get_plugins_with_function('hub_registration');
+1 -1
View File
@@ -39,7 +39,7 @@ $token = optional_param('token', '', PARAM_TEXT);
admin_externalpage_setup('registrationmoodleorg');
if ($url !== HUB_MOODLEORGHUBURL) {
if (parse_url($url, PHP_URL_HOST) !== parse_url(HUB_MOODLEORGHUBURL, PHP_URL_HOST)) {
// Allow other plugins to renew registration on custom hubs. Plugins implementing this
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
$callbacks = get_plugins_with_function('hub_registration');
+4 -1
View File
@@ -97,7 +97,10 @@ $options = array(
GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'HTTP_X_FORWARDED_FOR, REMOTE_ADDR',
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR => 'HTTP_CLIENT, REMOTE_ADDR',
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP => 'REMOTE_ADDR');
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'), new lang_string('configgetremoteaddrconf', 'admin'), 0, $options));
$temp->add(new admin_setting_configselect('getremoteaddrconf', new lang_string('getremoteaddrconf', 'admin'),
new lang_string('configgetremoteaddrconf', 'admin'),
GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP, $options));
$temp->add(new admin_setting_configtext('reverseproxyignore', new lang_string('reverseproxyignore', 'admin'), new lang_string('configreverseproxyignore', 'admin'), ''));
$temp->add(new admin_setting_heading('webproxy', new lang_string('webproxy', 'admin'), new lang_string('webproxyinfo', 'admin')));
$temp->add(new admin_setting_configtext('proxyhost', new lang_string('proxyhost', 'admin'), new lang_string('configproxyhost', 'admin'), '', PARAM_HOST));
+1 -1
View File
@@ -32,7 +32,7 @@ require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
// systems, but let's allow room for expansion.
core_php_time_limit::raise(300);
$filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
$filter = optional_param('filter', '', PARAM_NOTAGS);
$type = optional_param('type', false, PARAM_ALPHAEXT);
$component = optional_param('component', '', PARAM_ALPHAEXT);
+2 -2
View File
@@ -55,13 +55,13 @@ class tool_behat {
// The loaded steps depends on the component specified.
behat_config_manager::update_config_file($component, false);
// The Moodle\BehatExtension\HelpPrinter\MoodleDefinitionsPrinter will parse this search format.
// The Moodle\BehatExtension\Definition\Printer\ConsoleDefinitionInformationPrinter will parse this search format.
if ($type) {
$filter .= '&&' . $type;
}
if ($filter) {
$filteroption = ' -d "' . $filter . '"';
$filteroption = ' -d ' . escapeshellarg($filter);
} else {
$filteroption = ' -di';
}
+8 -17
View File
@@ -44,13 +44,9 @@ class tool_behat_renderer extends plugin_renderer_base {
global $CFG;
require_once($CFG->libdir . '/behat/classes/behat_selectors.php');
$html = $this->generic_info();
// Form.
ob_start();
$form->display();
$html .= ob_get_contents();
ob_end_clean();
$html = $this->output->header();
$html .= $this->output->heading(get_string('pluginname', 'tool_behat'));
$html .= $form->render();
if (empty($stepsdefinitions)) {
$stepsdefinitions = get_string('nostepsdefinitions', 'tool_behat');
@@ -128,7 +124,9 @@ class tool_behat_renderer extends plugin_renderer_base {
*/
public function render_error($msg) {
$html = $this->generic_info();
$html = $this->output->header();
$html .= $this->output->heading(get_string('pluginname', 'tool_behat'));
$html .= $this->generic_info();
$a = new stdClass();
$a->errormsg = $msg;
@@ -153,13 +151,7 @@ class tool_behat_renderer extends plugin_renderer_base {
*
* @return string
*/
protected function generic_info() {
$title = get_string('pluginname', 'tool_behat');
// Header.
$html = $this->output->header();
$html .= $this->output->heading($title);
public function generic_info() {
// Info.
$installurl = behat_command::DOCS_URL;
@@ -175,8 +167,7 @@ class tool_behat_renderer extends plugin_renderer_base {
);
// List of steps.
$html .= $this->output->box_start();
$html .= html_writer::tag('h3', get_string('infoheading', 'tool_behat'));
$html = $this->output->box_start();
$html .= html_writer::tag('div', get_string('aim', 'tool_behat'));
$html .= html_writer::start_tag('div');
$html .= html_writer::start_tag('ul');
@@ -40,8 +40,14 @@ class steps_definitions_form extends moodleform {
* @return void
*/
public function definition() {
global $PAGE;
$mform = $this->_form;
$output = $PAGE->get_renderer('tool_behat');
$mform->addElement('header', 'info', get_string('infoheading', 'tool_behat'));
$mform->setExpanded('info', false);
$mform->addElement('html', $output->generic_info());
$mform->addElement('header', 'filters', get_string('stepsdefinitionsfilters', 'tool_behat'));
+20 -14
View File
@@ -1,25 +1,31 @@
.steps-definitions {
border-style: solid;
border-width: 1px;
border-color: #bbb;
padding: 5px;
margin: auto;
width: 50%;
#page-admin-tool-behat-index .steps-definitions {
margin: 1rem auto;
}
.steps-definitions .step {
margin: 10px 0 10px 0;
#page-admin-tool-behat-index .steps-definitions .step {
margin: 1rem 0 0 0;
border: 1px solid #eee;
padding: 1rem;
}
.steps-definitions .stepdescription {
color: #bf8c12;
#page-admin-tool-behat-index .steps-definitions .stepdescription {
font-style: italic;
}
.steps-definitions .steptype {
#page-admin-tool-behat-index .steps-definitions .stepcontent {
margin: 1rem 0;
}
#page-admin-tool-behat-index .steps-definitions .steptype {
color: #1467a6;
margin-right: 5px;
margin-right: 1ex;
}
.steps-definitions .stepregex {
#page-admin-tool-behat-index .steps-definitions .stepapipath {
font-family: monospace;
font-size: smaller;
}
#page-admin-tool-behat-index .steps-definitions .stepregex {
color: #060;
}
@@ -26,3 +26,11 @@ Feature: List the system steps definitions
Given I set the field "Contains" to "homepage"
When I press "Filter"
Then I should see "Opens Moodle homepage."
@javascript
Scenario: Filtering by the multiple words pattern
Given I set the field "Contains" to "should exist"
When I press "Filter"
Then I should not see "There aren't steps definitions matching this filter"
And I should see "Checks the provided element and selector type exists in the current page."
And I should see "Checks that an element and selector type exists in another element and selector type on the current page."
+14 -4
View File
@@ -75,6 +75,7 @@ class tool_capability_renderer extends plugin_renderer_base {
* @return string
*/
public function capability_comparison_table(array $capabilities, $contextid, array $roles) {
static $capabilitycontexts = array();
$strpermissions = $this->get_permission_strings();
$permissionclasses = $this->get_permission_classes();
@@ -92,8 +93,13 @@ class tool_capability_renderer extends plugin_renderer_base {
}
$table->data = array();
$childcontextsids = [];
foreach ($capabilities as $capability) {
$contexts = tool_capability_calculate_role_data($capability, $roles);
if (empty($capabilitycontexts[$capability])) {
$capabilitycontexts[$capability] = tool_capability_calculate_role_data($capability, $roles);
}
$contexts = $capabilitycontexts[$capability];
$captitle = new html_table_cell(get_capability_string($capability) . html_writer::span($capability));
$captitle->header = true;
@@ -111,6 +117,10 @@ class tool_capability_renderer extends plugin_renderer_base {
}
$table->data[] = $row;
if (!empty($contexts[$contextid]->children)) {
$childcontextsids = array_merge($childcontextsids, $contexts[$contextid]->children);
$childcontextsids = array_unique($childcontextsids);
}
}
// Start the list item, and print the context name as a link to the place to make changes.
@@ -127,9 +137,9 @@ class tool_capability_renderer extends plugin_renderer_base {
$html = $this->output->heading(html_writer::link($url, $context->get_context_name(), ['title' => $title]), 3);
$html .= html_writer::table($table);
// If there are any child contexts, print them recursively.
if (!empty($contexts[$contextid]->children)) {
foreach ($contexts[$contextid]->children as $childcontextid) {
$html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles, true);
if (!empty($childcontextsids)) {
foreach ($childcontextsids as $childcontextid) {
$html .= $this->capability_comparison_table($capabilities, $childcontextid, $roles);
}
}
return $html;
@@ -0,0 +1,97 @@
@tool @tool_capability
Feature: Show capabilities for multiple contexts
In order to check roles capabilities
As an admin
I need to be able to see capability overrides on several contexts
Background:
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
| Course 2 | C2 | 0 |
And the following "permission overrides" exist:
| capability | permission | role | contextlevel | reference |
| enrol/category:config | Allow | student | Course | C1 |
| enrol/cohort:unenrol | Allow | student | Course | C2 |
And I log in as "admin"
And I navigate to "Users > Permissions > Capability overview" in site administration
Scenario: Show capabilities table with one capability with overrides
When I set the following fields to these values:
| Capability: | enrol/category:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "System"
And I should see "Category: Miscellaneous"
And I should see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with one capability without overrides
When I set the following fields to these values:
| Capability: | enrol/cohort:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "System"
And I should not see "Category: Miscellaneous"
And I should not see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with two capabilities, 1st without overrides and 2nd with
When I set the following fields to these values:
| Capability: | enrol/category:synchronised, enrol/category:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "System"
And I should see "Category: Miscellaneous"
And I should see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with two capabilities, 1st with overrides and 2nd without
When I set the following fields to these values:
| Capability: | enrol/category:config, enrol/cohort:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "System"
And I should see "Category: Miscellaneous"
And I should see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with two capabilities, none with overrides
When I set the following fields to these values:
| Capability: | enrol/category:synchronised, enrol/cohort:config |
| Roles: | Student |
And I click on "Get the overview" "button"
Then I should see "System"
And I should not see "Category: Miscellaneous"
And I should not see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with capability with override and no role selected
When I set the following fields to these values:
| Capability: | enrol/category:config |
| Roles: | |
And I click on "Get the overview" "button"
Then I should see "System"
And I should see "Category: Miscellaneous"
And I should see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with capability without override and no role selected
When I set the following fields to these values:
| Capability: | enrol/cohort:config |
| Roles: | |
And I click on "Get the overview" "button"
Then I should see "System"
And I should not see "Category: Miscellaneous"
And I should not see "Course: Course 1"
And I should not see "Course: Course 2"
Scenario: Show capabilities table with capability with two overrides on different contexts
When I set the following fields to these values:
| Capability: | enrol/category:config, enrol/cohort:unenrol |
| Roles: | |
And I click on "Get the overview" "button"
Then I should see "System"
And I should see "Category: Miscellaneous"
And I should see "Course: Course 1"
And I should see "Course: Course 2"
+45
View File
@@ -0,0 +1,45 @@
<?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/>.
/**
* Plugin upgrade code
*
* @package tool_cohortroles
* @copyright 2020 Paul Holden <paulh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Function to upgrade tool_cohortroles.
*
* @param int $oldversion the version we are upgrading from
* @return bool result
*/
function xmldb_tool_cohortroles_upgrade($oldversion) {
global $DB;
if ($oldversion < 2019052001) {
// Delete any tool_cohortroles mappings for roles which no longer exist.
$DB->delete_records_select('tool_cohortroles', 'roleid NOT IN (SELECT id FROM {role})');
// Cohortroles savepoint reached.
upgrade_plugin_savepoint(true, 2019052001, 'tool', 'cohortroles');
}
return true;
}
+1 -1
View File
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2019052000; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2019052001; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2019051100; // Requires this Moodle version.
$plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
+9 -1
View File
@@ -45,13 +45,22 @@ if ($manage) {
$context = context_system::instance();
// Make sure the user has the proper capability.
require_capability('tool/dataprivacy:managedatarequests', $context);
navigation_node::override_active_url($returnurl);
} else {
// For the case where a user makes request for themselves (or for their children if they are the parent).
$returnurl = new moodle_url($CFG->wwwroot . '/admin/tool/dataprivacy/mydatarequests.php');
$context = context_user::instance($USER->id);
}
$PAGE->set_context($context);
if (!$manage && $profilenode = $PAGE->settingsnav->find('myprofile', null)) {
$profilenode->make_active();
}
$title = get_string('createnewdatarequest', 'tool_dataprivacy');
$PAGE->navbar->add($title);
// If contactdataprotectionofficer is disabled, send the user back to the profile page, or the privacy policy page.
// That is, unless you have sufficient capabilities to perform this on behalf of a user.
if (!$manage && !\tool_dataprivacy\api::can_contact_dpo()) {
@@ -100,7 +109,6 @@ if ($data = $mform->get_data()) {
redirect($returnurl, $redirectmessage);
}
$title = get_string('createnewdatarequest', 'tool_dataprivacy');
$PAGE->set_heading($SITE->fullname);
$PAGE->set_title($title);
echo $OUTPUT->header();
+7 -1
View File
@@ -42,6 +42,13 @@ if (isguestuser()) {
$usercontext = context_user::instance($USER->id);
$PAGE->set_context($usercontext);
if ($profilenode = $PAGE->settingsnav->find('myprofile', null)) {
$profilenode->make_active();
}
$title = get_string('datarequests', 'tool_dataprivacy');
$PAGE->navbar->add($title);
// Return URL.
$params = ['id' => $USER->id];
if ($courseid) {
@@ -49,7 +56,6 @@ if ($courseid) {
}
$returnurl = new moodle_url('/user/profile.php', $params);
$title = get_string('datarequests', 'tool_dataprivacy');
$PAGE->set_heading($title);
$PAGE->set_title($title);
echo $OUTPUT->header();
+3 -9
View File
@@ -27,12 +27,10 @@ require_once('../../../config.php');
$requestid = required_param('requestid', PARAM_INT);
$confirm = optional_param('confirm', null, PARAM_INT);
$PAGE->set_url(new moodle_url('/admin/tool/dataprivacy/resubmitrequest.php', ['requestid' => $requestid]));
$url = new moodle_url('/admin/tool/dataprivacy/resubmitrequest.php', ['requestid' => $requestid]);
$title = get_string('resubmitrequestasnew', 'tool_dataprivacy');
require_login();
$PAGE->set_context(\context_system::instance());
require_capability('tool/dataprivacy:managedatarequests', $PAGE->context);
\tool_dataprivacy\page_helper::setup($url, $title, 'datarequests', 'tool/dataprivacy:managedatarequests');
$manageurl = new moodle_url('/admin/tool/dataprivacy/datarequests.php');
@@ -53,10 +51,6 @@ if (null !== $confirm && confirm_sesskey()) {
redirect($manageurl, get_string('resubmittedrequest', 'tool_dataprivacy', $stringparams));
}
$heading = get_string('resubmitrequest', 'tool_dataprivacy', $stringparams);
$PAGE->set_title($heading);
$PAGE->set_heading($heading);
echo $OUTPUT->header();
$confirmstring = get_string('confirmrequestresubmit', 'tool_dataprivacy', $stringparams);
+7
View File
@@ -34,6 +34,13 @@ $PAGE->set_context($context);
$PAGE->set_title($title);
$PAGE->set_heading($SITE->fullname);
// If user is logged in, then use profile navigation in breadcrumbs.
if ($profilenode = $PAGE->settingsnav->find('myprofile', null)) {
$profilenode->make_active();
}
$PAGE->navbar->add($title);
$output = $PAGE->get_renderer('tool_dataprivacy');
echo $output->header();
$summarypage = new \tool_dataprivacy\output\summary_page();
+28
View File
@@ -346,6 +346,7 @@ class api {
*/
public static function get_features_list() {
global $CFG;
require_once($CFG->libdir . '/authlib.php');
$general = new lang_string('general');
$mainmenu = new lang_string('mainmenu', 'tool_mobile');
@@ -355,6 +356,7 @@ class api {
$user = new lang_string('user');
$files = new lang_string('files');
$remoteaddons = new lang_string('remoteaddons', 'tool_mobile');
$identityproviders = new lang_string('oauth2identityproviders', 'tool_mobile');
$availablemods = core_plugin_manager::instance()->get_plugins_of_type('mod');
$coursemodules = array();
@@ -421,6 +423,7 @@ class api {
'NoDelegate_CoreTag' => new lang_string('tags'),
'$mmLoginEmailSignup' => new lang_string('startsignup'),
'NoDelegate_ResponsiveMainMenuItems' => new lang_string('responsivemainmenuitems', 'tool_mobile'),
'NoDelegate_DarkMode' => new lang_string('darkmode', 'tool_mobile'),
),
"$mainmenu" => array(
'$mmSideMenuDelegate_mmaFrontpage' => new lang_string('sitehome'),
@@ -473,6 +476,31 @@ class api {
$features["$remoteaddons"] = $remoteaddonslist;
}
// Display OAuth 2 identity providers.
if (is_enabled_auth('oauth2')) {
$identityproviderslist = array();
$idps = \auth_plugin_base::get_identity_providers(['oauth2']);
foreach ($idps as $idp) {
// Only add identity providers that have an ID.
$id = isset($idp['url']) ? $idp['url']->get_param('id') : null;
if ($id != null) {
$identityproviderslist['NoDelegate_IdentityProvider_' . $id] = $idp['name'];
}
}
if (!empty($identityproviderslist)) {
$features["$identityproviders"] = array();
if (count($identityproviderslist) > 1) {
// Include an option to disable them all.
$features["$identityproviders"]['NoDelegate_IdentityProviders'] = new lang_string('all');
}
$features["$identityproviders"] = array_merge($features["$identityproviders"], $identityproviderslist);
}
}
return $features;
}
@@ -45,12 +45,16 @@ $string['custommenuitems_desc'] = 'Additional items can be added to the app\'s m
Link-opening methods are: app (for linking to an activity supported by the app), inappbrowser (for opening a link in a browser without leaving the app), browser (for opening the link in the device default browser outside the app) and embedded (for displaying the link in an iframe in a new page in the app).
When items are missing a translation for a given language, they will use other languages as fallback unless "_only" is appended to the language code.
For example:
<pre>
App help|https://someurl.xyz/help|inappbrowser
My grades|https://someurl.xyz/local/mygrades/index.php|embedded|en
Mis calificaciones|https://someurl.xyz/local/mygrades/index.php|embedded|es
You will only see this in English|https://someurl.xyz/english|browser|en_only
</pre>';
$string['darkmode'] = 'Dark mode';
$string['disabledfeatures'] = 'Disabled features';
$string['disabledfeatures_desc'] = 'Select here the features you want to disable in the Mobile app for your site. Please note that some features listed here could be already disabled via other site settings. You will have to log out and log in again in the app to see the changes.';
$string['displayerrorswarning'] = 'Display debug messages (debugdisplay) is enabled. It should be disabled.';
@@ -84,6 +88,7 @@ $string['mobilecssurl'] = 'CSS';
$string['mobilefeatures'] = 'Mobile features';
$string['mobilenotificationsdisabledwarning'] = 'Mobile notifications are not enabled. They should be enabled in Notification settings.';
$string['mobilesettings'] = 'Mobile settings';
$string['oauth2identityproviders'] = 'OAuth 2 identity providers';
$string['offlineuse'] = 'Offline use';
$string['pluginname'] = 'Moodle app tools';
$string['pluginnotenabledorconfigured'] = 'Plugin not enabled or configured.';
+7 -1
View File
@@ -30,10 +30,16 @@ require_once($CFG->libdir . '/externallib.php');
$serviceshortname = required_param('service', PARAM_ALPHANUMEXT);
$passport = required_param('passport', PARAM_RAW); // Passport send from the app to validate the response URL.
$urlscheme = optional_param('urlscheme', 'moodlemobile', PARAM_ALPHANUM); // The URL scheme the app supports.
$urlscheme = optional_param('urlscheme', 'moodlemobile', PARAM_NOTAGS); // The URL scheme the app supports.
$confirmed = optional_param('confirmed', false, PARAM_BOOL); // If we are being redirected after user confirmation.
$oauthsso = optional_param('oauthsso', 0, PARAM_INT); // Id of the OpenID issuer (for OAuth direct SSO).
// Validate that the urlscheme is valid.
if (!preg_match('/^[a-zA-Z][a-zA-Z0-9-\+\.]*$/', $urlscheme)) {
throw new moodle_exception('Invalid parameter: the value of urlscheme isn\'t valid. ' .
'It should start with a letter and can only contain letters, numbers and the characters "." "+" "-".');
}
// Check web services enabled.
if (!$CFG->enablewebservices) {
throw new moodle_exception('enablewsdescription', 'webservice');
+1 -1
View File
@@ -63,7 +63,7 @@ if ($hassiteconfig) {
$temp->add(new admin_setting_configtext('tool_mobile/forcedurlscheme',
new lang_string('forcedurlscheme_key', 'tool_mobile'),
new lang_string('forcedurlscheme', 'tool_mobile'), '', PARAM_ALPHANUM));
new lang_string('forcedurlscheme', 'tool_mobile'), '', PARAM_NOTAGS));
$ADMIN->add('mobileapp', $temp);
+6 -5
View File
@@ -131,11 +131,12 @@ if ($execute) {
tool_phpunit_problem('Can not create configuration file');
}
}
$configdir = escapeshellarg($configdir);
// no cleanup of path - this is tricky because we can not use escapeshellarg and friends for escaping,
// this is from admin user so PARAM_PATH must be enough
chdir($CFG->dirroot);
passthru("php $CFG->admin/tool/phpunit/cli/util.php --run -c $configdir $testclass $testpath", $code);
$configdir = escapeshellarg($configdir);
$cleanclass = escapeshellarg($testclass);
$cleanpath = escapeshellarg($testpath);
passthru("php $CFG->admin/tool/phpunit/cli/util.php --run -c $configdir $cleanclass $cleanpath", $code);
chdir($oldcwd);
echo '</pre>';
@@ -146,7 +147,7 @@ if ($execute) {
}
echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
echo '<form method="get" action="webrunner.php">';
echo '<form method="post" action="webrunner.php">';
echo '<fieldset class="invisiblefieldset">';
echo '<label for="testpath">Test one file</label> ';
echo '<input type="text" id="testpath" name="testpath" value="'.s($testpath).'" size="50" /> (all test cases from webrunner.xml if empty)';
+15 -1
View File
@@ -39,15 +39,29 @@ if ($userid != $USER->id) {
if (!has_capability('tool/policy:acceptbehalf', $context)) {
require_capability('tool/policy:viewacceptances', $context);
}
$user = core_user::get_user($userid);
$PAGE->navigation->extend_for_user($user);
}
$title = get_string('policiesagreements', 'tool_policy');
$PAGE->set_context($context);
$PAGE->set_pagelayout('standard');
$PAGE->set_url(new moodle_url('/admin/tool/policy/user.php', ['userid' => $userid]));
$PAGE->set_title($title);
if ($userid == $USER->id &&
($profilenode = $PAGE->settingsnav->find('myprofile', null))) {
$profilenode->make_active();
}
$PAGE->navbar->add($title);
$output = $PAGE->get_renderer('tool_policy');
echo $output->header();
echo $output->heading(get_string('policiesagreements', 'tool_policy'));
echo $output->heading($title);
$acceptances = new \tool_policy\output\acceptances($userid, $returnurl);
echo $output->render($acceptances);
$PAGE->requires->js_call_amd('tool_policy/acceptmodal', 'getInstance', [context_system::instance()->id]);
+2 -2
View File
@@ -100,9 +100,9 @@ if (!$problems) {
$count = $problem->racount;
$edit = array();
$aurl = new moodle_url('/admin/roles/define.php', array('roleid'=>$problem->roleid, 'action'=>'edit'));
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/edit', 'core', get_string('edit')));
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
$aurl = new moodle_url($PAGE->url, array('roleid'=>$problem->roleid, 'contextlevel'=>$problem->contextlevel, 'action'=>'delete'));
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/delete', 'core', get_string('delete')));
$edit[] = html_writer::link($aurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
$data[] = array($levelname, $rolename, $count, implode('&nbsp;', $edit));
}
$table = new html_table();
@@ -412,6 +412,12 @@ class tool_uploadcourse_course {
$this->error('invalidshortname', new lang_string('invalidshortname', 'tool_uploadcourse'));
return false;
}
// Ensure we don't overflow the maximum length of the shortname field.
if (core_text::strlen($this->shortname) > 255) {
$this->error('invalidshortnametoolong', new lang_string('invalidshortnametoolong', 'tool_uploadcourse', 255));
return false;
}
}
$exists = $this->exists();
@@ -479,6 +485,12 @@ class tool_uploadcourse_course {
return false;
}
// Ensure we don't overflow the maximum length of the fullname field.
if (!empty($coursedata['fullname']) && core_text::strlen($coursedata['fullname']) > 254) {
$this->error('invalidfullnametoolong', new lang_string('invalidfullnametoolong', 'tool_uploadcourse', 254));
return false;
}
// If the course does not exist, or will be forced created.
if (!$exists || $mode === tool_uploadcourse_processor::MODE_CREATE_ALL) {
@@ -93,6 +93,8 @@ $string['invalideupdatemode'] = 'Invalid update mode selected';
$string['invalidvisibilitymode'] = 'Invalid visible mode';
$string['invalidroles'] = 'Invalid role names: {$a}';
$string['invalidshortname'] = 'Invalid shortname';
$string['invalidfullnametoolong'] = 'The fullname field is limited to {$a} characters';
$string['invalidshortnametoolong'] = 'The shortname field is limited to {$a} characters';
$string['missingmandatoryfields'] = 'Missing value for mandatory fields: {$a}';
$string['missingshortnamenotemplate'] = 'Missing shortname and shortname template not set';
$string['mode'] = 'Upload mode';
@@ -82,6 +82,37 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
$this->assertArrayHasKey('invalidshortname', $co->get_errors());
}
public function test_invalid_shortname_too_long() {
$this->resetAfterTest();
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
$upload = new tool_uploadcourse_course($mode, $updatemode, [
'category' => 1,
'fullname' => 'New course',
'shortname' => str_repeat('X', 2000),
]);
$this->assertFalse($upload->prepare());
$this->assertArrayHasKey('invalidshortnametoolong', $upload->get_errors());
}
public function test_invalid_fullname_too_long() {
$this->resetAfterTest();
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
$upload = new tool_uploadcourse_course($mode, $updatemode, [
'category' => 1,
'fullname' => str_repeat('X', 2000),
]);
$this->assertFalse($upload->prepare());
$this->assertArrayHasKey('invalidfullnametoolong', $upload->get_errors());
}
public function test_invalid_visibility() {
$this->resetAfterTest(true);
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
+1 -1
View File
@@ -149,7 +149,7 @@ class auth_email_external extends external_api {
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'Profile field id', VALUE_OPTIONAL),
'shortname' => new external_value(PARAM_ALPHANUM, 'Password policy', VALUE_OPTIONAL),
'shortname' => new external_value(PARAM_ALPHANUMEXT, 'Profile field shortname', VALUE_OPTIONAL),
'name' => new external_value(PARAM_TEXT, 'Profield field name', VALUE_OPTIONAL),
'datatype' => new external_value(PARAM_ALPHANUMEXT, 'Profield field datatype', VALUE_OPTIONAL),
'description' => new external_value(PARAM_RAW, 'Profield field description', VALUE_OPTIONAL),
+2 -1
View File
@@ -263,7 +263,8 @@ class auth_plugin_shibboleth extends auth_plugin_base {
global $OUTPUT;
if (!isset($this->config->user_attribute) || empty($this->config->user_attribute)) {
echo $OUTPUT->notification(get_string("shib_not_set_up_error", "auth_shibboleth"), 'notifyproblem');
echo $OUTPUT->notification(get_string("shib_not_set_up_error", "auth_shibboleth",
(new moodle_url('/auth/shibboleth/README.txt'))->out()), 'notifyproblem');
return;
}
if ($this->config->convert_data and $this->config->convert_data != '' and !is_readable($this->config->convert_data)) {
+3 -2
View File
@@ -32,8 +32,9 @@
$shibbolethauth = get_auth_plugin('shibboleth');
// Check whether Shibboleth is configured properly
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
if (empty($pluginconfig->user_attribute)) {
print_error('shib_not_set_up_error', 'auth_shibboleth');
print_error('shib_not_set_up_error', 'auth_shibboleth', '', $readmeurl);
}
/// If we can find the Shibboleth attribute, save it in session and return to main login page
@@ -91,7 +92,7 @@
elseif (!empty($_SERVER['HTTP_SHIB_APPLICATION_ID']) || !empty($_SERVER['Shib-Application-ID'])) {
print_error('shib_no_attributes_error', 'auth_shibboleth' , '', '\''.$pluginconfig->user_attribute.'\', \''.$pluginconfig->field_map_firstname.'\', \''.$pluginconfig->field_map_lastname.'\' and \''.$pluginconfig->field_map_email.'\'');
} else {
print_error('shib_not_set_up_error', 'auth_shibboleth');
print_error('shib_not_set_up_error', 'auth_shibboleth', '', $readmeurl);
}
+3 -3
View File
@@ -28,7 +28,7 @@ $string['auth_shib_auth_method_description'] = 'Provide a name for the Shibbolet
$string['auth_shib_auth_logo'] = 'Authentication method logo';
$string['auth_shib_auth_logo_description'] = 'Provide a logo for the Shibboleth authentication method that is familiar to your users. This could be the logo of your Shibboleth federation, e.g. <tt>SWITCHaai Login</tt> or <tt>InCommon Login</tt> or similar.';
$string['auth_shib_contact_administrator'] = 'In case you are not associated with the given organizations and you need access to a course on this server, please contact the <a href="mailto:{$a}">Moodle Administrator</a>.';
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth. For set-up details, see the <a href="../auth/shibboleth/README.txt">Shibboleth README</a>.';
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth. For set-up details, see the <a href="{$a}">Shibboleth README</a>.';
$string['auth_shibboleth_errormsg'] = 'Please select the organization you are member of!';
$string['auth_shibboleth_login'] = 'Shibboleth login';
$string['auth_shibboleth_login_long'] = 'Login to Moodle via Shibboleth';
@@ -36,7 +36,7 @@ $string['auth_shibboleth_manual_login'] = 'Manual login';
$string['auth_shibboleth_select_member'] = 'I\'m a member of ...';
$string['auth_shibboleth_select_organization'] = 'For authentication via Shibboleth, please select your organisation from the drop-down menu:';
$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="../auth/shibboleth/README.txt">README</a> for further instructions.';
$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_changepasswordurl'] = 'Password-change URL';
$string['auth_shib_idp_list'] = 'Identity providers';
@@ -57,6 +57,6 @@ $string['auth_shib_username_description'] = 'Name of the webserver Shibboleth en
$string['shib_invalid_account_error'] = 'You seem to be Shibboleth authenticated but Moodle has no valid account for your username. Your account may not exist or it may have been suspended.';
$string['shib_no_attributes_error'] = 'You seem to be Shibboleth authenticated but Moodle didn\'t receive any user attributes. Please check that your Identity Provider releases the necessary attributes ({$a}) to the Service Provider Moodle is running on or inform the webmaster of this server.';
$string['shib_not_all_attributes_error'] = 'Moodle needs certain Shibboleth attributes which are not present in your case. The attributes are: {$a}<br />Please contact the webmaster of this server or your Identity Provider.';
$string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="README.txt">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
$string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="{$a}">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
$string['pluginname'] = 'Shibboleth';
$string['privacy:metadata'] = 'The Shibboleth authentication plugin does not store any personal data.';
+3 -2
View File
@@ -30,8 +30,9 @@ if ($ADMIN->fulltree) {
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_idp_configtextarea.php');
// Introductory explanation.
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
$settings->add(new admin_setting_heading('auth_shibboleth/pluginname', '',
new lang_string('auth_shibbolethdescription', 'auth_shibboleth')));
new lang_string('auth_shibbolethdescription', 'auth_shibboleth', $readmeurl)));
// Username.
$settings->add(new admin_setting_configtext('auth_shibboleth/user_attribute', get_string('username'),
@@ -40,7 +41,7 @@ if ($ADMIN->fulltree) {
// COnvert Data configuration file.
$settings->add(new admin_setting_configfile('auth_shibboleth/convert_data',
get_string('auth_shib_convert_data', 'auth_shibboleth'),
get_string('auth_shib_convert_data_description', 'auth_shibboleth'), ''));
get_string('auth_shib_convert_data_description', 'auth_shibboleth', $readmeurl), ''));
// WAYF.
$settings->add(new auth_shibboleth_admin_setting_special_wayf_select());
-1
View File
@@ -91,7 +91,6 @@ class core_backup_external extends external_api {
require_capability('moodle/backup:backupactivity', $context);
} else {
require_capability('moodle/backup:backupcourse', $context);
$instanceid = $course->id;
}
$results = array();
+2 -2
View File
@@ -55,9 +55,11 @@ require_capability('moodle/restore:restorecourse', $context);
if (is_null($course)) {
$coursefullname = $SITE->fullname;
$courseshortname = $SITE->shortname;
$courseurl = new moodle_url('/');
} else {
$coursefullname = $course->fullname;
$courseshortname = $course->shortname;
$courseurl = course_get_url($course->id);
}
// Show page header.
@@ -173,7 +175,6 @@ if ($restore->get_stage() != restore_ui::STAGE_PROCESS) {
\core\task\manager::queue_adhoc_task($asynctask);
// Add ajax progress bar and initiate ajax via a template.
$courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
$restoreurl = new moodle_url('/backup/restorefile.php', array('contextid' => $contextid));
$progresssetup = array(
'backupid' => $restoreid,
@@ -182,7 +183,6 @@ if ($restore->get_stage() != restore_ui::STAGE_PROCESS) {
'restoreurl' => $restoreurl->out()
);
echo $renderer->render_from_template('core/async_backup_status', $progresssetup);
}
$restore->destroy();
+4 -4
View File
@@ -199,7 +199,7 @@ class core_badges_assertion {
$class['criteria'] = $this->_url->out(false); // Currently issued badge URL.
if ($issued) {
if ($this->_obversion == OPEN_BADGES_V2) {
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id(), 'action' => 0));
$issuerurl = new moodle_url('/badges/issuer_json.php', array('id' => $this->get_badge_id()));
} else {
$issuerurl = new moodle_url('/badges/assertion.php', array('b' => $this->_data->uniquehash, 'action' => 0));
}
@@ -233,7 +233,8 @@ class core_badges_assertion {
$issuer['email'] = $CFG->badges_defaultissuercontact;
}
} else {
$issuer = badges_get_default_issuer();
$badge = new badge($this->get_badge_id());
$issuer = $badge->get_badge_issuer();
}
}
$this->embed_data_badge_version2($issuer, OPEN_BADGES_V2_TYPE_ISSUER);
@@ -341,8 +342,7 @@ class core_badges_assertion {
'/badges/badge_json.php',
array('id' => $this->get_badge_id())
);
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $this->get_badge_id(), 'action' => 0,
'obversion' => $this->_obversion));
$issuerurl = new moodle_url('/badges/issuer_json.php', ['id' => $this->get_badge_id()]);
// For assertion.
if ($type == OPEN_BADGES_V2_TYPE_ASSERTION) {
$json['@context'] = OPEN_BADGES_V2_CONTEXT;
+2 -2
View File
@@ -929,12 +929,12 @@ class badge {
*/
public function get_badge_issuer() {
$issuer = array();
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $this->id, 'action' => 0));
$issuer['name'] = $this->issuername;
$issuer['url'] = $this->issuerurl;
$issuer['email'] = $this->issuercontact;
$issuer['@context'] = OPEN_BADGES_V2_CONTEXT;
$issuer['id'] = $this->issuerurl;
$issueridurl = new moodle_url('/badges/issuer_json.php', array('id' => $this->id));
$issuer['id'] = $issueridurl->out(false);
$issuer['type'] = OPEN_BADGES_V2_TYPE_ISSUER;
return $issuer;
}
+12 -2
View File
@@ -49,7 +49,6 @@ class badge extends moodleform {
$mform = $this->_form;
$badge = (isset($this->_customdata['badge'])) ? $this->_customdata['badge'] : false;
$action = $this->_customdata['action'];
$languages = get_string_manager()->get_list_of_languages();
$mform->addElement('header', 'badgedetails', get_string('badgedetails', 'badges'));
$mform->addElement('text', 'name', get_string('name'), array('size' => '70'));
@@ -61,6 +60,8 @@ class badge extends moodleform {
$mform->addElement('text', 'version', get_string('version', 'badges'), array('size' => '70'));
$mform->setType('version', PARAM_TEXT);
$mform->addHelpButton('version', 'version', 'badges');
$languages = get_string_manager()->get_list_of_languages();
$mform->addElement('select', 'language', get_string('language'), $languages);
$mform->addHelpButton('language', 'language', 'badges');
@@ -157,7 +158,16 @@ class badge extends moodleform {
$mform->setType('action', PARAM_TEXT);
if ($action == 'new') {
$mform->setDefault('language', $CFG->lang);
// Try to set default badge language to that of current language, or it's parent.
$language = current_language();
if (isset($languages[$language])) {
$defaultlanguage = $language;
} else {
// Calling get_parent_language returns an empty string instead of 'en'.
$defaultlanguage = get_parent_language($language) ?: 'en';
}
$mform->setDefault('language', $defaultlanguage);
$this->add_action_buttons(true, get_string('createbutton', 'badges'));
} else {
// Add hidden fields.
+52
View File
@@ -0,0 +1,52 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Serve Issuer JSON for related badge or default Issuer if no badge is defined.
*
* @package core
* @subpackage badges
* @copyright 2020 Sara Arjona <sara@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('AJAX_SCRIPT', true);
define('NO_MOODLE_COOKIES', true); // No need for a session here.
require_once(__DIR__ . '/../config.php');
require_once($CFG->libdir . '/badgeslib.php');
$id = optional_param('id', null, PARAM_INT);
if (empty($id)) {
// Get the default issuer for this site.
$json = badges_get_default_issuer();
} else {
// Get the issuer for this badge.
$badge = new badge($id);
if ($badge->status != BADGE_STATUS_INACTIVE) {
$json = $badge->get_badge_issuer();
} else {
// The badge doen't exist or not accessible for the users.
header("HTTP/1.0 410 Gone");
$badgeurl = new moodle_url('/badges/issuer_json.php', array('id' => $id));
$json = ['id' => $badgeurl->out()];
$json['error'] = get_string('error:relatedbadgedoesntexist', 'badges');
}
}
echo $OUTPUT->header();
echo json_encode($json);
+41 -5
View File
@@ -114,23 +114,59 @@ class PNG_MetaDataHandler
* @param string $value Currently an assertion URL that is added to an image metadata.
*
* @return string $result File content with a new chunk as a string. Can be used in file_put_contents() to write to a file.
* @throws \moodle_exception when unsupported chunk type is defined.
*/
public function add_chunks($type, $key, $value) {
if (strlen($key) > 79) {
debugging('Key is too big');
}
// tEXt Textual data.
// Keyword: 1-79 bytes (character string)
// Null separator: 1 byte
// Text: n bytes (character string)
$data = $key . "\0" . $value;
$dataparts = [];
if ($type === 'iTXt') {
// International textual data (iTXt).
// Keyword: 1-79 bytes (character string).
$dataparts[] = $key;
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Compression flag: 1 byte
// A value of 0 means no compression.
$dataparts[] = "\x00";
// Compression method: 1 byte
// If compression is disabled, the method should also be 0.
$dataparts[] = "\x00";
// Language tag: 0 or more bytes (character string)
// When there is no language specified leave empty.
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Translated keyword: 0 or more bytes
// When there is no translation specified, leave empty.
// Null separator: 1 byte.
$dataparts[] = "\x00";
// Text: 0 or more bytes.
$dataparts[] = $value;
} else if ($type === 'tEXt') {
// Textual data (tEXt).
// Keyword: 1-79 bytes (character string).
$dataparts[] = $key;
// Null separator: 1 byte.
$dataparts[] = "\0";
// Text: n bytes (character string).
$dataparts[] = $value;
} else {
throw new \moodle_exception('Unsupported chunk type: ' . $type);
}
$data = implode($dataparts);
$crc = pack("N", crc32($type . $data));
$len = pack("N", strlen($data));
// Chunk format: length + type + data + CRC.
// CRC is a CRC-32 computed over the chunk type and chunk data.
$newchunk = $len . $type . $data . $crc;
$this->_chunks[$type] = $data;
$result = substr($this->_contents, 0, $this->_size - 12)
. $newchunk
+8 -5
View File
@@ -37,11 +37,14 @@ $string['privacy:metadata'] = 'The File cache cachestore plugin stores data brie
$string['prescan'] = 'Prescan directory';
$string['prescan_help'] = 'If enabled the directory is scanned when the cache is first used and requests for files are first checked against the scan data. This can help if you have a slow file system and are finding that file operations are causing you a bottle neck.';
$string['singledirectory'] = 'Single directory store';
$string['singledirectory_help'] = 'If enabled files (cached items) will be stored in a single directory rather than being broken up into multiple directories.<br />
Enabling this will speed up file interactions but comes at the cost of increased risk of hitting file system limitations.<br />
It is advisable to only turn this on if the following is true:<br />
- If you know the number of items in the cache is going to be small enough that it won\'t cause issues on the file system you are running with.<br />
- The data being cached is not expensive to generate. If it is then sticking with the default may still be the better option as it reduces the chance of issues.';
$string['singledirectory_help'] = 'If enabled files (cached items) will be stored in a single directory rather than being broken up into multiple directories.
Enabling this will speed up file interactions but comes at the cost of increased risk of hitting file system limitations.
It is advisable to only turn this on if the following is true:
* If you know the number of items in the cache is going to be small enough that it won\'t cause issues on the file system you are running with.
* The data being cached is not expensive to generate. If it is then sticking with the default may still be the better option as it reduces the chance of issues.';
/**
* This is is like the file store, but designed for siutations where:
+12
View File
@@ -52,11 +52,23 @@ require_once($CFG->dirroot.'/calendar/lib.php');
$categoryid = optional_param('category', null, PARAM_INT);
$courseid = optional_param('course', SITEID, PARAM_INT);
$view = optional_param('view', 'upcoming', PARAM_ALPHA);
$day = optional_param('cal_d', 0, PARAM_INT);
$mon = optional_param('cal_m', 0, PARAM_INT);
$year = optional_param('cal_y', 0, PARAM_INT);
$time = optional_param('time', 0, PARAM_INT);
$lookahead = optional_param('lookahead', null, PARAM_INT);
$url = new moodle_url('/calendar/view.php');
// If a day, month and year were passed then convert it to a timestamp. If these were passed
// then we can assume the day, month and year are passed as Gregorian, as no where in core
// should we be passing these values rather than the time. This is done for BC.
if (!empty($day) && !empty($mon) && !empty($year)) {
if (checkdate($mon, $day, $year)) {
$time = make_timestamp($year, $mon, $day);
}
}
if (empty($time)) {
$time = time();
}
+34
View File
@@ -4777,6 +4777,40 @@ class api {
$DB->delete_records(template_cohort::TABLE, array('cohortid' => $cohort->id));
}
/**
* Action to perform when a user is deleted.
*
* @param int $userid The user id.
*/
public static function hook_user_deleted($userid) {
global $DB;
$usercompetencies = $DB->get_records(user_competency::TABLE, ['userid' => $userid], '', 'id');
foreach ($usercompetencies as $usercomp) {
$DB->delete_records(evidence::TABLE, ['usercompetencyid' => $usercomp->id]);
}
$DB->delete_records(user_competency::TABLE, ['userid' => $userid]);
$DB->delete_records(user_competency_course::TABLE, ['userid' => $userid]);
$DB->delete_records(user_competency_plan::TABLE, ['userid' => $userid]);
// Delete any associated files.
$fs = get_file_storage();
$context = context_user::instance($userid);
$userevidences = $DB->get_records(user_evidence::TABLE, ['userid' => $userid], '', 'id');
foreach ($userevidences as $userevidence) {
$DB->delete_records(user_evidence_competency::TABLE, ['userevidenceid' => $userevidence->id]);
$DB->delete_records(user_evidence::TABLE, ['id' => $userevidence->id]);
$fs->delete_area_files($context->id, 'core_competency', 'userevidence', $userevidence->id);
}
$userplans = $DB->get_records(plan::TABLE, ['userid' => $userid], '', 'id');
foreach ($userplans as $userplan) {
$DB->delete_records(plan_competency::TABLE, ['planid' => $userplan->id]);
$DB->delete_records(plan::TABLE, ['id' => $userplan->id]);
}
}
/**
* Manually grade a user competency.
*
+43
View File
@@ -207,4 +207,47 @@ class core_competency_hooks_testcase extends advanced_testcase {
$this->assertEquals(1, \core_competency\template_cohort::count_records(array('templateid' => $t1->get('id'))));
$this->assertEquals(0, \core_competency\template_cohort::count_records(array('templateid' => $t2->get('id'))));
}
public function test_hook_user_deleted() {
$this->resetAfterTest();
$dg = $this->getDataGenerator();
$ccg = $dg->get_plugin_generator('core_competency');
$u1 = $dg->create_user();
$framework = $ccg->create_framework();
$comp1 = $ccg->create_competency(['competencyframeworkid' => $framework->get('id')]);
$comp2 = $ccg->create_competency(['competencyframeworkid' => $framework->get('id')]);
$c1 = $dg->create_course();
$cc1a = $ccg->create_course_competency(['competencyid' => $comp1->get('id'), 'courseid' => $c1->id]);
$cc1b = $ccg->create_course_competency(['competencyid' => $comp2->get('id'), 'courseid' => $c1->id]);
$assign1a = $dg->create_module('assign', ['course' => $c1]);
$assign1b = $dg->create_module('assign', ['course' => $c1]);
$cmc1a = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign1a->cmid]);
$cmc1b = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign1b->cmid]);
$ucc1a = $ccg->create_user_competency_course(['competencyid' => $comp1->get('id'), 'courseid' => $c1->id,
'userid' => $u1->id]);
$ucc1b = $ccg->create_user_competency_course(['competencyid' => $comp2->get('id'), 'courseid' => $c1->id,
'userid' => $u1->id]);
$c2 = $dg->create_course();
$cc2a = $ccg->create_course_competency(['competencyid' => $comp1->get('id'), 'courseid' => $c2->id]);
$cc2b = $ccg->create_course_competency(['competencyid' => $comp2->get('id'), 'courseid' => $c2->id]);
$assign2a = $dg->create_module('assign', ['course' => $c2]);
$assign2b = $dg->create_module('assign', ['course' => $c2]);
$cmc2a = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign2a->cmid]);
$cmc2b = $ccg->create_course_module_competency(['competencyid' => $comp1->get('id'), 'cmid' => $assign2b->cmid]);
$ucc2a = $ccg->create_user_competency_course(['competencyid' => $comp1->get('id'), 'courseid' => $c2->id,
'userid' => $u1->id]);
$ucc2b = $ccg->create_user_competency_course(['competencyid' => $comp2->get('id'), 'courseid' => $c2->id,
'userid' => $u1->id]);
reset_course_userdata((object) ['id' => $c1->id, 'reset_competency_ratings' => true]);
delete_user($u1);
// Assert the records don't exist anymore.
$this->assertEquals(0, user_competency_course::count_records(['courseid' => $c1->id, 'userid' => $u1->id]));
}
}
+38 -7
View File
@@ -717,13 +717,49 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
* @return mixed
*/
protected static function get_tree($id) {
global $DB;
$coursecattreecache = cache::make('core', 'coursecattree');
$rv = $coursecattreecache->get($id);
if ($rv !== false) {
return $rv;
}
// Might need to rebuild the tree. Put a lock in place to ensure other requests don't try and do this in parallel.
$lockfactory = \core\lock\lock_config::get_lock_factory('core_coursecattree');
$lock = $lockfactory->get_lock('core_coursecattree_cache',
course_modinfo::COURSE_CACHE_LOCK_WAIT, course_modinfo::COURSE_CACHE_LOCK_EXPIRY);
if ($lock === false) {
// Couldn't get a lock to rebuild the tree.
return [];
}
$rv = $coursecattreecache->get($id);
if ($rv !== false) {
// Tree was built while we were waiting for the lock.
$lock->release();
return $rv;
}
// Re-build the tree.
try {
$all = self::rebuild_coursecattree_cache_contents();
$coursecattreecache->set_many($all);
} finally {
$lock->release();
}
if (array_key_exists($id, $all)) {
return $all[$id];
}
// Requested non-existing category.
return array();
}
/**
* Rebuild the course category tree as an array, including an extra "countall" field.
*
* @return array
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
private static function rebuild_coursecattree_cache_contents() : array {
global $DB;
$sql = "SELECT cc.id, cc.parent, cc.visible
FROM {course_categories} cc
ORDER BY cc.sortorder";
@@ -760,12 +796,7 @@ class core_course_category implements renderable, cacheable_object, IteratorAggr
}
// We must add countall to all in case it was the requested ID.
$all['countall'] = $count;
$coursecattreecache->set_many($all);
if (array_key_exists($id, $all)) {
return $all[$id];
}
// Requested non-existing category.
return array();
return $all;
}
/**
@@ -68,6 +68,17 @@ class course_handler extends \core_customfield\handler {
return self::$singleton;
}
/**
* Run reset code after unit tests to reset the singleton usage.
*/
public static function reset_caches(): void {
if (!PHPUNIT_TEST) {
throw new \coding_exception('This feature is only intended for use in unit tests');
}
static::$singleton = null;
}
/**
* The current user can configure custom fields on this component.
*
+2 -2
View File
@@ -514,7 +514,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
// Output section activities summary:
$o = '';
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities pr-2 mdl-right'));
foreach ($sectionmods as $mod) {
$o.= html_writer::start_tag('span', array('class' => 'activity-count'));
$o.= $mod['name'].': '.$mod['count'];
@@ -528,7 +528,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
$a->complete = $complete;
$a->total = $total;
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
$o.= html_writer::start_tag('div', array('class' => 'section-summary-activities pr-2 mdl-right'));
$o.= html_writer::tag('span', get_string('progresstotal', 'completion', $a), array('class' => 'activity-count'));
$o.= html_writer::end_tag('div');
}
+4 -1
View File
@@ -1144,7 +1144,9 @@ function course_delete_module($cmid, $async = false) {
}
// Delete activity context questions and question categories.
question_delete_activity($cm);
$showinfo = !defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0';
question_delete_activity($cm, $showinfo);
// Call the delete_instance function, if it returns false throw an exception.
if (!$deleteinstancefunction($cm->instance)) {
@@ -2202,6 +2204,7 @@ function move_courses($courseids, $categoryid) {
foreach ($dbcourses as $dbcourse) {
$course = new stdClass();
$course->id = $dbcourse->id;
$course->timemodified = time();
$course->category = $category->id;
$course->sortorder = $category->sortorder + MAX_COURSES_IN_CATEGORY - $i++;
if ($category->visible == 0) {
+2 -1
View File
@@ -316,7 +316,8 @@ if ($action !== false && confirm_sesskey()) {
$notificationsfail[] = get_string('movecategoryownparent', 'error', $cattomove->get_formatted_name());
continue;
}
if (strpos($movetocat->path, $cattomove->path) === 0) {
// Don't allow user to move selected category into one of it's own sub-categories.
if (strpos($movetocat->path, $cattomove->path . '/') === 0) {
$notificationsfail[] = get_string('movecategoryparentconflict', 'error', $cattomove->get_formatted_name());
continue;
}
+1 -1
View File
@@ -17,7 +17,7 @@
<form action="{{searchurl}}" id="{{id}}" method="get" class="form-inline">
<fieldset class="coursesearchbox invisiblefieldset">
<label for="{{inputid}}">{{#str}}searchcourses{{/str}}</label>
<input id="{{inputid}}" name="search" type="text" size="{{inputsize}}" value="{{value}}" class="form-control">
<input id="{{inputid}}" name="search" type="text" size="{{inputsize}}" value="{{value}}" class="form-control mb-1 mb-sm-0">
<button class="btn btn-secondary" type="submit">{{#str}}go{{/str}}</button>
{{#helpicon}}
{{>core/help_icon}}
+14 -18
View File
@@ -38,25 +38,11 @@ use \core_customfield\category_controller;
class core_customfield_api_testcase extends advanced_testcase {
/**
* This method is called after the last test of this test class is run.
*/
public static function tearDownAfterClass() {
$handler = core_course\customfield\course_handler::create();
$handler->delete_all();
}
/**
* Tests set up.
*/
public function setUp() {
$this->resetAfterTest();
}
/**
* Get generator
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator() : core_customfield_generator {
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
@@ -65,7 +51,7 @@ class core_customfield_api_testcase extends advanced_testcase {
*
* @param array $expected
* @param array $array array of objects with "get($property)" method
* @param sring $propertyname
* @param string $propertyname
*/
protected function assert_property_in_array($expected, $array, $propertyname) {
$this->assertEquals($expected, array_values(array_map(function($a) use ($propertyname) {
@@ -80,6 +66,8 @@ class core_customfield_api_testcase extends advanced_testcase {
* in the interface using drag-drop.
*/
public function test_move_category() {
$this->resetAfterTest();
// Create the categories.
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0];
$id0 = $this->get_generator()->create_category($params)->get('id');
@@ -129,6 +117,8 @@ class core_customfield_api_testcase extends advanced_testcase {
* Tests for \core_customfield\api::get_categories_with_fields() behaviour.
*/
public function test_get_categories_with_fields() {
$this->resetAfterTest();
// Create the categories.
$options = [
'component' => 'core_course',
@@ -163,6 +153,8 @@ class core_customfield_api_testcase extends advanced_testcase {
* Test for functions api::save_category() and rename_category)
*/
public function test_save_category() {
$this->resetAfterTest();
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
'contextid' => context_system::instance()->id];
$c1 = category_controller::create(0, (object)$params);
@@ -196,6 +188,8 @@ class core_customfield_api_testcase extends advanced_testcase {
* Test for function handler::create_category
*/
public function test_create_category() {
$this->resetAfterTest();
$handler = \core_course\customfield\course_handler::create();
$c1id = $handler->create_category();
$c1 = $handler->get_categories_with_fields()[$c1id];
@@ -218,6 +212,8 @@ class core_customfield_api_testcase extends advanced_testcase {
* Tests for \core_customfield\api::delete_category() behaviour.
*/
public function test_delete_category_with_fields() {
$this->resetAfterTest();
global $DB;
// Create two categories with fields and data.
$options = [
+15 -17
View File
@@ -37,29 +37,20 @@ use \core_customfield\field_controller;
class core_customfield_category_controller_testcase extends advanced_testcase {
/**
* This method is called after the last test of this test class is run.
*/
public static function tearDownAfterClass() {
$handler = core_course\customfield\course_handler::create();
$handler->delete_all();
}
/**
* Tests set up.
*/
public function setUp() {
$this->resetAfterTest();
}
/**
* Get generator
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator() : core_customfield_generator {
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
/**
* Test for the field_controller::__construct function.
*/
public function test_constructor() {
$this->resetAfterTest();
$c = category_controller::create(0, (object)['component' => 'core_course', 'area' => 'course', 'itemid' => 0]);
$handler = $c->get_handler();
$this->assertTrue($c instanceof category_controller);
@@ -83,6 +74,8 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
*/
public function test_constructor_errors() {
global $DB;
$this->resetAfterTest();
$cat = $this->get_generator()->create_category();
$catrecord = $cat->to_record();
@@ -181,6 +174,7 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
* \core_customfield\category_controller::get()
*/
public function test_create_category() {
$this->resetAfterTest();
// Create the category.
$lpg = $this->get_generator();
@@ -209,6 +203,8 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
* Tests for \core_customfield\category_controller::set() behaviour.
*/
public function test_rename_category() {
$this->resetAfterTest();
// Create the category.
$params = ['component' => 'core_course', 'area' => 'course', 'itemid' => 0, 'name' => 'Cat1',
'contextid' => context_system::instance()->id];
@@ -232,6 +228,8 @@ class core_customfield_category_controller_testcase extends advanced_testcase {
* Tests for \core_customfield\category_controller::delete() behaviour.
*/
public function test_delete_category() {
$this->resetAfterTest();
// Create the category.
$lpg = $this->get_generator();
$category0 = $lpg->create_category();
+8 -18
View File
@@ -35,25 +35,11 @@ use core_customfield\data_controller;
class core_customfield_data_controller_testcase extends advanced_testcase {
/**
* This method is called after the last test of this test class is run.
*/
public static function tearDownAfterClass() {
$handler = core_course\customfield\course_handler::create();
$handler->delete_all();
}
/**
* Tests set up.
*/
public function setUp() {
$this->resetAfterTest();
}
/**
* Get generator
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator() : core_customfield_generator {
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
@@ -62,6 +48,8 @@ class core_customfield_data_controller_testcase extends advanced_testcase {
*/
public function test_constructor() {
global $DB;
$this->resetAfterTest();
// Create a course, fields category and fields.
$course = $this->getDataGenerator()->create_course();
$category0 = $this->get_generator()->create_category(['name' => 'aaaa']);
@@ -130,6 +118,8 @@ class core_customfield_data_controller_testcase extends advanced_testcase {
*/
public function test_constructor_errors() {
global $DB;
$this->resetAfterTest();
// Create a category, field and data.
$category = $this->get_generator()->create_category();
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
@@ -188,4 +178,4 @@ class core_customfield_data_controller_testcase extends advanced_testcase {
$this->assertEquals(moodle_exception::class, get_class($e));
}
}
}
}
+14 -18
View File
@@ -39,25 +39,11 @@ use \core_customfield\field_controller;
class core_customfield_field_controller_testcase extends advanced_testcase {
/**
* This method is called after the last test of this test class is run.
*/
public static function tearDownAfterClass() {
$handler = core_course\customfield\course_handler::create();
$handler->delete_all();
}
/**
* Tests set up.
*/
public function setUp() {
$this->resetAfterTest();
}
/**
* Get generator
* Get generator.
*
* @return core_customfield_generator
*/
protected function get_generator() : core_customfield_generator {
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
@@ -66,6 +52,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
*/
public function test_constructor() {
global $DB;
$this->resetAfterTest();
// Create the category.
$category0 = $this->get_generator()->create_category();
@@ -111,6 +99,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
*/
public function test_constructor_errors() {
global $DB;
$this->resetAfterTest();
// Create a category and a field.
$category = $this->get_generator()->create_category();
$field = $this->get_generator()->create_field(['categoryid' => $category->get('id')]);
@@ -183,6 +173,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
*/
public function test_create_field() {
global $DB;
$this->resetAfterTest();
$lpg = $this->get_generator();
$category = $lpg->create_category();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
@@ -211,6 +203,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
*/
public function test_delete_field() {
global $DB;
$this->resetAfterTest();
$lpg = $this->get_generator();
$category = $lpg->create_category();
$fields = $DB->get_records(\core_customfield\field::TABLE, ['categoryid' => $category->get('id')]);
@@ -237,6 +231,8 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
* Tests for \core_customfield\field_controller::get_configdata_property() behaviour.
*/
public function test_get_configdata_property() {
$this->resetAfterTest();
$lpg = $this->get_generator();
$category = $lpg->create_category();
$configdata = ['a' => 'b', 'c' => ['d', 'e']];
@@ -251,4 +247,4 @@ class core_customfield_field_controller_testcase extends advanced_testcase {
$this->assertEquals(['d', 'e'], $field->get_configdata_property('c'));
$this->assertEquals(null, $field->get_configdata_property('x'));
}
}
}
+1 -9
View File
@@ -35,19 +35,11 @@ defined('MOODLE_INTERNAL') || die();
*/
class core_customfield_generator_testcase extends advanced_testcase {
/**
* This method is called after the last test of this test class is run.
*/
public static function tearDownAfterClass() {
$handler = core_course\customfield\course_handler::create();
$handler->delete_all();
}
/**
* Get generator
* @return core_customfield_generator
*/
protected function get_generator() : core_customfield_generator {
protected function get_generator(): core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
}
+100 -69
View File
@@ -38,71 +38,59 @@ use core_customfield\privacy\provider;
*/
class core_customfield_privacy_testcase extends provider_testcase {
/** @var stdClass[] */
private $courses = [];
/** @var \core_customfield\category_controller[] */
private $cfcats = [];
/** @var \core_customfield\field_controller[] */
private $cffields = [];
/**
* This method is called after the last test of this test class is run.
* Generate data.
*
* @return array
*/
public static function tearDownAfterClass() {
$handler = core_course\customfield\course_handler::create();
$handler->delete_all();
}
/**
* Set up
*/
public function setUp() {
protected function generate_test_data(): array {
$this->resetAfterTest();
$this->cfcats[1] = $this->get_generator()->create_category();
$this->cfcats[2] = $this->get_generator()->create_category();
$this->cffields[11] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'checkbox']);
$this->cffields[12] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'date']);
$this->cffields[13] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[1]->get('id'),
$generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
$cfcats[1] = $generator->create_category();
$cfcats[2] = $generator->create_category();
$cffields[11] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'checkbox']);
$cffields[12] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'date']);
$cffields[13] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'),
'type' => 'select', 'configdata' => ['options' => "a\nb\nc"]]);
$this->cffields[14] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'text']);
$this->cffields[15] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[1]->get('id'), 'type' => 'textarea']);
$this->cffields[21] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[2]->get('id')]);
$this->cffields[22] = $this->get_generator()->create_field(
['categoryid' => $this->cfcats[2]->get('id')]);
$cffields[14] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'text']);
$cffields[15] = $generator->create_field(
['categoryid' => $cfcats[1]->get('id'), 'type' => 'textarea']);
$cffields[21] = $generator->create_field(
['categoryid' => $cfcats[2]->get('id')]);
$cffields[22] = $generator->create_field(
['categoryid' => $cfcats[2]->get('id')]);
$this->courses[1] = $this->getDataGenerator()->create_course();
$this->courses[2] = $this->getDataGenerator()->create_course();
$this->courses[3] = $this->getDataGenerator()->create_course();
$courses[1] = $this->getDataGenerator()->create_course();
$courses[2] = $this->getDataGenerator()->create_course();
$courses[3] = $this->getDataGenerator()->create_course();
$this->get_generator()->add_instance_data($this->cffields[11], $this->courses[1]->id, 1);
$this->get_generator()->add_instance_data($this->cffields[12], $this->courses[1]->id, 1546300800);
$this->get_generator()->add_instance_data($this->cffields[13], $this->courses[1]->id, 2);
$this->get_generator()->add_instance_data($this->cffields[14], $this->courses[1]->id, 'Hello1');
$this->get_generator()->add_instance_data($this->cffields[15], $this->courses[1]->id,
$generator->add_instance_data($cffields[11], $courses[1]->id, 1);
$generator->add_instance_data($cffields[12], $courses[1]->id, 1546300800);
$generator->add_instance_data($cffields[13], $courses[1]->id, 2);
$generator->add_instance_data($cffields[14], $courses[1]->id, 'Hello1');
$generator->add_instance_data($cffields[15], $courses[1]->id,
['text' => '<p>Hi there</p>', 'format' => FORMAT_HTML]);
$this->get_generator()->add_instance_data($this->cffields[21], $this->courses[1]->id, 'hihi1');
$generator->add_instance_data($cffields[21], $courses[1]->id, 'hihi1');
$this->get_generator()->add_instance_data($this->cffields[14], $this->courses[2]->id, 'Hello2');
$generator->add_instance_data($cffields[14], $courses[2]->id, 'Hello2');
$this->get_generator()->add_instance_data($this->cffields[21], $this->courses[2]->id, 'hihi2');
$generator->add_instance_data($cffields[21], $courses[2]->id, 'hihi2');
$this->setUser($this->getDataGenerator()->create_user());
}
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
/**
* Get generator
* @return core_customfield_generator
*/
protected function get_generator() : core_customfield_generator {
return $this->getDataGenerator()->get_plugin_generator('core_customfield');
return [
'user' => $user,
'cfcats' => $cfcats,
'cffields' => $cffields,
'courses' => $courses,
];
}
/**
@@ -119,11 +107,17 @@ class core_customfield_privacy_testcase extends provider_testcase {
*/
public function test_get_customfields_data_contexts() {
global $DB;
list($sql, $params) = $DB->get_in_or_equal([$this->courses[1]->id, $this->courses[2]->id], SQL_PARAMS_NAMED);
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
list($sql, $params) = $DB->get_in_or_equal([$courses[1]->id, $courses[2]->id], SQL_PARAMS_NAMED);
$r = provider::get_customfields_data_contexts('core_course', 'course', '=0',
$sql, $params);
$this->assertEquals([context_course::instance($this->courses[1]->id)->id,
context_course::instance($this->courses[2]->id)->id],
$this->assertEquals([context_course::instance($courses[1]->id)->id,
context_course::instance($courses[2]->id)->id],
$r->get_contextids(), '', 0, 10, true);
}
@@ -131,6 +125,8 @@ class core_customfield_privacy_testcase extends provider_testcase {
* Test for provider::get_customfields_configuration_contexts()
*/
public function test_get_customfields_configuration_contexts() {
$this->generate_test_data();
$r = provider::get_customfields_configuration_contexts('core_course', 'course');
$this->assertEquals([context_system::instance()->id], $r->get_contextids());
}
@@ -140,13 +136,20 @@ class core_customfield_privacy_testcase extends provider_testcase {
*/
public function test_export_customfields_data() {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
// Hack one of the fields so it has an invalid field type.
$invalidfieldid = $this->cffields[21]->get('id');
$invalidfieldid = $cffields[21]->get('id');
$DB->update_record('customfield_field', ['id' => $invalidfieldid, 'type' => 'invalid']);
$context = context_course::instance($this->courses[1]->id);
$context = context_course::instance($courses[1]->id);
$contextlist = new approved_contextlist($USER, 'core_customfield', [$context->id]);
provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $this->courses[1]->id]);
provider::export_customfields_data($contextlist, 'core_course', 'course', '=0', '=:i', ['i' => $courses[1]->id]);
/** @var core_privacy\tests\request\content_writer $writer */
$writer = writer::with_context($context);
@@ -155,7 +158,7 @@ class core_customfield_privacy_testcase extends provider_testcase {
$invaldfieldischecked = false;
foreach ($DB->get_records('customfield_data', []) as $dbrecord) {
$data = $writer->get_data(['Custom fields data', $dbrecord->id]);
if ($dbrecord->instanceid == $this->courses[1]->id) {
if ($dbrecord->instanceid == $courses[1]->id) {
$this->assertEquals($dbrecord->fieldid, $data->fieldid);
$this->assertNotEmpty($data->fieldtype);
$this->assertNotEmpty($data->fieldshortname);
@@ -175,10 +178,17 @@ class core_customfield_privacy_testcase extends provider_testcase {
*/
public function test_delete_customfields_data() {
global $USER, $DB;
$approvedcontexts = new approved_contextlist($USER, 'core_course', [context_course::instance($this->courses[1]->id)->id]);
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
$approvedcontexts = new approved_contextlist($USER, 'core_course', [context_course::instance($courses[1]->id)->id]);
provider::delete_customfields_data($approvedcontexts, 'core_course', 'course');
$this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $this->courses[1]->id]));
$this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $this->courses[2]->id]));
$this->assertEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[1]->id]));
$this->assertNotEmpty($DB->get_records('customfield_data', ['instanceid' => $courses[2]->id]));
}
/**
@@ -186,9 +196,16 @@ class core_customfield_privacy_testcase extends provider_testcase {
*/
public function test_delete_customfields_configuration() {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
// Remember the list of fields in the category 2 before we delete it.
$catid1 = $this->cfcats[1]->get('id');
$catid2 = $this->cfcats[2]->get('id');
$catid1 = $cfcats[1]->get('id');
$catid2 = $cfcats[2]->get('id');
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
$this->assertNotEmpty($fids2);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
@@ -216,9 +233,16 @@ class core_customfield_privacy_testcase extends provider_testcase {
*/
public function test_delete_customfields_configuration_for_context() {
global $USER, $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
// Remember the list of fields in the category 2 before we delete it.
$catid1 = $this->cfcats[1]->get('id');
$catid2 = $this->cfcats[2]->get('id');
$catid1 = $cfcats[1]->get('id');
$catid2 = $cfcats[2]->get('id');
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', 'categoryid=?', [$catid2]);
$this->assertNotEmpty($fids2);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
@@ -246,12 +270,19 @@ class core_customfield_privacy_testcase extends provider_testcase {
*/
public function test_delete_customfields_data_for_context() {
global $DB;
$this->resetAfterTest();
[
'cffields' => $cffields,
'cfcats' => $cfcats,
'courses' => $courses,
] = $this->generate_test_data();
provider::delete_customfields_data_for_context('core_course', 'course',
context_course::instance($this->courses[1]->id));
context_course::instance($courses[1]->id));
$fids2 = $DB->get_fieldset_select('customfield_field', 'id', '1=1', []);
list($fsql, $fparams) = $DB->get_in_or_equal($fids2, SQL_PARAMS_NAMED);
$fparams['course1'] = $this->courses[1]->id;
$fparams['course2'] = $this->courses[2]->id;
$fparams['course1'] = $courses[1]->id;
$fparams['course2'] = $courses[2]->id;
$this->assertEmpty($DB->get_records_select('customfield_data', 'instanceid = :course1 AND fieldid ' . $fsql, $fparams));
$this->assertNotEmpty($DB->get_records_select('customfield_data', 'instanceid = :course2 AND fieldid ' . $fsql, $fparams));
}
+7 -5
View File
@@ -448,8 +448,9 @@ class enrol_self_plugin extends enrol_plugin {
$userid = $instance->userid;
unset($instance->userid);
$this->unenrol_user($instance, $userid);
$days = $instance->customint2 / 60*60*24;
$trace->output("unenrolling user $userid from course $instance->courseid as they have did not log in for at least $days days", 1);
$days = $instance->customint2 / DAYSECS;
$trace->output("unenrolling user $userid from course $instance->courseid " .
"as they did not log in for at least $days days", 1);
}
$rs->close();
@@ -465,8 +466,9 @@ class enrol_self_plugin extends enrol_plugin {
$userid = $instance->userid;
unset($instance->userid);
$this->unenrol_user($instance, $userid);
$days = $instance->customint2 / 60*60*24;
$trace->output("unenrolling user $userid from course $instance->courseid as they have did not access course for at least $days days", 1);
$days = $instance->customint2 / DAYSECS;
$trace->output("unenrolling user $userid from course $instance->courseid " .
"as they did not access the course for at least $days days", 1);
}
$rs->close();
@@ -712,7 +714,7 @@ class enrol_self_plugin extends enrol_plugin {
* @return bool
*/
public function edit_instance_form($instance, MoodleQuickForm $mform, $context) {
global $CFG;
global $CFG, $DB;
// Merge these two settings to one value for the single selection element.
if ($instance->notifyall and $instance->expirynotify) {
+16 -2
View File
@@ -61,7 +61,7 @@ class enrol_self_testcase extends advanced_testcase {
$now = time();
$trace = new null_progress_trace();
$trace = new progress_trace_buffer(new text_progress_trace(), false);
// Prepare some data.
@@ -133,18 +133,32 @@ class enrol_self_testcase extends advanced_testcase {
// Execute sync - this is the same thing used from cron.
$selfplugin->sync($trace, $course2->id);
$output = $trace->get_buffer();
$trace->reset_buffer();
$this->assertEquals(10, $DB->count_records('user_enrolments'));
$this->assertStringContainsString('No expired enrol_self enrolments detected', $output);
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
$this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
$selfplugin->sync($trace, null);
$output = $trace->get_buffer();
$trace->reset_buffer();
$this->assertEquals(6, $DB->count_records('user_enrolments'));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user1->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user2->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user1->id)));
$this->assertFalse($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
$this->assertStringContainsString('unenrolling user ' . $user1->id . ' from course ' . $course1->id .
' as they did not log in for at least 14 days', $output);
$this->assertStringContainsString('unenrolling user ' . $user1->id . ' from course ' . $course3->id .
' as they did not log in for at least 50 days', $output);
$this->assertStringContainsString('unenrolling user ' . $user2->id . ' from course ' . $course1->id .
' as they did not access the course for at least 14 days', $output);
$this->assertStringContainsString('unenrolling user ' . $user3->id . ' from course ' . $course3->id .
' as they did not access the course for at least 50 days', $output);
$this->assertStringNotContainsString('unenrolling user ' . $user4->id, $output);
$this->assertEquals(6, $DB->count_records('role_assignments'));
$this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
@@ -88,7 +88,7 @@ class component_favourite_service_testcase extends advanced_testcase {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
$returns[$index] = $mockrow;
}
}
@@ -107,7 +107,7 @@ class component_favourite_service_testcase extends advanced_testcase {
$crit = ['userid' => $userid, 'component' => $comp, 'itemtype' => $type, 'itemid' => $id, 'contextid' => $ctxid];
foreach ($mockstore as $fakerow) {
$fakerowarr = (array)$fakerow;
if (array_diff($crit, $fakerowarr) == []) {
if (array_diff_assoc($crit, $fakerowarr) == []) {
return $fakerow;
}
}
@@ -133,7 +133,7 @@ class component_favourite_service_testcase extends advanced_testcase {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
$count++;
}
}
@@ -156,7 +156,7 @@ class component_favourite_service_testcase extends advanced_testcase {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
unset($mockstore[$index]);
}
}
@@ -169,7 +169,7 @@ class component_favourite_service_testcase extends advanced_testcase {
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
echo "Here";
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
return true;
}
}
@@ -88,7 +88,7 @@ class user_favourite_service_testcase extends advanced_testcase {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
$returns[$index] = $mockrow;
}
}
@@ -107,7 +107,7 @@ class user_favourite_service_testcase extends advanced_testcase {
$crit = ['userid' => $userid, 'component' => $comp, 'itemtype' => $type, 'itemid' => $id, 'contextid' => $ctxid];
foreach ($mockstore as $fakerow) {
$fakerowarr = (array)$fakerow;
if (array_diff($crit, $fakerowarr) == []) {
if (array_diff_assoc($crit, $fakerowarr) == []) {
return $fakerow;
}
}
@@ -133,7 +133,7 @@ class user_favourite_service_testcase extends advanced_testcase {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
$count++;
}
}
@@ -156,7 +156,7 @@ class user_favourite_service_testcase extends advanced_testcase {
// Check the mockstore for all objects with properties matching the key => val pairs in $criteria.
foreach ($mockstore as $index => $mockrow) {
$mockrowarr = (array)$mockrow;
if (array_diff($criteria, $mockrowarr) == []) {
if (array_diff_assoc($criteria, $mockrowarr) == []) {
return true;
}
}
+31 -3
View File
@@ -37,7 +37,6 @@ require_once($CFG->dirroot . '/filter/activitynames/filter.php'); // Include the
class filter_activitynames_filter_testcase extends advanced_testcase {
public function test_links() {
global $CFG;
$this->resetAfterTest(true);
// Create a test course.
@@ -59,8 +58,8 @@ class filter_activitynames_filter_testcase extends advanced_testcase {
preg_match_all('~<a class="autolink" title="([^"]*)" href="[^"]*/mod/page/view.php\?id=([0-9]+)">([^<]*)</a>~',
$filtered, $matches);
// There should be 3 links links.
$this->assertEquals(2, count($matches[1]));
// There should be 2 links links.
$this->assertCount(2, $matches[1]);
// Check text of title attribute.
$this->assertEquals($page1->name, $matches[1][0]);
@@ -74,4 +73,33 @@ class filter_activitynames_filter_testcase extends advanced_testcase {
$this->assertEquals($page1->name, $matches[3][0]);
$this->assertEquals($page2->name, $matches[3][1]);
}
public function test_links_activity_named_hyphen() {
$this->resetAfterTest(true);
// Create a test course.
$course = $this->getDataGenerator()->create_course();
$context = context_course::instance($course->id);
// Work around an issue with the activity names filter which maintains a static cache
// of activities for current course ID. We can re-build the cache by switching user.
$this->setUser($this->getDataGenerator()->create_user());
// Create a page activity named '-' (single hyphen).
$page = $this->getDataGenerator()->create_module('page', ['course' => $course->id, 'name' => '-']);
$html = '<p>Please read the - page.</p>';
$filtered = format_text($html, FORMAT_HTML, array('context' => $context));
// Find the page link in the filtered html.
preg_match_all('~<a class="autolink" title="([^"]*)" href="[^"]*/mod/page/view.php\?id=([0-9]+)">([^<]*)</a>~',
$filtered, $matches);
// We should have exactly one match.
$this->assertCount(1, $matches[1]);
$this->assertEquals($page->name, $matches[1][0]);
$this->assertEquals($page->cmid, $matches[2][0]);
$this->assertEquals($page->name, $matches[3][0]);
}
}
@@ -54,7 +54,7 @@ $string['leveldefinition'] = 'Level {$a} definition';
$string['levelempty'] = 'Click to edit level';
$string['levelsgroup'] = 'Levels group';
$string['lockzeropoints'] = 'Calculate grade having a minimum score of the minimum achievable grade for the rubric';
$string['lockzeropoints_help'] = 'This setting only applies if the sum of the minimum number of points for each criterion is greater than 0. If ticked, the minimum achievable grade for the rubric will be the minimum achievable grade for the rubric. If unticked, the minimum possible score for the rubric will be mapped to the minimum grade available for the activity (which is 0 unless a scale is used).';
$string['lockzeropoints_help'] = 'This setting only applies if the sum of the minimum number of points for each criterion is greater than 0. If ticked, the minimum score of the activity will be the minimum achievable grade for the rubric. If unticked, the minimum possible score for the rubric will be mapped to the minimum grade available for the activity (which is 0 unless a scale is used).';
$string['name'] = 'Name';
$string['needregrademessage'] = 'The rubric definition was changed after this student had been graded. The student can not see this rubric until you check the rubric and update the grade.';
$string['pluginname'] = 'Rubric';
+39 -5
View File
@@ -128,6 +128,7 @@ class helper {
* @return array sql and params list
*/
protected static function get_users_sql_and_params($context, $search = '', $count = false) {
global $DB, $USER;
// Fields we need from the user table.
$extrafields = get_extra_user_fields($context);
@@ -147,13 +148,33 @@ class helper {
$select = "SELECT DISTINCT $ufields ";
$orderby = " ORDER BY u.lastname ASC, u.firstname ASC";
}
$groupjoinsql = '';
$groupwheresql = '';
$courseid = $context->instanceid;
$groupmode = groups_get_course_groupmode(get_course($courseid));
// We're only interested in separate groups mode because it's the only group mode that requires the user to be a member of
// specific group(s), except when they have the 'moodle/site:accessallgroups' capability.
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
// Fetch the groups that the user can see.
$groups = groups_get_all_groups($courseid, $USER->id, 0, 'g.id');
// Add join condition to include users that only belong to the same group as the user.
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED, 'gid', true, 0);
$groupjoinsql = " JOIN {groups_members} gm ON gm.userid = u.id ";
$groupwheresql = " AND gm.groupid $insql ";
$params = array_merge($params, $inparams);
}
$sql = "$select
FROM {user} u
JOIN {grade_grades_history} ggh ON u.id = ggh.userid
JOIN {grade_items} gi ON gi.id = ggh.itemid
WHERE $filtersql gi.courseid = :courseid";
$groupjoinsql
WHERE $filtersql gi.courseid = :courseid $groupwheresql";
$sql .= $orderby;
$params['courseid'] = $context->instanceid;
$params['courseid'] = $courseid;
return array($sql, $params);
}
@@ -166,18 +187,31 @@ class helper {
* @return array list of graders.
*/
public static function get_graders($courseid) {
global $DB;
global $DB, $USER;
$groupjoinsql = $groupwheresql = '';
$inparams = [];
$groupmode = groups_get_course_groupmode(get_course($courseid));
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', \context_course::instance($courseid))) {
// Fetch the groups that the user can see.
$groups = groups_get_all_groups($courseid, $USER->id, 0, 'g.id');
// Add join condition to include users that only belong to the same group as the user.
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($groups), SQL_PARAMS_NAMED, 'gid', true, 0);
$groupjoinsql = " JOIN {groups_members} gm ON gm.userid = u.id ";
$groupwheresql = " AND gm.groupid $insql ";
}
$ufields = get_all_user_name_fields(true, 'u');
$sql = "SELECT u.id, $ufields
FROM {user} u
JOIN {grade_grades_history} ggh ON ggh.usermodified = u.id
JOIN {grade_items} gi ON gi.id = ggh.itemid
WHERE gi.courseid = :courseid
$groupjoinsql
WHERE gi.courseid = :courseid $groupwheresql
GROUP BY u.id, $ufields
ORDER BY u.lastname ASC, u.firstname ASC";
$graders = $DB->get_records_sql($sql, array('courseid' => $courseid));
$graders = $DB->get_records_sql($sql, array('courseid' => $courseid) + $inparams);
$return = array(0 => get_string('allgraders', 'gradereport_history'));
foreach ($graders as $grader) {
$return[$grader->id] = fullname($grader);
@@ -337,7 +337,7 @@ class tablelog extends \table_sql implements \renderable {
* @return array containing sql to use and an array of params.
*/
protected function get_filters_sql_and_params() {
global $DB;
global $DB, $USER;
$coursecontext = $this->context;
$filter = 'gi.courseid = :courseid';
@@ -368,6 +368,16 @@ class tablelog extends \table_sql implements \renderable {
$params += array('grader' => $this->filters->grader);
}
// If the course is separate group mode and the current user is not allowed to see all groups make sure
// that we display only users from the same groups as current user.
$groupmode = get_course($coursecontext->instanceid)->groupmode;
if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $coursecontext)) {
$groupids = array_column(groups_get_all_groups($coursecontext->instanceid, $USER->id, 0, 'g.id'), 'id');
list($gsql, $gparams) = $DB->get_in_or_equal($groupids, SQL_PARAMS_NAMED, 'gmuparam', true, 0);
$filter .= " AND EXISTS (SELECT 1 FROM {groups_members} gmu WHERE gmu.userid=ggh.userid AND gmu.groupid $gsql)";
$params += $gparams;
}
return array($filter, $params);
}
+157
View File
@@ -53,6 +53,12 @@ class gradereport_history_report_testcase extends advanced_testcase {
$u5 = $this->getDataGenerator()->create_user();
$grader1 = $this->getDataGenerator()->create_user();
$grader2 = $this->getDataGenerator()->create_user();
self::getDataGenerator()->enrol_user($grader1->id, $c1->id, 'teacher');
self::getDataGenerator()->enrol_user($grader2->id, $c1->id, 'teacher');
self::getDataGenerator()->enrol_user($u2->id, $c1->id, 'student');
self::getDataGenerator()->enrol_user($u3->id, $c1->id, 'student');
self::getDataGenerator()->enrol_user($u4->id, $c1->id, 'student');
self::getDataGenerator()->enrol_user($u5->id, $c1->id, 'student');
// Modules.
$c1m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c1));
@@ -65,6 +71,8 @@ class gradereport_history_report_testcase extends advanced_testcase {
$giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign');
$grades = array();
$this->setUser($grader1);
$gi = grade_item::fetch($giparams + array('iteminstance' => $c1m1->id));
$grades['c1m1u1'] = $this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id,
'timemodified' => time() - 3600));
@@ -163,6 +171,20 @@ class gradereport_history_report_testcase extends advanced_testcase {
$this->assertEquals(null, $results[$grades['c2m2u1a']->id]->prevgrade);
$this->assertEquals($grades['c2m2u1a']->finalgrade, $results[$grades['c2m2u1c']->id]->prevgrade);
$this->assertEquals($grades['c2m2u1c']->finalgrade, $results[$grades['c2m2u1e']->id]->prevgrade);
// Put course in separate groups mode, add grader1 and two students to the same group.
$c1->groupmode = SEPARATEGROUPS;
update_course($c1);
$this->assertFalse(has_capability('moodle/site:accessallgroups', \context_course::instance($c1->id)));
$g1 = self::getDataGenerator()->create_group(['courseid' => $c1->id, 'name' => 'g1']);
self::getDataGenerator()->create_group_member(['groupid' => $g1->id, 'userid' => $grader1->id]);
self::getDataGenerator()->create_group_member(['groupid' => $g1->id, 'userid' => $u1->id]);
self::getDataGenerator()->create_group_member(['groupid' => $g1->id, 'userid' => $u2->id]);
$this->assertEquals(2, $this->get_tablelog_results($c1ctx, array(), true));
// Grader2 is not in any groups.
$this->setUser($grader2);
$this->assertEquals(0, $this->get_tablelog_results($c1ctx, array(), true));
}
/**
@@ -219,6 +241,118 @@ class gradereport_history_report_testcase extends advanced_testcase {
$this->assertEquals(1, \gradereport_history\helper::get_users_count($c1ctx, 'c'));
}
/**
* Data provider method for \gradereport_history_report_testcase::test_get_users_with_groups()
*/
public function get_users_provider() {
return [
'Visible groups, non-editing teacher, not in any group' => [
VISIBLEGROUPS, 'teacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
],
'Visible groups, non-editing teacher' => [
VISIBLEGROUPS, 'teacher', [], ['s1', 's2', 's3', 's4', 's5']
],
'Visible groups, editing teacher' => [
VISIBLEGROUPS, 'editingteacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
],
'Separate groups, non-editing teacher' => [
SEPARATEGROUPS, 'teacher', ['g1', 'g2'], ['s1', 's2']
],
'Separate groups, non-editing teacher, not in any group' => [
SEPARATEGROUPS, 'teacher', [], []
],
'Separate groups, non-editing teacher and student share two groups' => [
SEPARATEGROUPS, 'teacher', ['g4', 'g5'], ['s5']
],
'Separate groups, editing teacher' => [
SEPARATEGROUPS, 'editingteacher', ['g1', 'g2'], ['s1', 's2', 's3', 's4', 's5']
],
];
}
/**
* Test for helper::get_users() with course group mode set.
*
* @dataProvider get_users_provider
* @param $groupmode
* @param $teacherrole
* @param $teachergroups
* @param $expectedusers
*/
public function test_get_users_with_groups($groupmode, $teacherrole, $teachergroups, $expectedusers) {
global $DB;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
// Create a test course.
$course = $generator->create_course(['groupmode' => $groupmode]);
// Create an assignment module.
$assign = $generator->create_module('assign', ['course' => $course]);
// Fetch roles.
$role = $DB->get_record('role', ['shortname' => $teacherrole], '*', MUST_EXIST);
$studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
// Create users.
$t1 = $generator->create_user(['username' => 't1', 'email' => 't1@example.com']);
$s1 = $generator->create_user(['username' => 's1', 'email' => 's1@example.com']);
$s2 = $generator->create_user(['username' => 's2', 'email' => 's2@example.com']);
$s3 = $generator->create_user(['username' => 's3', 'email' => 's3@example.com']);
$s4 = $generator->create_user(['username' => 's4', 'email' => 's4@example.com']);
$s5 = $generator->create_user(['username' => 's5', 'email' => 's5@example.com']);
// Enrol users.
$generator->enrol_user($t1->id, $course->id, $role->id);
$generator->enrol_user($s1->id, $course->id, $studentrole->id);
$generator->enrol_user($s2->id, $course->id, $studentrole->id);
$generator->enrol_user($s3->id, $course->id, $studentrole->id);
$generator->enrol_user($s4->id, $course->id, $studentrole->id);
$generator->enrol_user($s5->id, $course->id, $studentrole->id);
// Create groups.
$groups = [];
$groups['g1'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g1']);
$groups['g2'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g2']);
$groups['g3'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g3']);
$groups['g4'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g4']);
$groups['g5'] = $generator->create_group(['courseid' => $course->id, 'name' => 'g5']);
// Add teacher to the assigned groups.
foreach ($teachergroups as $groupname) {
$group = $groups[$groupname];
$generator->create_group_member(['groupid' => $group->id, 'userid' => $t1->id]);
}
// Add students to groups.
$generator->create_group_member(['groupid' => $groups['g1']->id, 'userid' => $s1->id]);
$generator->create_group_member(['groupid' => $groups['g2']->id, 'userid' => $s2->id]);
$generator->create_group_member(['groupid' => $groups['g3']->id, 'userid' => $s3->id]);
$generator->create_group_member(['groupid' => $groups['g4']->id, 'userid' => $s5->id]);
$generator->create_group_member(['groupid' => $groups['g5']->id, 'userid' => $s5->id]);
// Creating grade history for the students.
$gi = grade_item::fetch(['iteminstance' => $assign->id, 'itemtype' => 'mod', 'itemmodule' => 'assign']);
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s1->id]);
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s2->id]);
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s3->id]);
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s4->id]);
$this->create_grade_history(['itemid' => $gi->id, 'userid' => $s5->id]);
// Log in as the teacher.
$this->setUser($t1);
// Fetch the users.
$users = \gradereport_history\helper::get_users(context_course::instance($course->id));
// Confirm that the number of users fetched is the same as the count of expected users.
$this->assertCount(count($expectedusers), $users);
foreach ($users as $user) {
// Confirm that each user returned is in the list of expected users.
$this->assertTrue(in_array($user->username, $expectedusers));
}
}
/**
* Test the get graders helper method.
*/
@@ -228,9 +362,11 @@ class gradereport_history_report_testcase extends advanced_testcase {
// Making the setup.
$c1 = $this->getDataGenerator()->create_course();
$c2 = $this->getDataGenerator()->create_course();
$c3 = $this->getDataGenerator()->create_course(['groupmode' => SEPARATEGROUPS]);
$c1m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c1));
$c2m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c2));
$c3m1 = $this->getDataGenerator()->create_module('assign', array('course' => $c3));
// Users.
$u1 = $this->getDataGenerator()->create_user(array('firstname' => 'Eric', 'lastname' => 'Cartman'));
@@ -238,6 +374,12 @@ class gradereport_history_report_testcase extends advanced_testcase {
$u3 = $this->getDataGenerator()->create_user(array('firstname' => 'Kyle', 'lastname' => 'Broflovski'));
$u4 = $this->getDataGenerator()->create_user(array('firstname' => 'Kenny', 'lastname' => 'McCormick'));
foreach ([$c1, $c2, $c3] as $course) {
foreach ([$u1, $u2, $u3, $u4] as $user) {
self::getDataGenerator()->enrol_user($user->id, $course->id, 'student');
}
}
// Creating grade history for some users.
$gi = grade_item::fetch(array('iteminstance' => $c1m1->id, 'itemtype' => 'mod', 'itemmodule' => 'assign'));
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id, 'usermodified' => $u1->id));
@@ -247,6 +389,10 @@ class gradereport_history_report_testcase extends advanced_testcase {
$gi = grade_item::fetch(array('iteminstance' => $c2m1->id, 'itemtype' => 'mod', 'itemmodule' => 'assign'));
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id, 'usermodified' => $u4->id));
$gi = grade_item::fetch(array('iteminstance' => $c3m1->id, 'itemtype' => 'mod', 'itemmodule' => 'assign'));
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u1->id, 'usermodified' => $u1->id));
$this->create_grade_history(array('itemid' => $gi->id, 'userid' => $u2->id, 'usermodified' => $u2->id));
// Checking fetching some users.
$graders = \gradereport_history\helper::get_graders($c1->id);
$this->assertCount(4, $graders); // Including "all graders" .
@@ -256,6 +402,17 @@ class gradereport_history_report_testcase extends advanced_testcase {
$graders = \gradereport_history\helper::get_graders($c2->id);
$this->assertCount(2, $graders); // Including "all graders" .
$this->assertArrayHasKey($u4->id, $graders);
// Third course is in separate groups mode. Only graders from the same group will be returned.
$g = self::getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'g1']);
self::getDataGenerator()->create_group_member(['groupid' => $g->id, 'userid' => $u1->id]);
self::getDataGenerator()->create_group_member(['groupid' => $g->id, 'userid' => $u2->id]);
$this->setUser($u1);
$graders = \gradereport_history\helper::get_graders($c3->id);
$this->assertCount(3, $graders); // Including "all graders" .
$this->setUser($u3);
$graders = \gradereport_history\helper::get_graders($c3->id);
$this->assertCount(1, $graders); // Including "all graders" .
}
/**
@@ -18,13 +18,13 @@
Bulk insert attribute.
}}
<div class="enable">
<input type="checkbox" name="{{applyname}}" value="1" id="{{applyname}}">
<input type="checkbox" name="{{applyname}}" value="1" id="{{applyname}}" class="ml-0">
<label for="{{applyname}}">{{applylabel}}</label>
</div>
<fieldset class="form-inline">
<legend class="accesshide">{{label}}</legend>
<label for="{{menuname}}">{{menulabel}}</label>
<select name="{{menuname}}" id="{{menuname}}" class="form-control">
<select name="{{menuname}}" id="{{menuname}}" class="form-control custom-select">
{{#menuoptions}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
{{/menuoptions}}
+2 -2
View File
@@ -171,7 +171,7 @@ if ($editform->is_cancelled()) {
$table->width = '90%';
}
$table->data = array();
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
foreach ($groups as $group) {
$line = array();
if (groups_get_group_by_name($courseid, $group['name'])) {
@@ -183,7 +183,7 @@ if ($editform->is_cancelled()) {
if ($data->allocateby != 'no') {
$unames = array();
foreach ($group['members'] as $user) {
$unames[] = fullname($user, true);
$unames[] = fullname($user, $viewfullnames);
}
$line[] = implode(', ', $unames);
$line[] = count($group['members']);
@@ -77,8 +77,10 @@ class user_groups_editable extends \core\output\inplace_editable {
foreach ($coursegroups as $group) {
$options[$group->id] = format_string($group->name, true, ['context' => $this->context]);
}
$this->edithint = get_string('editusersgroupsa', 'group', fullname($user));
$this->editlabel = get_string('editusersgroupsa', 'group', fullname($user));
$fullname = fullname($user, has_capability('moodle/site:viewfullnames', $this->context));
$this->edithint = get_string('editusersgroupsa', 'group', $fullname);
$this->editlabel = get_string('editusersgroupsa', 'group', $fullname);
$attributes = ['multiple' => true];
$this->set_type_autocomplete($options, $attributes);
+2 -1
View File
@@ -556,7 +556,8 @@ class core_group_external extends external_api {
require_capability('moodle/course:managegroups', $context);
if (!groups_remove_member_allowed($group, $user)) {
throw new moodle_exception('errorremovenotpermitted', 'group', '', fullname($user));
$fullname = fullname($user, has_capability('moodle/site:viewfullnames', $context));
throw new moodle_exception('errorremovenotpermitted', 'group', '', $fullname);
}
groups_remove_member($group, $user);
}
+8 -2
View File
@@ -81,6 +81,9 @@ switch ($action) {
case 'ajax_getmembersingroup':
$roles = array();
if ($groupmemberroles = groups_get_members_by_role($groupids[0], $courseid, 'u.id, ' . get_all_user_name_fields(true, 'u'))) {
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
foreach($groupmemberroles as $roleid=>$roledata) {
$shortroledata = new stdClass();
$shortroledata->name = $roledata->name;
@@ -88,7 +91,7 @@ switch ($action) {
foreach($roledata->users as $member) {
$shortmember = new stdClass();
$shortmember->id = $member->id;
$shortmember->name = fullname($member, true);
$shortmember->name = fullname($member, $viewfullnames);
$shortroledata->users[] = $shortmember;
}
$roles[] = $shortroledata;
@@ -190,12 +193,15 @@ $members = array();
if ($singlegroup) {
$usernamefields = get_all_user_name_fields(true, 'u');
if ($groupmemberroles = groups_get_members_by_role(reset($groupids), $courseid, 'u.id, ' . $usernamefields)) {
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
foreach ($groupmemberroles as $roleid => $roledata) {
$users = array();
foreach ($roledata->users as $member) {
$users[] = (object)[
'value' => $member->id,
'text' => fullname($member, true)
'text' => fullname($member, $viewfullnames)
];
}
$members[] = (object)[
+3 -1
View File
@@ -248,9 +248,11 @@ foreach ($members as $gpgid=>$groupdata) {
$line[] = html_writer::tag('span', $name, array('class' => 'group_hoverdescription', 'data-groupid' => $gpid));
$hoverevents[$gpid] = get_string('descriptiona', null, $jsdescription);
}
$viewfullnames = has_capability('moodle/site:viewfullnames', $context);
$fullnames = array();
foreach ($users as $user) {
$fullnames[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$user->id.'&amp;course='.$course->id.'">'.fullname($user, true).'</a>';
$fullnames[] = html_writer::link(new moodle_url('/user/view.php', ['id' => $user->id, 'course' => $course->id]),
fullname($user, $viewfullnames));
}
$line[] = implode(', ', $fullnames);
$line[] = count($users);
+34
View File
@@ -0,0 +1,34 @@
<?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/>.
/**
* 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['parentlanguage'] = 'ar';
$string['thislanguage'] = 'بالعربي workplace';
+1 -1
View File
@@ -46,7 +46,7 @@ $string['downloadedfilecheckfailed'] = 'Ha fallat la comprovació del fitxer bai
$string['invalidmd5'] = 'L\'md5 no és vàlid. Torneu a provar-ho';
$string['missingrequiredfield'] = 'Falta algun camp necessari';
$string['remotedownloaderror'] = '<p>No s\'ha pogut baixar el component al vostre servidor. Verifiqueu els paràmetres del servidor intermediari. Es recomana vivament l\'extensió cURL de PHP.</p>
<p>Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació «{$a->dest}» del vostre servidor i descomprimir-lo allí.</p>';
<p>Haureu de baixar manualment el fitxer <a href="{$a->url}">{$a->url}</a>, copiar-lo a la ubicació «{$a->dest}» del vostre servidor i descomprimir-lo allà.</p>';
$string['wrongdestpath'] = 'El camí de destinació és erroni';
$string['wrongsourcebase'] = 'L\'adreça (URL) base de la font és errònia';
$string['wrongzipfilename'] = 'El nom del fitxer ZIP és erroni';
+2 -2
View File
@@ -45,7 +45,7 @@ $string['datarootpermission'] = 'Zugriffsrechte zum Datenverzeichnis';
$string['dbprefix'] = 'Tabellen-Prefix';
$string['dirroot'] = 'Moodle-Verzeichnis';
$string['environmenthead'] = 'Installationsvoraussetzungen werden geprüft ...';
$string['environmentsub2'] = 'Jede Version hat Mindestvoraussetzungen für der PHP-Version und für verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird eine vollständige Prüfung durchgeführt. Bitte fragen Sie den Administrator des Servers, wenn Sie mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommen.';
$string['environmentsub2'] = 'Jede Version hat Mindestvoraussetzungen für der PHP-Version und für verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird eine vollständige Prüfung durchgeführt. Bitte fragen Sie die Administrator/innen des Servers, wenn Sie mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommen.';
$string['errorsinenvironment'] = 'Fehler bei der Prüfung der Systemvoraussetzungen!';
$string['installation'] = 'Installation';
$string['langdownloaderror'] = 'Das Sprachpaket \'{$a}\' konnte nicht heruntergeladen werden. Die Installation wird in englischer Sprache fortgesetzt.';
@@ -63,7 +63,7 @@ $string['pathserrcreatedataroot'] = 'Das Datenverzeichnis ({$a->dataroot}) kann
$string['pathshead'] = 'Pfade bestätigen';
$string['pathsrodataroot'] = 'Das Verzeichnis dataroot ist schreibgeschützt.';
$string['pathsroparentdataroot'] = 'Das Verzeichnis ({$a->parent}) ist schreibgeschützt. Deswegen kann das Datenverzeichnis ({$a->dataroot}) vom Installer nicht angelegt werden.';
$string['pathssubadmindir'] = 'Einige Webserver benutzen /admin als speziellen Link, um auf Einstellungsseiten oder Ähnliches zu verweisen. Unglücklicherweise kollidiert dies mit dem standardmäßigen Verzeichnis für die Moodle-Administration. Sie können dieses Problem beheben, indem Sie das Verzeichnis admin in Ihrer Moodle-Installation umbenennen und den neuen Namen hier eingeben (z.B. <em>moodleadmin</em>). Mit dieser Änderung werden alle Admin-Links korrigiert.';
$string['pathssubadmindir'] = 'Einige Webserver benutzen /admin als speziellen Link, um auf Einstellungsseiten oder Ähnliches zu verweisen. Unglücklicherweise kollidiert dies mit dem Verzeichnis für die Moodle-Administration. Sie können dieses Problem beheben, indem Sie das Verzeichnis admin in Ihrer Moodle-Installation umbenennen und den neuen Namen hier eingeben (z.B. <em>moodleadmin</em>). Mit dieser Änderung werden alle Admin-Links korrigiert.';
$string['pathssubdataroot'] = '<p>Sie benötigen einen Platz, wo Moodle hochgeladene Dateien abspeichern kann. </p><p>Dieses Verzeichnis muss Lese- und Schreibrechte für das Nutzerkonto besitzen, mit dem Ihr Webservers läuft (üblicherweise \'nobody\', \'apache\' oder \'www-data).</p><p> Außerdem sollte das Verzeichnis nicht direkt aus dem Internet erreichbar sein. </p><p>Das Intallationsskript wird versuchen, ein solches Verzeichnis zu erstellen, falls es nicht existiert.</p>';
$string['pathssubdirroot'] = '<p>Vollständiger Pfad der Moodle-Installation.</p>';
$string['pathssubwwwroot'] = '<p>Webadresse, die ein Nutzer im Browser eingibt, um auf Moodle zuzugreifen.</p><p> Es ist nicht möglich, über unterschiedliche Adressen auf Moodle zuzugreifen. Sollte Ihre Website mehrere öffentliche Adressen verwenden, so müssen Sie eine Adresse festlegen und für die übrigen Adressen dauerhafte Weiterleitungen dorthin einrichten.</p>
+1 -1
View File
@@ -45,6 +45,6 @@ $string['downloadedfilecheckfailed'] = 'Αποτυχία ελέγχου αρχε
$string['invalidmd5'] = 'Η μεταβλητή ελέγχου ήταν λανθασμένη - δοκιμάστε ξανά';
$string['missingrequiredfield'] = 'Κάποιο απαιτούμενο πεδίο λείπει';
$string['remotedownloaderror'] = '<p>Η λήψη του στοιχείου λογισμικού στον εξυπηρετητή σας απέτυχε. Παρακαλούμε επαληθεύστε τις ρυθμίσεις του διακομιστή μεσολάβησης (proxy)· η επέκταση PHP cURL συνιστάται θερμά.</p><br /><p>Πρέπει να κατεβάσετε το αρχείο <a href="{$a->url}">{$a->url}</a> χειροκίνητα, να το αντιγράψετε στο «{$a->dest}» στον εξυπηρετητή σας και να το αποσυμπιέσετε εκεί.</p>';
$string['wrongdestpath'] = 'Λανθασμένη διαδρομή προορισμού (πλήρες όνομα).';
$string['wrongdestpath'] = 'Λανθασμένο μονοπάτι προορισμού.';
$string['wrongsourcebase'] = 'Λανθασμένη βάση πηγής URL.';
$string['wrongzipfilename'] = 'Λανθασμένo όνομα αρχείου ZIP.';
+2 -2
View File
@@ -70,12 +70,12 @@ $string['pathsroparentdataroot'] = 'Ο γονικός φάκελος ({$a->paren
$string['pathssubadmindir'] = 'Κάποιοι λίγοι κεντρικοί υπολογιστές ιστού χρησιμοποιούν το /admin ως ειδική διεύθυνση URL για την πρόσβαση σε κάποιο πίνακα ελέγχου ή κάτι τέτοιο. Δυστυχώς αυτό έρχεται σε αντίθεση με την τυπική τοποθεσία των σελίδων διαχείρισης (admin) του Moodle. Αυτό μπορεί να διορθωθεί με την μετονομασία του admin φακέλου στην εγκατάστασή σας, και βάζοντας αυτό το καινούργιο όνομα εδώ. Για παράδειγμα: <em>moodleadmin</em>. Αυτό θα διορθώσει όλους τους συνδέσμους με το admin στην διεύθυνσή τους σε όλη την εγκατάσταση του Moodle σας.';
$string['pathssubdataroot'] = '<p>Ένας φάκελος όπου το Moodle θα αποθηκεύει όλα τα ανεβασμένα από τους χρήστες αρχεία.</p> <p>Αυτος ο φάκελος θα πρέπει να είναι αναγνώσιμος ΚΑΙ ΕΓΓΡΑΨΙΜΟΣ από τον χρήστη του εξυπηρετητή ιστού (συνήθως «nobody» ή «apache»).</p> <p>Δεν πρέπει να είναι προσβάσιμος κατευθείαν από τον ιστό.</p> <p>Αν ο φάκελος δεν υπάρχει, η διαδικασία εγκατάστασης θα προσπαθήσει να τον δημιουργήσει.</p>';
$string['pathssubdirroot'] = '<p>Η πλήρης διαδρομή του φακέλου που περιέχει τα αρχεία κώδικα του Moodle.</p>';
$string['pathssubwwwroot'] = '<p>Η πλήρης διεύθυνση (ιστού) από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.</p>
$string['pathssubwwwroot'] = '<p>Η πλήρης διεύθυνση από την οποία θα γίνεται η πρόσβαση στο Moodle, δηλαδή η διεύθυνση που οι χρήστες θα εισάγουν στην γραμμή διεύθυνσης του περιηγητή, για να έχουν πρόσβαση στου Moodle.</p>
<p>Δεν είναι δυνατόν να έχετε πρόβαση στο Moodle χρησιμοποιώντας πολλαπλές διευθύνσεις. Εάν ο ιστότοπος θα είναι προσβάσιμος μέσω πολλαπλών διευθύνσεων τότε επιλέξτε την ευκολότερη και εγκαταστήστε μια μόνιμη ανακατεύθυνση για καθεμία από τις άλλες διευθύνσεις.</p>
<p>Εάν ο ιστότοπός σας είναι προσβάσιμος τόσο από το Διαδίκτυο όσο και από ένα εσωτερικό δίκτυο (που συχνά λέγεται intranet) τότε χρησιμοποιήστε εδώ την δημόσια διεύθυνση.</p>
<p>Αν η τρέχουσα διεύθυνση δεν είναι σωστή, παρακαλούμε αλλάξτε την URL διεύθυνση στην γραμμή διευθύνσεων του περιηγητή σας και επανεκκινήστε την εγκατάσταση.</p>';
$string['pathsunsecuredataroot'] = 'Η τοποθεσία του Φάκελου Δεδομένων δεν είναι ασφαλής';
$string['pathswrongadmindir'] = 'Ο Φάκελος Admin δεν υπάρχει';
$string['pathswrongadmindir'] = 'Ο φάκελος Admin δεν υπάρχει';
$string['phpextension'] = 'Επέκταση {$a} της PHP';
$string['phpversion'] = 'Έκδοση της PHP';
$string['phpversionhelp'] = 'p>Το Moodle απαιτεί η έκδοση της PHP να είναι τουλάχιστον 5.6.5 ή 7.1 (η 7.0.x έχει κάποιους περιορισμούς στη μηχανή).</p>
+1
View File
@@ -31,4 +31,5 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'es';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Español para la Empresa';
+1
View File
@@ -31,4 +31,5 @@
defined('MOODLE_INTERNAL') || die();
$string['parentlanguage'] = 'he';
$string['thisdirection'] = 'rtl';
$string['thislanguage'] = 'עברית בתי־ספר';
+35
View File
@@ -0,0 +1,35 @@
<?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/>.
/**
* 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['clianswerno'] = 'ל';
$string['cliansweryes'] = 'כ';
$string['cliincorrectvalueretry'] = 'ערך לא תקין, נסו שוב בבקשה';
+34
View File
@@ -0,0 +1,34 @@
<?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/>.
/**
* 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['parentlanguage'] = 'ja';
$string['thislanguage'] = 'Workplace準拠の日本語';
+1 -1
View File
@@ -30,4 +30,4 @@
defined('MOODLE_INTERNAL') || die();
$string['thislanguage'] = 'myanma bhasa';
$string['thislanguage'] = 'ဗမာစာ';
+33
View File
@@ -0,0 +1,33 @@
<?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/>.
/**
* 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'] = 'Afaan Oromoo';
+12 -10
View File
@@ -60,7 +60,7 @@ $string['allowindexingexceptlogin'] = 'Everywhere except login and signup pages'
$string['allowindexingnowhere'] = 'Nowhere';
$string['allowusermailcharset'] = 'Allow user to select character set';
$string['allowframembedding'] = 'Allow frame embedding';
$string['allowframembedding_help'] = 'If enabled, this site may be embedded in a frame in a remote system, as recommended when using the \'Publish as LTI tool\' enrolment plugin. Otherwise, it is recommended to leave frame embedding disabled for security reasons.<br />Please, note also that for the mobile app this setting is ignored and frame embedding is always allowed.';
$string['allowframembedding_help'] = 'If enabled, this site may be embedded in a frame in a remote system, as recommended when using the \'Publish as LTI tool\' enrolment plugin. Otherwise, it is recommended to leave frame embedding disabled for security reasons. Please note that for the mobile app this setting is ignored and frame embedding is always allowed.';
$string['allowguestmymoodle'] = 'Allow guest access to Dashboard';
$string['allowobjectembed'] = 'Allow EMBED and OBJECT tags';
$string['allowthemechangeonurl'] = 'Allow theme changes in the URL';
@@ -183,15 +183,15 @@ $string['configcourseswithsummarieslimit'] = 'The maximum number of courses to d
$string['configcronclionly'] = 'Running the cron from a web browser can expose privileged information to anonymous users. Thus it is recommended to only run the cron from the command line or set a cron password for remote access.';
$string['configcronremotepassword'] = 'This means that the cron.php script cannot be run from a web browser without supplying the password using the following form of URL:<pre> https://site.example.com/admin/cron.php?password=opensesame </pre>If this is left empty, no password is required.';
$string['configcurlcache'] = 'Time-to-live for cURL cache, in seconds.';
$string['configcustommenuitems'] = 'You can configure a custom menu here to be shown by themes. Each line consists of some menu text, a link URL (optional), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. Lines starting with a hyphen will appear as menu items in the previous top level menu, and dividers can be used by adding a line of one or more # characters where desired. For example:
$string['configcustommenuitems'] = 'A custom menu may be configured here. Enter each menu item on a new line with format: menu text, a link URL (optional, not for a top menu item with sub-items), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. Lines starting with a hyphen will appear as menu items in the previous top level menu and ### makes a divider. For example:
<pre>
Moodle community|https://moodle.org
-Moodle free support|https://moodle.org/support
-Moodle Docs|https://docs.moodle.org|Moodle Docs
-German Moodle Docs|https://docs.moodle.org/de|Documentation in German|de
Courses
-All courses|/course/
-Course search|/course/search.php
-###
-Moodle development|https://moodle.org/development
Moodle.com|https://moodle.com/
-FAQ|https://someurl.xyz/faq
-Preguntas más frecuentes|https://someurl.xyz/pmf||es
Mobile app|https://someurl.xyz/app|Download our app
</pre>';
$string['configcustomusermenuitems'] = 'You can configure the contents of the user menu (with the exception of the log out link, which is automatically added). Each line is separated by pipe characters and consists of 1) a string in "langstringname, componentname" form or as plain text, 2) a URL, and 3) an icon either as a pix icon (in the folder pix with the structure [subfoldername]/[iconname], e.g. i/publish) or as a URL. Dividers can be used by adding a line of one or more # characters where desired.';
$string['configdbsessions'] = 'If enabled, this setting will use the database to store information about current sessions. Note that changing this setting now will log out all current users (including you). If you are using MySQL please make sure that \'max_allowed_packet\' in my.cnf (or my.ini) is at least 4M. Other session drivers can be configured directly in config.php, see config-dist.php for more information. This option disappears if you specify session driver in config.php file.';
@@ -230,7 +230,7 @@ $string['configenablerssfeedsdisabled2'] = 'RSS feeds are currently disabled at
$string['configenablesafebrowserintegration'] = 'This adds the choice \'Require Safe Exam Browser\' to the \'Browser security\' field on the quiz settings form. See https://www.safeexambrowser.org/ for more information.';
$string['configenablestats'] = 'If you choose \'yes\' here, Moodle\'s cronjob will process the logs and gather some statistics. Depending on the amount of traffic on your site, this can take awhile. If you enable this, you will be able to see some interesting graphs and statistics about each of your courses, or on a sitewide basis.';
$string['configenabletrusttext'] = 'By default Moodle will always thoroughly clean text that comes from users to remove any possible bad scripts, media etc that could be a security risk. The Trusted Content system is a way of giving particular users that you trust the ability to include these advanced features in their content without interference. To enable this system, you need to first enable this setting, and then grant the Trusted Content permission to a specific Moodle role. Texts created or uploaded by such users will be marked as trusted and will not be cleaned before display.';
$string['configenablewebservices'] = 'Web services enable other systems to log in to this Moodle and perform operations. For extra security this feature should be disabled unless you are really using it.';
$string['configenablewebservices'] = 'Web services enable other systems, such as the Moodle app, to log in to the site and perform operations. For extra security, the setting should be disabled if you are not using the app, or an external tool/service that requires integration via web services.';
$string['configenablewsdocumentation'] = 'Enable auto-generation of web services documentation. A user can access to his own documentation on his security keys page {$a}. It displays the documentation for the enabled protocols only.';
$string['configerrorlevel'] = 'Choose the amount of PHP warnings that you want to be displayed. Normal is usually the best choice.';
$string['configexportlookahead'] = 'Days to look ahead during export';
@@ -319,6 +319,7 @@ $string['configrequestedstudentname'] = 'Word for student used in requested cour
$string['configrequestedstudentsname'] = 'Word for students used in requested courses';
$string['configrequestedteachername'] = 'Word for teacher used in requested courses';
$string['configrequestedteachersname'] = 'Word for teachers used in requested courses';
$string['configreverseproxyignore'] = 'If your server is behind multiple reverse proxies that append to the X-Forwarded-For header then you will need to specify a comma separated list of ip addresses or subnets of the reverse proxies to be ignored in order to find the users correct IP address.';
$string['configuserquota'] = 'The maximum number of bytes that a user can store in their own private file area. {$a->bytes} bytes == {$a->displaysize}';
$string['configsectioninterface'] = 'Interface';
$string['configsectionmail'] = 'Mail';
@@ -1043,6 +1044,7 @@ $string['restorernewroleid'] = 'Restorers\' role in courses';
$string['restorernewroleid_help'] = 'If the user does not already have the permission to manage the newly restored course, the user is automatically assigned this role and enrolled if necessary. Select "None" if you do not want restorers to be able to manage every restored course.';
$string['resultfilter'] = 'Filter by result';
$string['reverseproxy'] = 'Reverse proxy';
$string['reverseproxyignore'] = 'Ignore reverse proxies';
$string['riskconfig'] = 'Users could change site configuration and behaviour';
$string['riskconfigshort'] = 'Configuration risk';
$string['riskdataloss'] = 'Users could destroy large amounts of content or information';
@@ -1421,4 +1423,4 @@ $string['configloginhttps'] = 'Turning this on will make Moodle use a secure htt
$string['loginhttps'] = 'Use HTTPS for logins';
// Deprecated since Moodle 3.7.
$string['allowblockstodock'] = 'Allow blocks to use the dock';
$string['configallowblockstodock'] = 'If enabled and supported by the selected theme users can choose to move blocks to a special dock.';
$string['configallowblockstodock'] = 'If enabled and supported by the selected theme users can choose to move blocks to a special dock.';
+1 -1
View File
@@ -246,7 +246,7 @@ $string['criteria_5_help'] = 'Allows a badge to be awarded to users who have com
$string['criteria_6'] = 'Profile completion';
$string['criteria_6_help'] = 'Allows a badge to be awarded to users for completing certain fields in their profile. You can select from default and custom profile fields that are available to users. ';
$string['criteria_7'] = 'Awarded badges';
$string['criteria_7_help'] = 'Allows a badge to be awarded to users based on the other badges thay have earned.';
$string['criteria_7_help'] = 'Allows a badge to be awarded to users based on other badges they have earned.';
$string['criteria_8'] = 'Cohort membership';
$string['criteria_8_help'] = 'Allows a badge to be awarded to users based on cohort membership.';
$string['criteria_9'] = 'Competencies';
+10 -5
View File
@@ -516,7 +516,7 @@ $string['displayonpage'] = 'Display on page';
$string['dndcourse'] = 'You can drag and drop this course to alter its sorting or to move it to another category.';
$string['dndenabled_inbox'] = 'You can drag and drop files here to add them.';
$string['dndnotsupported'] = 'Drag and drop upload not supported';
$string['dndnotsupported_help'] = 'Your browser does not support drag and drop upload.<br />This feature is available in all recent versions of Chrome, Firefox and Safari, as well as Internet Explorer v10 and above.';
$string['dndnotsupported_help'] = 'Your browser does not support drag and drop upload. This feature is available in all recent versions of Chrome, Firefox and Safari, as well as Internet Explorer v10 and above.';
$string['dndnotsupported_insentence'] = 'drag and drop not supported';
$string['dnduploadwithoutcontent'] = 'This upload does not have any content';
$string['dndworkingfiletextlink'] = 'Drag and drop files, text or links onto course sections to upload them';
@@ -1229,14 +1229,18 @@ $string['moddoesnotsupporttype'] = 'Module {$a->modname} does not support upload
$string['modhide'] = 'Hide';
$string['modshow'] = 'Show';
$string['modvisible'] = 'Availability';
$string['modvisible_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).<br><br>
$string['modvisible_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).
If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).';
$string['modvisiblewithstealth'] = 'Availability';
$string['modvisiblewithstealth_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).<br><br>
If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).<br><br>
$string['modvisiblewithstealth_help'] = 'If the availability is set to \'Show on course page\', the activity or resource is available to students (subject to any access restrictions which may be set).
If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).
If the course contains many activities or resources, the course page may be simplified by setting the availability to \'Make available but not shown on course page\'. In this case, a link to the activity or resource must be provided from elsewhere, such as from a page resource. The activity would still be listed in the gradebook and other reports.';
$string['modvisiblehiddensection'] = 'Availability';
$string['modvisiblehiddensection_help'] = 'If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).<br><br>
$string['modvisiblehiddensection_help'] = 'If the availability is set to \'Hide from students\', the activity or resource is only available to users with permission to view hidden activities (by default, users with the role of teacher or non-editing teacher).
If the course contains many activities or resources, the course page may be simplified by setting the availability to \'Make available but not shown on course page\'. In this case, a link to the activity or resource must be provided from elsewhere, such as from a page resource. The activity would still be listed in the gradebook and other reports.';
$string['moodlelogo'] = 'Moodle logo';
$string['month'] = 'Month';
@@ -1808,6 +1812,7 @@ $string['shortnameuser'] = 'User short name';
$string['shortsitename'] = 'Short name for site (eg single word)';
$string['show'] = 'Show';
$string['showactions'] = 'Show actions';
$string['showadvancededitor'] = 'Advanced';
$string['showadvancedsettings'] = 'Show advanced settings';
$string['showall'] = 'Show all {$a}';
$string['showallcourses'] = 'Show all courses';
+1 -1
View File
@@ -283,7 +283,7 @@ $string['questiondoesnotexist'] = 'This question does not exist';
$string['questionname'] = 'Question name';
$string['questionno'] = 'Question {$a}';
$string['questionsaveerror'] = 'Errors occur during saving question - ({$a})';
$string['questionsinuse'] = '(* Questions marked by an asterisk are already in use in some quizzes. These questions will not be deleted from these quizzes but only from the category list.)';
$string['questionsinuse'] = '(* Questions marked with an asterisk are used somewhere, for example in a quiz. Therefore, if you proceed, these questions will not really be deleted, they will just be hidden.)';
$string['questionsmovedto'] = 'Questions still in use moved to "{$a}" in the parent course category.';
$string['questionsrescuedfrom'] = 'Questions saved from context {$a}.';
$string['questionsrescuedfrominfo'] = 'These questions (some of which may be hidden) were saved when context {$a} was deleted because they are still used by some quizzes or other activities.';
+102 -26
View File
@@ -27,7 +27,7 @@ $string['africa/abidjan'] = 'Africa/Abidjan';
$string['africa/accra'] = 'Africa/Accra';
$string['africa/addis_ababa'] = 'Africa/Addis_Ababa';
$string['africa/algiers'] = 'Africa/Algiers';
$string['africa/asmera'] = 'Africa/Asmera';
$string['africa/asmara'] = 'Africa/Asmara';
$string['africa/bamako'] = 'Africa/Bamako';
$string['africa/bangui'] = 'Africa/Bangui';
$string['africa/banjul'] = 'Africa/Banjul';
@@ -48,6 +48,7 @@ $string['africa/freetown'] = 'Africa/Freetown';
$string['africa/gaborone'] = 'Africa/Gaborone';
$string['africa/harare'] = 'Africa/Harare';
$string['africa/johannesburg'] = 'Africa/Johannesburg';
$string['africa/juba'] = 'Africa/Juba';
$string['africa/kampala'] = 'Africa/Kampala';
$string['africa/khartoum'] = 'Africa/Khartoum';
$string['africa/kigali'] = 'Africa/Kigali';
@@ -71,32 +72,35 @@ $string['africa/nouakchott'] = 'Africa/Nouakchott';
$string['africa/ouagadougou'] = 'Africa/Ouagadougou';
$string['africa/porto-novo'] = 'Africa/Porto-Novo';
$string['africa/sao_tome'] = 'Africa/Sao_Tome';
$string['africa/timbuktu'] = 'Africa/Timbuktu';
$string['africa/tripoli'] = 'Africa/Tripoli';
$string['africa/tunis'] = 'Africa/Tunis';
$string['africa/windhoek'] = 'Africa/Windhoek';
$string['america/adak'] = 'America/Adak';
$string['america/anguilla'] = 'America/Anguilla';
$string['america/anchorage'] = 'America/Anchorage';
$string['america/anguilla'] = 'America/Anguilla';
$string['america/antigua'] = 'America/Antigua';
$string['america/araguaina'] = 'America/Araguaina';
$string['america/argentina/buenos_aires'] = 'America/Argentina/Buenos_Aires';
$string['america/argentina/catamarca'] = 'America/Argentina/Catamarca';
$string['america/argentina/comodrivadavia'] = 'America/Argentina/ComodRivadavia';
$string['america/argentina/cordoba'] = 'America/Argentina/Cordoba';
$string['america/argentina/jujuy'] = 'America/Argentina/Jujuy';
$string['america/argentina/la_rioja'] = 'America/Argentina/La_Rioja';
$string['america/argentina/mendoza'] = 'America/Argentina/Mendoza';
$string['america/argentina/rio_gallegos'] = 'America/Argentina/Rio_Gallegos';
$string['america/argentina/salta'] = 'America/Argentina/Salta';
$string['america/argentina/san_juan'] = 'America/Argentina/San_Juan';
$string['america/argentina/san_luis'] = 'America/Argentina/San_Luis';
$string['america/argentina/tucuman'] = 'America/Argentina/Tucuman';
$string['america/argentina/ushuaia'] = 'America/Argentina/Ushuaia';
$string['america/aruba'] = 'America/Aruba';
$string['america/asuncion'] = 'America/Asuncion';
$string['america/atikokan'] = 'America/Atikokan';
$string['america/bahia'] = 'America/Bahia';
$string['america/bahia_banderas'] = 'America/Bahia_Banderas';
$string['america/barbados'] = 'America/Barbados';
$string['america/belem'] = 'America/Belem';
$string['america/belize'] = 'America/Belize';
$string['america/blanc-sablon'] = 'America/Blanc-Sablon';
$string['america/boa_vista'] = 'America/Boa_Vista';
$string['america/bogota'] = 'America/Bogota';
$string['america/boise'] = 'America/Boise';
@@ -106,7 +110,10 @@ $string['america/cancun'] = 'America/Cancun';
$string['america/caracas'] = 'America/Caracas';
$string['america/cayenne'] = 'America/Cayenne';
$string['america/cayman'] = 'America/Cayman';
$string['america/chicago'] = 'America/Chicago';
$string['america/chihuahua'] = 'America/Chihuahua';
$string['america/costa_rica'] = 'America/Costa_Rica';
$string['america/creston'] = 'America/Creston';
$string['america/cuiaba'] = 'America/Cuiaba';
$string['america/curacao'] = 'America/Curacao';
$string['america/danmarkshavn'] = 'America/Danmarkshavn';
@@ -118,6 +125,7 @@ $string['america/dominica'] = 'America/Dominica';
$string['america/edmonton'] = 'America/Edmonton';
$string['america/eirunepe'] = 'America/Eirunepe';
$string['america/el_salvador'] = 'America/El_Salvador';
$string['america/fort_nelson'] = 'America/Fort_Nelson';
$string['america/fortaleza'] = 'America/Fortaleza';
$string['america/glace_bay'] = 'America/Glace_Bay';
$string['america/godthab'] = 'America/Godthab';
@@ -131,40 +139,50 @@ $string['america/guyana'] = 'America/Guyana';
$string['america/halifax'] = 'America/Halifax';
$string['america/havana'] = 'America/Havana';
$string['america/hermosillo'] = 'America/Hermosillo';
$string['america/chicago'] = 'America/Chicago';
$string['america/chihuahua'] = 'America/Chihuahua';
$string['america/indiana/indianapolis'] = 'America/Indiana/Indianapolis';
$string['america/indiana/knox'] = 'America/Indiana/Knox';
$string['america/indiana/marengo'] = 'America/Indiana/Marengo';
$string['america/indianapolis'] = 'America/Indianapolis';
$string['america/indiana/petersburg'] = 'America/Indiana/Petersburg';
$string['america/indiana/tell_city'] = 'America/Indiana/Tell_City';
$string['america/indiana/vevay'] = 'America/Indiana/Vevay';
$string['america/indiana/vincennes'] = 'America/Indiana/Vincennes';
$string['america/indiana/winamac'] = 'America/Indiana/Winamac';
$string['america/inuvik'] = 'America/Inuvik';
$string['america/iqaluit'] = 'America/Iqaluit';
$string['america/jamaica'] = 'America/Jamaica';
$string['america/juneau'] = 'America/Juneau';
$string['america/kentucky/louisville'] = 'America/Kentucky/Louisville';
$string['america/kentucky/monticello'] = 'America/Kentucky/Monticello';
$string['america/kralendijk'] = 'America/Kralendijk';
$string['america/la_paz'] = 'America/La_Paz';
$string['america/lima'] = 'America/Lima';
$string['america/los_angeles'] = 'America/Los_Angeles';
$string['america/louisville'] = 'America/Louisville';
$string['america/lower_princes'] = 'America/Lower_Princes';
$string['america/maceio'] = 'America/Maceio';
$string['america/managua'] = 'America/Managua';
$string['america/manaus'] = 'America/Manaus';
$string['america/marigot'] = 'America/Marigot';
$string['america/martinique'] = 'America/Martinique';
$string['america/matamoros'] = 'America/Matamoros';
$string['america/mazatlan'] = 'America/Mazatlan';
$string['america/menominee'] = 'America/Menominee';
$string['america/merida'] = 'America/Merida';
$string['america/metlakatla'] = 'America/Metlakatla';
$string['america/mexico_city'] = 'America/Mexico_City';
$string['america/miquelon'] = 'America/Miquelon';
$string['america/moncton'] = 'America/Moncton';
$string['america/monterrey'] = 'America/Monterrey';
$string['america/montevideo'] = 'America/Montevideo';
$string['america/montreal'] = 'America/Montreal';
$string['america/montserrat'] = 'America/Montserrat';
$string['america/nassau'] = 'America/Nassau';
$string['america/new_york'] = 'America/New_York';
$string['america/nipigon'] = 'America/Nipigon';
$string['america/nome'] = 'America/Nome';
$string['america/noronha'] = 'America/Noronha';
$string['america/north_dakota/beulah'] = 'America/North_Dakota/Beulah';
$string['america/north_dakota/center'] = 'America/North_Dakota/Center';
$string['america/north_dakota/new_salem'] = 'America/North_Dakota/New_Salem';
$string['america/ojinaga'] = 'America/Ojinaga';
$string['america/panama'] = 'America/Panama';
$string['america/pangnirtung'] = 'America/Pangnirtung';
$string['america/paramaribo'] = 'America/Paramaribo';
@@ -173,15 +191,20 @@ $string['america/port-au-prince'] = 'America/Port-au-Prince';
$string['america/port_of_spain'] = 'America/Port_of_Spain';
$string['america/porto_velho'] = 'America/Porto_Velho';
$string['america/puerto_rico'] = 'America/Puerto_Rico';
$string['america/punta_arenas'] = 'America/Punta_Arenas';
$string['america/rainy_river'] = 'America/Rainy_River';
$string['america/rankin_inlet'] = 'America/Rankin_Inlet';
$string['america/recife'] = 'America/Recife';
$string['america/regina'] = 'America/Regina';
$string['america/resolute'] = 'America/Resolute';
$string['america/rio_branco'] = 'America/Rio_Branco';
$string['america/santarem'] = 'America/Santarem';
$string['america/santiago'] = 'America/Santiago';
$string['america/santo_domingo'] = 'America/Santo_Domingo';
$string['america/sao_paulo'] = 'America/Sao_Paulo';
$string['america/scoresbysund'] = 'America/Scoresbysund';
$string['america/sitka'] = 'America/Sitka';
$string['america/st_barthelemy'] = 'America/St_Barthelemy';
$string['america/st_johns'] = 'America/St_Johns';
$string['america/st_kitts'] = 'America/St_Kitts';
$string['america/st_lucia'] = 'America/St_Lucia';
@@ -202,12 +225,15 @@ $string['america/yellowknife'] = 'America/Yellowknife';
$string['antarctica/casey'] = 'Antarctica/Casey';
$string['antarctica/davis'] = 'Antarctica/Davis';
$string['antarctica/dumontdurville'] = 'Antarctica/DumontDUrville';
$string['antarctica/macquarie'] = 'Antarctica/Macquarie';
$string['antarctica/mawson'] = 'Antarctica/Mawson';
$string['antarctica/mcmurdo'] = 'Antarctica/McMurdo';
$string['antarctica/palmer'] = 'Antarctica/Palmer';
$string['antarctica/rothera'] = 'Antarctica/Rothera';
$string['antarctica/syowa'] = 'Antarctica/Syowa';
$string['antarctica/troll'] = 'Antarctica/Troll';
$string['antarctica/vostok'] = 'Antarctica/Vostok';
$string['arctic/longyearbyen'] = 'Arctic/Longyearbyen';
$string['asia/aden'] = 'Asia/Aden';
$string['asia/almaty'] = 'Asia/Almaty';
$string['asia/amman'] = 'Asia/Amman';
@@ -215,34 +241,39 @@ $string['asia/anadyr'] = 'Asia/Anadyr';
$string['asia/aqtau'] = 'Asia/Aqtau';
$string['asia/aqtobe'] = 'Asia/Aqtobe';
$string['asia/ashgabat'] = 'Asia/Ashgabat';
$string['asia/atyrau'] = 'Asia/Atyrau';
$string['asia/baghdad'] = 'Asia/Baghdad';
$string['asia/bahrain'] = 'Asia/Bahrain';
$string['asia/baku'] = 'Asia/Baku';
$string['asia/bangkok'] = 'Asia/Bangkok';
$string['asia/barnaul'] = 'Asia/Barnaul';
$string['asia/beirut'] = 'Asia/Beirut';
$string['asia/bishkek'] = 'Asia/Bishkek';
$string['asia/brunei'] = 'Asia/Brunei';
$string['asia/calcutta'] = 'Asia/Calcutta';
$string['asia/chita'] = 'Asia/Chita';
$string['asia/choibalsan'] = 'Asia/Choibalsan';
$string['asia/colombo'] = 'Asia/Colombo';
$string['asia/damascus'] = 'Asia/Damascus';
$string['asia/dhaka'] = 'Asia/Dhaka';
$string['asia/dili'] = 'Asia/Dili';
$string['asia/dubai'] = 'Asia/Dubai';
$string['asia/dushanbe'] = 'Asia/Dushanbe';
$string['asia/famagusta'] = 'Asia/Famagusta';
$string['asia/gaza'] = 'Asia/Gaza';
$string['asia/harbin'] = 'Asia/Harbin';
$string['asia/hebron'] = 'Asia/Hebron';
$string['asia/ho_chi_minh'] = 'Asia/Ho_Chi_Minh';
$string['asia/hong_kong'] = 'Asia/Hong_Kong';
$string['asia/hovd'] = 'Asia/Hovd';
$string['asia/choibalsan'] = 'Asia/Choibalsan';
$string['asia/chongqing'] = 'Asia/Chongqing';
$string['asia/irkutsk'] = 'Asia/Irkutsk';
$string['asia/jakarta'] = 'Asia/Jakarta';
$string['asia/jayapura'] = 'Asia/Jayapura';
$string['asia/jerusalem'] = 'Asia/Jerusalem';
$string['asia/kabul'] = 'Asia/Kabul';
$string['asia/kamchatka'] = 'Asia/Kamchatka';
$string['asia/karachi'] = 'Asia/Karachi';
$string['asia/kashgar'] = 'Asia/Kashgar';
$string['asia/katmandu'] = 'Asia/Katmandu';
$string['asia/kathmandu'] = 'Asia/Kathmandu';
$string['asia/khandyga'] = 'Asia/Khandyga';
$string['asia/kolkata'] = 'Asia/Kolkata';
$string['asia/krasnoyarsk'] = 'Asia/Krasnoyarsk';
$string['asia/kuala_lumpur'] = 'Asia/Kuala_Lumpur';
$string['asia/kuching'] = 'Asia/Kuching';
@@ -253,6 +284,7 @@ $string['asia/makassar'] = 'Asia/Makassar';
$string['asia/manila'] = 'Asia/Manila';
$string['asia/muscat'] = 'Asia/Muscat';
$string['asia/nicosia'] = 'Asia/Nicosia';
$string['asia/novokuznetsk'] = 'Asia/Novokuznetsk';
$string['asia/novosibirsk'] = 'Asia/Novosibirsk';
$string['asia/omsk'] = 'Asia/Omsk';
$string['asia/oral'] = 'Asia/Oral';
@@ -260,42 +292,47 @@ $string['asia/phnom_penh'] = 'Asia/Phnom_Penh';
$string['asia/pontianak'] = 'Asia/Pontianak';
$string['asia/pyongyang'] = 'Asia/Pyongyang';
$string['asia/qatar'] = 'Asia/Qatar';
$string['asia/qostanay'] = 'Asia/Qostanay';
$string['asia/qyzylorda'] = 'Asia/Qyzylorda';
$string['asia/rangoon'] = 'Asia/Rangoon';
$string['asia/riyadh'] = 'Asia/Riyadh';
$string['asia/saigon'] = 'Asia/Saigon';
$string['asia/sakhalin'] = 'Asia/Sakhalin';
$string['asia/samarkand'] = 'Asia/Samarkand';
$string['asia/seoul'] = 'Asia/Seoul';
$string['asia/shanghai'] = 'Asia/Shanghai';
$string['asia/singapore'] = 'Asia/Singapore';
$string['asia/srednekolymsk'] = 'Asia/Srednekolymsk';
$string['asia/taipei'] = 'Asia/Taipei';
$string['asia/tashkent'] = 'Asia/Tashkent';
$string['asia/tbilisi'] = 'Asia/Tbilisi';
$string['asia/tehran'] = 'Asia/Tehran';
$string['asia/thimphu'] = 'Asia/Thimphu';
$string['asia/tokyo'] = 'Asia/Tokyo';
$string['asia/tomsk'] = 'Asia/Tomsk';
$string['asia/ulaanbaatar'] = 'Asia/Ulaanbaatar';
$string['asia/urumqi'] = 'Asia/Urumqi';
$string['asia/ust-nera'] = 'Asia/Ust-Nera';
$string['asia/vientiane'] = 'Asia/Vientiane';
$string['asia/vladivostok'] = 'Asia/Vladivostok';
$string['asia/yakutsk'] = 'Asia/Yakutsk';
$string['asia/yangon'] = 'Asia/Yangon';
$string['asia/yekaterinburg'] = 'Asia/Yekaterinburg';
$string['asia/yerevan'] = 'Asia/Yerevan';
$string['atlantic/azores'] = 'Atlantic/Azores';
$string['atlantic/bermuda'] = 'Atlantic/Bermuda';
$string['atlantic/canary'] = 'Atlantic/Canary';
$string['atlantic/cape_verde'] = 'Atlantic/Cape_Verde';
$string['atlantic/faeroe'] = 'Atlantic/Faeroe';
$string['atlantic/faroe'] = 'Atlantic/Faroe';
$string['atlantic/madeira'] = 'Atlantic/Madeira';
$string['atlantic/reykjavik'] = 'Atlantic/Reykjavik';
$string['atlantic/south_georgia'] = 'Atlantic/South_Georgia';
$string['atlantic/stanley'] = 'Atlantic/Stanley';
$string['atlantic/st_helena'] = 'Atlantic/St_Helena';
$string['atlantic/stanley'] = 'Atlantic/Stanley';
$string['australia/adelaide'] = 'Australia/Adelaide';
$string['australia/brisbane'] = 'Australia/Brisbane';
$string['australia/broken_hill'] = 'Australia/Broken_Hill';
$string['australia/currie'] = 'Australia/Currie';
$string['australia/darwin'] = 'Australia/Darwin';
$string['australia/eucla'] = 'Australia/Eucla';
$string['australia/hobart'] = 'Australia/Hobart';
$string['australia/lindeman'] = 'Australia/Lindeman';
$string['australia/lord_howe'] = 'Australia/Lord_Howe';
@@ -304,51 +341,69 @@ $string['australia/perth'] = 'Australia/Perth';
$string['australia/sydney'] = 'Australia/Sydney';
$string['europe/amsterdam'] = 'Europe/Amsterdam';
$string['europe/andorra'] = 'Europe/Andorra';
$string['europe/astrakhan'] = 'Europe/Astrakhan';
$string['europe/athens'] = 'Europe/Athens';
$string['europe/belfast'] = 'Europe/Belfast';
$string['europe/belgrade'] = 'Europe/Belgrade';
$string['europe/berlin'] = 'Europe/Berlin';
$string['europe/bratislava'] = 'Europe/Bratislava';
$string['europe/brussels'] = 'Europe/Brussels';
$string['europe/budapest'] = 'Europe/Budapest';
$string['europe/bucharest'] = 'Europe/Bucharest';
$string['europe/budapest'] = 'Europe/Budapest';
$string['europe/busingen'] = 'Europe/Busingen';
$string['europe/chisinau'] = 'Europe/Chisinau';
$string['europe/copenhagen'] = 'Europe/Copenhagen';
$string['europe/dublin'] = 'Europe/Dublin';
$string['europe/gibraltar'] = 'Europe/Gibraltar';
$string['europe/guernsey'] = 'Europe/Guernsey';
$string['europe/helsinki'] = 'Europe/Helsinki';
$string['europe/chisinau'] = 'Europe/Chisinau';
$string['europe/isle_of_man'] = 'Europe/Isle_of_Man';
$string['europe/istanbul'] = 'Europe/Istanbul';
$string['europe/jersey'] = 'Europe/Jersey';
$string['europe/kaliningrad'] = 'Europe/Kaliningrad';
$string['europe/kiev'] = 'Europe/Kiev';
$string['europe/kirov'] = 'Europe/Kirov';
$string['europe/lisbon'] = 'Europe/Lisbon';
$string['europe/ljubljana'] = 'Europe/Ljubljana';
$string['europe/london'] = 'Europe/London';
$string['europe/luxembourg'] = 'Europe/Luxembourg';
$string['europe/madrid'] = 'Europe/Madrid';
$string['europe/malta'] = 'Europe/Malta';
$string['europe/mariehamn'] = 'Europe/Mariehamn';
$string['europe/minsk'] = 'Europe/Minsk';
$string['europe/monaco'] = 'Europe/Monaco';
$string['europe/moscow'] = 'Europe/Moscow';
$string['europe/oslo'] = 'Europe/Oslo';
$string['europe/paris'] = 'Europe/Paris';
$string['europe/podgorica'] = 'Europe/Podgorica';
$string['europe/prague'] = 'Europe/Prague';
$string['europe/riga'] = 'Europe/Riga';
$string['europe/rome'] = 'Europe/Rome';
$string['europe/samara'] = 'Europe/Samara';
$string['europe/san_marino'] = 'Europe/San_Marino';
$string['europe/sarajevo'] = 'Europe/Sarajevo';
$string['europe/saratov'] = 'Europe/Saratov';
$string['europe/simferopol'] = 'Europe/Simferopol';
$string['europe/skopje'] = 'Europe/Skopje';
$string['europe/sofia'] = 'Europe/Sofia';
$string['europe/stockholm'] = 'Europe/Stockholm';
$string['europe/tallinn'] = 'Europe/Tallinn';
$string['europe/tirane'] = 'Europe/Tirane';
$string['europe/ulyanovsk'] = 'Europe/Ulyanovsk';
$string['europe/uzhgorod'] = 'Europe/Uzhgorod';
$string['europe/vaduz'] = 'Europe/Vaduz';
$string['europe/vatican'] = 'Europe/Vatican';
$string['europe/vienna'] = 'Europe/Vienna';
$string['europe/vilnius'] = 'Europe/Vilnius';
$string['europe/volgograd'] = 'Europe/Volgograd';
$string['europe/warsaw'] = 'Europe/Warsaw';
$string['europe/zagreb'] = 'Europe/Zagreb';
$string['europe/zaporozhye'] = 'Europe/Zaporozhye';
$string['europe/zurich'] = 'Europe/Zurich';
$string['indian/antananarivo'] = 'Indian/Antananarivo';
$string['indian/comoro'] = 'Indian/Comoro';
$string['indian/chagos'] = 'Indian/Chagos';
$string['indian/christmas'] = 'Indian/Christmas';
$string['indian/cocos'] = 'Indian/Cocos';
$string['indian/comoro'] = 'Indian/Comoro';
$string['indian/kerguelen'] = 'Indian/Kerguelen';
$string['indian/mahe'] = 'Indian/Mahe';
$string['indian/maldives'] = 'Indian/Maldives';
@@ -357,6 +412,9 @@ $string['indian/mayotte'] = 'Indian/Mayotte';
$string['indian/reunion'] = 'Indian/Reunion';
$string['pacific/apia'] = 'Pacific/Apia';
$string['pacific/auckland'] = 'Pacific/Auckland';
$string['pacific/bougainville'] = 'Pacific/Bougainville';
$string['pacific/chatham'] = 'Pacific/Chatham';
$string['pacific/chuuk'] = 'Pacific/Chuuk';
$string['pacific/easter'] = 'Pacific/Easter';
$string['pacific/efate'] = 'Pacific/Efate';
$string['pacific/enderbury'] = 'Pacific/Enderbury';
@@ -368,7 +426,6 @@ $string['pacific/gambier'] = 'Pacific/Gambier';
$string['pacific/guadalcanal'] = 'Pacific/Guadalcanal';
$string['pacific/guam'] = 'Pacific/Guam';
$string['pacific/honolulu'] = 'Pacific/Honolulu';
$string['pacific/chatham'] = 'Pacific/Chatham';
$string['pacific/kiritimati'] = 'Pacific/Kiritimati';
$string['pacific/kosrae'] = 'Pacific/Kosrae';
$string['pacific/kwajalein'] = 'Pacific/Kwajalein';
@@ -382,14 +439,33 @@ $string['pacific/noumea'] = 'Pacific/Noumea';
$string['pacific/pago_pago'] = 'Pacific/Pago_Pago';
$string['pacific/palau'] = 'Pacific/Palau';
$string['pacific/pitcairn'] = 'Pacific/Pitcairn';
$string['pacific/ponape'] = 'Pacific/Ponape';
$string['pacific/pohnpei'] = 'Pacific/Pohnpei';
$string['pacific/port_moresby'] = 'Pacific/Port_Moresby';
$string['pacific/rarotonga'] = 'Pacific/Rarotonga';
$string['pacific/saipan'] = 'Pacific/Saipan';
$string['pacific/tahiti'] = 'Pacific/Tahiti';
$string['pacific/tarawa'] = 'Pacific/Tarawa';
$string['pacific/tongatapu'] = 'Pacific/Tongatapu';
$string['pacific/truk'] = 'Pacific/Truk';
$string['pacific/wake'] = 'Pacific/Wake';
$string['pacific/wallis'] = 'Pacific/Wallis';
$string['utc'] = 'UTC';
// The following identifiers have been previous removed from TimeDateZone::listIdentifiers and are no longer used.
// Deprecated since Moodle 3.9.
$string['africa/asmera'] = 'Africa/Asmera';
$string['africa/timbuktu'] = 'Africa/Timbuktu';
$string['america/argentina/comodrivadavia'] = 'America/Argentina/ComodRivadavia';
$string['america/indianapolis'] = 'America/Indianapolis';
$string['america/louisville'] = 'America/Louisville';
$string['america/montreal'] = 'America/Montreal';
$string['asia/calcutta'] = 'Asia/Calcutta';
$string['asia/chongqing'] = 'Asia/Chongqing';
$string['asia/harbin'] = 'Asia/Harbin';
$string['asia/kashgar'] = 'Asia/Kashgar';
$string['asia/katmandu'] = 'Asia/Katmandu';
$string['asia/rangoon'] = 'Asia/Rangoon';
$string['asia/saigon'] = 'Asia/Saigon';
$string['atlantic/faeroe'] = 'Atlantic/Faeroe';
$string['europe/belfast'] = 'Europe/Belfast';
$string['pacific/ponape'] = 'Pacific/Ponape';
$string['pacific/truk'] = 'Pacific/Truk';
$string['pacific/yap'] = 'Pacific/Yap';
@@ -20,6 +20,12 @@ class ADODB_postgres8 extends ADODB_postgres7
{
var $databaseType = 'postgres8';
// From PostgreSQL 8.0 onwards, the adsrc column used in earlier versions to
// retrieve the default value is obsolete and should not be used (see #562).
var $metaDefaultsSQL = "SELECT d.adnum as num, pg_get_expr(d.adbin, d.adrelid) as def
FROM pg_attrdef d, pg_class c
WHERE d.adrelid=c.oid AND c.relname='%s'
ORDER BY d.adnum";
/**
* Retrieve last inserted ID
+2 -1
View File
@@ -33,5 +33,6 @@ Our changes:
* MDL-58546 replaced each() with foreach for PHP 7.2 compatibility.
pull request upstream: https://github.com/ADOdb/ADOdb/pull/373
* MDL-65920 solved PHP 7.2 deprecations; create_function() and each().
* MDL-67414 Fix to make the library PostgreSQL 12.x compliant (upstream: a4876f100602c2ce4).
skodak, iarenaza, moodler, stronk7, abgreeve, lameze, ankitagarwal, marinaglancy
skodak, iarenaza, moodler, stronk7, abgreeve, lameze, ankitagarwal, marinaglancy, matteo
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -114,7 +114,7 @@ function($, log, str, templates, notification, LoadingIcon) {
});
var context = $.extend({items: items}, options, state);
// Render the template.
return templates.render('core/form_autocomplete_selection', context)
return templates.render('core/form_autocomplete_selection_items', context)
.then(function(html, js) {
// Add it to the page.
templates.replaceNodeContents(newSelection, html, js);
+10 -6
View File
@@ -503,10 +503,13 @@ function badges_bake($hash, $badgeid, $userid = 0, $pathhash = false) {
$contents = $file->get_content();
$filehandler = new PNG_MetaDataHandler($contents);
$assertion = new moodle_url('/badges/assertion.php', array('b' => $hash));
if ($filehandler->check_chunks("tEXt", "openbadges")) {
// Add assertion URL tExt chunk.
$newcontents = $filehandler->add_chunks("tEXt", "openbadges", $assertion->out(false));
// For now, the site backpack OB version will be used as default.
$obversion = badges_open_badges_backpack_api();
$assertion = new core_badges_assertion($hash, $obversion);
$assertionjson = json_encode($assertion->get_badge_assertion());
if ($filehandler->check_chunks("iTXt", "openbadges")) {
// Add assertion URL iTXt chunk.
$newcontents = $filehandler->add_chunks("iTXt", "openbadges", $assertionjson);
$fileinfo = array(
'contextid' => $user_context->id,
'component' => 'badges',
@@ -868,7 +871,7 @@ function badges_get_default_issuer() {
global $CFG, $SITE;
$issuer = array();
$issuerurl = new moodle_url('/badges/issuer.php');
$issuerurl = new moodle_url('/');
$issuer['name'] = $CFG->badges_defaultissuername;
if (empty($issuer['name'])) {
$issuer['name'] = $SITE->fullname ? $SITE->fullname : $SITE->shortname;
@@ -876,7 +879,8 @@ function badges_get_default_issuer() {
$issuer['url'] = $issuerurl->out(false);
$issuer['email'] = $CFG->badges_defaultissuercontact;
$issuer['@context'] = OPEN_BADGES_V2_CONTEXT;
$issuer['id'] = $issuerurl->out(false);
$issuerid = new moodle_url('/badges/issuer_json.php');
$issuer['id'] = $issuerid->out(false);
$issuer['type'] = OPEN_BADGES_V2_TYPE_ISSUER;
return $issuer;
}
+9 -19
View File
@@ -338,20 +338,11 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
if (!$timeout) {
$timeout = self::get_timeout();
}
if ($microsleep) {
// Will sleep 1/10th of a second by default for self::get_timeout() seconds.
$loops = $timeout * 10;
} else {
// Will sleep for self::get_timeout() seconds.
$loops = $timeout;
}
// DOM will never change on non-javascript case; do not wait or try again.
if (!$this->running_javascript()) {
$loops = 1;
}
$start = microtime(true);
$end = $start + $timeout;
for ($i = 0; $i < $loops; $i++) {
do {
// We catch the exception thrown by the step definition to execute it again.
try {
// We don't check with !== because most of the time closures will return
@@ -367,14 +358,13 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
}
}
if ($this->running_javascript()) {
if ($microsleep) {
usleep(100000);
} else {
sleep(1);
}
if (!$this->running_javascript()) {
break;
}
}
usleep(100000);
} while (microtime(true) < $end);
// Using coding_exception as is a development issue if no exception has been provided.
if (!$exception) {
+38 -15
View File
@@ -90,31 +90,54 @@ class behat_context_helper {
* @return behat_base
*/
public static function get($classname) {
if (self::$environment->hasContextClass($classname)) {
return self::$environment->getContext($classname);
$definedclassname = self::get_theme_override($classname);
if ($definedclassname) {
return self::$environment->getContext($definedclassname);
}
// Just fall back on getContext to ensure that we throw the correct exception.
return self::$environment->getContext($classname);
}
/**
* Get the context for the specified component or subsystem.
*
* @param string $component The component or subsystem to find the context for
* @return behat_base|null
*/
public static function get_component_context(string $component): ?behat_base {
$component = str_replace('core_', '', $component);
if ($classname = self::get_theme_override("behat_{$component}")) {
return self::get($classname);
}
return null;
}
/**
* Check for any theme override of the specified class name.
*
* @param string $classname
* @return string|null
*/
protected static function get_theme_override(string $classname): ?string {
$suitename = self::$environment->getSuite()->getName();
// If default suite, then get the default theme name.
if ($suitename == 'default') {
$suitename = theme_config::DEFAULT_THEME;
}
$overridencontextname = 'behat_theme_'.$suitename.'_'.$classname;
// If contexts has not been checked before and doesn't exist then just use core one.
if (!isset(self::$nonexistingcontexts[$overridencontextname])) {
try {
$subcontext = self::$environment->getContext($overridencontextname);
return $subcontext;
} catch (Behat\Behat\Context\Exception\ContextNotFoundException $e) {
// If context not found then it's not overridden.
self::$nonexistingcontexts[$overridencontextname] = 1;
}
$overrideclassname = "behat_theme_{$suitename}_{$classname}";
if (self::$environment->hasContextClass($overrideclassname)) {
return $overrideclassname;
}
// Get the actual context.
return self::$environment->getContext($classname);
if (self::$environment->hasContextClass($classname)) {
return $classname;
}
return null;
}
/**
+15 -2
View File
@@ -42,8 +42,21 @@ define('ANY_VERSION', 'any');
* Collection of components related methods.
*/
class core_component {
/** @var array list of ignored directories - watch out for auth/db exception */
protected static $ignoreddirs = array('CVS'=>true, '_vti_cnf'=>true, 'simpletest'=>true, 'db'=>true, 'yui'=>true, 'tests'=>true, 'classes'=>true, 'fonts'=>true);
/** @var array list of ignored directories in plugin type roots - watch out for auth/db exception */
protected static $ignoreddirs = [
'CVS' => true,
'_vti_cnf' => true,
'amd' => true,
'classes' => true,
'db' => true,
'fonts' => true,
'lang' => true,
'pix' => true,
'simpletest' => true,
'templates' => true,
'tests' => true,
'yui' => true,
];
/** @var array list plugin types that support subplugins, do not add more here unless absolutely necessary */
protected static $supportsubplugins = array('mod', 'editor', 'tool', 'local');
+21
View File
@@ -224,4 +224,25 @@ final class ip_utils {
}
return false;
}
/**
* Is an ip in a given list of subnets?
*
* @param string $ip - the IP to test against the list
* @param string $list - the list of IP subnets
* @param string $delim a delimiter of the list
* @return bool
*/
public static function is_ip_in_subnet_list($ip, $list, $delim = "\n") {
$list = explode($delim, $list);
foreach ($list as $line) {
$tokens = explode('#', $line);
$subnet = trim($tokens[0]);
if (address_in_subnet($ip, $subnet)) {
return true;
}
}
return false;
}
}
+11 -18
View File
@@ -331,15 +331,14 @@ class manager {
// Trigger event for sending a message or notification - we need to do this before marking as read!
self::trigger_message_events($eventdata, $savemessage);
if ($eventdata->notification or empty($CFG->messaging)) {
// If they have deselected all processors and its a notification mark it read. The user doesn't want to be bothered.
// The same goes if the messaging is completely disabled.
if ($eventdata->notification) {
$savemessage->timeread = null;
\core_message\api::mark_notification_as_read($savemessage);
} else {
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
}
if ($eventdata->notification) {
// If they have deselected all processors and it's a notification mark it read. The user doesn't want to be
// bothered.
$savemessage->timeread = null;
\core_message\api::mark_notification_as_read($savemessage);
} else if (empty($CFG->messaging)) {
// If it's a message and messaging is disabled mark it read.
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
}
return $savemessage->id;
@@ -383,15 +382,9 @@ class manager {
// Trigger event for sending a message or notification - we need to do this before marking as read!
self::trigger_message_events($eventdata, $savemessage);
if (empty($CFG->messaging)) {
// If they have deselected all processors and its a notification mark it read. The user doesn't want to be bothered.
// The same goes if the messaging is completely disabled.
if ($eventdata->notification) {
$savemessage->timeread = null;
\core_message\api::mark_notification_as_read($savemessage);
} else {
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
}
if (!$eventdata->notification && empty($CFG->messaging)) {
// If it's a message and messaging is disabled mark it read.
\core_message\api::mark_message_as_read($eventdata->userto->id, $savemessage);
}
return $savemessage->id;
+80 -1
View File
@@ -292,7 +292,27 @@ class manager {
// Set configuration.
session_name($sessionname);
session_set_cookie_params(0, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $cookiesecure, $CFG->cookiehttponly);
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
$sessionoptions = [
'lifetime' => 0,
'path' => $CFG->sessioncookiepath,
'domain' => $CFG->sessioncookiedomain,
'secure' => $cookiesecure,
'httponly' => $CFG->cookiehttponly,
];
if (self::should_use_samesite_none()) {
// If $samesite is empty, we don't want there to be any SameSite attribute.
$sessionoptions['samesite'] = 'None';
}
session_set_cookie_params($sessionoptions);
} else {
// Once PHP 7.3 becomes our minimum, drop this in favour of the alternative call to session_set_cookie_params above,
// as that does not require a hack to work with same site settings on cookies.
session_set_cookie_params(0, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $cookiesecure, $CFG->cookiehttponly);
}
ini_set('session.use_trans_sid', '0');
ini_set('session.use_only_cookies', '1');
ini_set('session.hash_function', '0'); // For now MD5 - we do not have room for sha-1 in sessions table.
@@ -452,6 +472,8 @@ class manager {
if ($timedout) {
$_SESSION['SESSION']->has_timed_out = true;
}
self::append_samesite_cookie_attribute();
}
/**
@@ -519,6 +541,61 @@ class manager {
// Setup $USER object.
self::set_user($user);
self::append_samesite_cookie_attribute();
}
/**
* Returns a valid setting for the SameSite cookie attribute.
*
* @return string The desired setting for the SameSite attribute on the cookie. Empty string indicates the SameSite attribute
* should not be set at all.
*/
private static function should_use_samesite_none(): bool {
// We only want None or no attribute at this point. When we have cookie handling compatible with Lax,
// we can look at checking a setting.
// Browser support for none is not consistent yet. There are known issues with Safari, and IE11.
// Things are stablising, however as they're not stable yet we will deal specifically with the version of chrome
// that introduces a default of lax, setting it to none for the current version of chrome (2 releases before the change).
// We also check you are using secure cookies and HTTPS because if you are not running over HTTPS
// then setting SameSite=None will cause your session cookie to be rejected.
if (\core_useragent::is_chrome() && \core_useragent::check_chrome_version('78') && is_moodle_cookie_secure()) {
return true;
}
return false;
}
/**
* Conditionally append the SameSite attribute to the session cookie if necessary.
*
* Contains a hack for versions of PHP lower than 7.3 as there is no API built into PHP cookie API
* for adding the SameSite setting.
*
* This won't change the Set-Cookie headers if:
* - PHP 7.3 or higher is being used. That already adds the SameSite attribute without any hacks.
* - If the samesite setting is empty.
* - If the samesite setting is None but the browser is not compatible with that setting.
*/
private static function append_samesite_cookie_attribute() {
if (version_compare(PHP_VERSION, '7.3.0', '>=')) {
// This hack is only necessary if we weren't able to set the samesite flag via the session_set_cookie_params API.
return;
}
if (!self::should_use_samesite_none()) {
return;
}
$cookies = headers_list();
header_remove('Set-Cookie');
$setcookiesession = 'Set-Cookie: ' . session_name() . '=';
foreach ($cookies as $cookie) {
if (strpos($cookie, $setcookiesession) === 0) {
$cookie .= '; SameSite=None';
}
header($cookie, false);
}
}
/**
@@ -555,6 +632,8 @@ class manager {
self::add_session_record($_SESSION['USER']->id); // Do not use $USER here because it may not be set up yet.
session_write_close();
self::$sessionactive = false;
self::append_samesite_cookie_attribute();
}
/**
+4 -1
View File
@@ -163,6 +163,9 @@ class database_logger implements task_logger {
return;
}
$DB->delete_records_list('task_log', 'id', $logids);
$chunks = array_chunk($logids, 1000);
foreach ($chunks as $chunk) {
$DB->delete_records_list('task_log', 'id', $chunk);
}
}
}
+1 -1
View File
@@ -68,7 +68,7 @@ class file_temp_cleanup_task extends scheduled_task {
// Now loop through again and remove old files and directories.
for ($iter->rewind(); $iter->valid(); $iter->next()) {
$node = $iter->getRealPath();
if (!is_readable($node)) {
if (!isset($modifieddateobject[$node]) || !is_readable($node)) {
continue;
}

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