Compare commits

..

395 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 940aa17049 Moodle release 3.6.10 2020-05-09 20:05:30 +02:00
Eloy Lafuente (stronk7) 536c360cd3 weekly release 3.6.9+ 2020-05-08 13:29:51 +02:00
Eloy Lafuente (stronk7) 419173f859 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-05-08 13:29:49 +02:00
Paul Holden 3c31f748f1 MDL-68410 mod_scorm: safer status operator comparison. 2020-05-07 09:03:46 +08:00
AMOS bot b0fc844ba2 Automatically generated installer lang files 2020-05-06 00:13:29 +00:00
Ferran Recio 3a692f8080 MDL-68430 filter_mathjaxloader: update default CDN to 2.7.8 2020-05-05 16:16:48 +02:00
AMOS bot c15e459968 Automatically generated installer lang files 2020-05-05 00:11:48 +00:00
AMOS bot db39006c44 Automatically generated installer lang files 2020-04-30 00:12:11 +00:00
AMOS bot 7c74cd3910 Automatically generated installer lang files 2020-04-27 00:11:44 +00:00
AMOS bot d09e145e84 Automatically generated installer lang files 2020-04-23 00:14:51 +00:00
AMOS bot 642ce70984 Automatically generated installer lang files 2020-04-19 00:13:33 +00:00
Eloy Lafuente (stronk7) 6e1442bfa7 weekly release 3.6.9+ 2020-04-16 19:34:10 +02:00
Eloy Lafuente (stronk7) d523a66834 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-04-16 19:34:04 +02:00
AMOS bot d530cd12b3 Automatically generated installer lang files 2020-04-11 00:12:09 +00:00
AMOS bot 949e0caf94 Automatically generated installer lang files 2020-04-11 00:12:09 +00:00
Eloy Lafuente (stronk7) 98c0290a13 Merge branch 'MDL-67919-36' of git://github.com/sarjona/moodle into MOODLE_36_STABLE 2020-04-10 12:00:38 +02:00
Eloy Lafuente (stronk7) 35f84c0e43 Merge branch 'MDL-67910-36' of git://github.com/sarjona/moodle into MOODLE_36_STABLE 2020-04-10 11:47:35 +02:00
AMOS bot 612ba453d0 Automatically generated installer lang files 2020-04-08 00:11:27 +00:00
AMOS bot 45e68195b9 Automatically generated installer lang files 2020-04-08 00:11:26 +00:00
Sara Arjona e9018ca76a MDL-67919 dataprivacy: Fix behat error when contacting DPO 2020-04-03 19:49:32 +02:00
Sara Arjona 8d0e2cb079 weekly release 3.6.9+ 2020-04-02 16:51:29 +02:00
Sara Arjona 1cb6257bab Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-04-02 16:51:26 +02:00
Sara Arjona 3820d5d2be Merge branch 'MDL-66245-36' of git://github.com/junpataleta/moodle into MOODLE_36_STABLE 2020-03-31 15:09:42 +02:00
Sara Arjona 7d47ced769 MDL-67910 behat: PendingJS improvements for deleteevent modal 2020-03-31 08:46:25 +02:00
AMOS bot ea9d2e6050 Automatically generated installer lang files 2020-03-29 00:12:00 +00:00
AMOS bot a01c6de010 Automatically generated installer lang files 2020-03-28 00:11:54 +00:00
AMOS bot 020b7dcb49 Automatically generated installer lang files 2020-03-24 00:11:19 +00:00
AMOS bot d74e8be2b5 Automatically generated installer lang files 2020-03-23 00:12:26 +00:00
Victor Deniz Falcon 28944a18db weekly release 3.6.9+ 2020-03-12 14:22:42 +00:00
Victor Deniz Falcon d866e7315b Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-03-12 14:22:37 +00:00
Eloy Lafuente (stronk7) 217767bb7f Merge branch 'MDL-68125-regression-MOODLE_36_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_36_STABLE 2020-03-12 01:20:02 +01:00
Brendan Heywood 7ac5548953 MDL-68125 core: Fixed $CFG->reverseproxyignore install regression 2020-03-12 09:55:02 +11:00
Eloy Lafuente (stronk7) 77d95a2ccb Merge branch 'MDL-67827-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2020-03-09 20:36:38 +01:00
Andrew Nicols 025a00781e MDL-67827 behat: Pending JS improvements for dialogues 2020-03-09 08:31:21 +08:00
Andrew Nicols c7489c6d4d MDL-67827 behat: Add missing exception use 2020-03-09 08:31:21 +08:00
AMOS bot fe0a150658 Automatically generated installer lang files 2020-03-09 00:12:09 +00:00
Sara Arjona bed733c86d Moodle release 3.6.9 2020-03-06 12:34:20 +01:00
AMOS bot c2d4052ffc Automatically generated installer lang files 2020-03-06 00:11:07 +00:00
Sara Arjona eac204a06d weekly release 3.6.8+ 2020-03-05 17:31:46 +01:00
Sara Arjona c270851b98 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-03-05 17:31:44 +01:00
Michael Hawkins f5e4c44183 MDL-67861 core: Fix getremoteaddr unit test to match new proxy setup 2020-03-05 14:41:17 +08:00
Brendan Heywood b4241111de 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:10:19 +01:00
Brendan Heywood c0c1997a6d MDL-67861 libraries: Refactor is_ip_in_subnet_list in ip_utils 2020-03-05 01:09:22 +01:00
Brendan Heywood 063d798f37 MDL-67861 admin: Default $CFG->getremoteaddrconf to only use REMOTE_ADDR 2020-03-05 01:09:21 +01:00
Brendan Heywood 52d5599ff2 MDL-67861 core: Use last ip in X-Forwarded-For list 2020-03-05 01:09:21 +01:00
Marina Glancy e972cd3ef3 MDL-56287 gradereport_history: Separate groups queries improved 2020-03-04 11:47:45 +01:00
Jun Pataleta b949f7ae45 MDL-56287 gradereport_history: Show users from groups that can be viewed 2020-03-04 11:47:45 +01:00
AMOS bot 95f07d4a29 Automatically generated installer lang files 2020-03-04 00:11:26 +00:00
AMOS bot 2efa7007da Automatically generated installer lang files 2020-02-16 00:11:25 +00:00
Sara Arjona 0d31f8cf80 weekly release 3.6.8+ 2020-02-14 12:12:23 +01:00
Sara Arjona 8ede6eb071 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-02-14 12:12:21 +01:00
Jun Pataleta 89ee8b5544 Merge branch 'MDL-67965-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2020-02-14 13:24:55 +08:00
Andrew Nicols 889ced5063 MDL-67965 behat: Get theme-specific context classes correctly 2020-02-14 11:36:21 +08:00
Jun Pataleta bd642555ce MDL-66245 privacy: Encode each part of the data URL instead of the whole 2020-02-10 16:57:30 +08:00
AMOS bot a014760344 Automatically generated installer lang files 2020-02-08 00:12:11 +00:00
Sara Arjona faf358bfe0 weekly release 3.6.8+ 2020-02-07 09:45:06 +01:00
Sara Arjona 6e2580ca50 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-02-07 09:45:04 +01:00
Brendan Heywood 4aaf81b43d MDL-67726 tool_phpunit: add missing input escaping 2020-02-06 19:46:04 +01:00
Andrew Nicols 8e6ccd11b1 Merge branch 'MDL-67175-36' of git://github.com/ferranrecio/moodle into MOODLE_36_STABLE 2020-02-06 10:22:07 +08:00
Ferran Recio 5d9da95fc8 MDL-67175 mod_scorm: fixing js eslint errors 2020-02-04 12:37:31 +01:00
Sam Hemelryk 9525024349 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 58f86af654 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
AMOS bot 7459866078 Automatically generated installer lang files 2020-02-04 00:11:30 +00:00
Eloy Lafuente (stronk7) c122a4abc7 weekly release 3.6.8+ 2020-01-30 16:11:13 +01:00
Eloy Lafuente (stronk7) 368b66502a Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-01-30 16:11:10 +01:00
Eloy Lafuente (stronk7) a9cfe079a3 Merge branch 'MDL-67722-36' of git://github.com/mickhawkins/moodle into MOODLE_36_STABLE 2020-01-28 20:14:06 +01:00
AMOS bot 6c7657a8f2 Automatically generated installer lang files 2020-01-28 00:11:56 +00:00
Adrian Greeve 9fc24562b5 Merge branch 'MDL-67691_36' of https://github.com/stronk7/moodle into MOODLE_36_STABLE 2020-01-28 07:55:34 +08:00
AMOS bot e3bd76b13e Automatically generated installer lang files 2020-01-25 00:11:58 +00:00
Adrian Greeve a470b60534 weekly release 3.6.8+ 2020-01-24 10:17:14 +08:00
Adrian Greeve 99fae65ea3 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-01-24 10:17:05 +08:00
Adrian Greeve 4deccac46a Merge branch 'MDL-67656-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2020-01-22 09:48:08 +08:00
Michael Hawkins 453d4d1846 MDL-67722 mod_forum: Reduce wait time on time limit expires behat test 2020-01-21 11:40:28 +08:00
Eloy Lafuente (stronk7) 0a4e899e01 Merge branch 'MDL-67724-36' of git://github.com/junpataleta/moodle into MOODLE_36_STABLE 2020-01-20 10:53:52 +01:00
Eloy Lafuente (stronk7) 10dee69379 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:14:39 +01:00
AMOS bot ed10e934d3 Automatically generated installer lang files 2020-01-18 00:11:03 +00:00
Jun Pataleta 153e4369e1 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:51:23 +08:00
AMOS bot 5c9b17c5f1 Automatically generated installer lang files 2020-01-17 00:12:35 +00:00
AMOS bot dd353c7247 Automatically generated installer lang files 2020-01-14 00:10:38 +00:00
Andrew Nicols b41a56380e MDL-67656 behat: Removed nested spin 2020-01-10 14:36:02 +08:00
Andrew Nicols f3a5e2a31a MDL-67656 behat: Fix usleep call in spin 2020-01-10 14:36:02 +08:00
Andrew Nicols e05d1c34cd Moodle release 3.6.8 2020-01-10 13:03:34 +08:00
Andrew Nicols fd43070bbc Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-01-10 13:03:32 +08:00
AMOS bot dd8fa044d9 Automatically generated installer lang files 2020-01-10 00:12:29 +00:00
Sara Arjona 57f962a915 weekly release 3.6.7+ 2020-01-09 15:43:01 +01:00
Eloy Lafuente (stronk7) 050ab7d479 Merge branch 'MDL-67469-36' of git://github.com/junpataleta/moodle into MOODLE_36_STABLE 2020-01-07 23:00:17 +01:00
Jake Dallimore d20bd99b07 weekly release 3.6.7+ 2020-01-03 11:25:14 +08:00
Jake Dallimore 8ac197d07f Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2020-01-03 11:25:12 +08:00
AMOS bot 593b942437 Automatically generated installer lang files 2020-01-03 00:12:25 +00:00
Adrian Greeve 25dcb6f193 Merge branch 'MDL-67599-36' of https://github.com/snake/moodle into MOODLE_36_STABLE 2020-01-02 15:18:37 +08:00
Jake Dallimore 98f33548d4 MDL-67599 behat: fix behat tests assuming Jan 2020 is a future date 2020-01-02 13:53:19 +08:00
AMOS bot feff218f2f Automatically generated installer lang files 2020-01-02 00:10:37 +00:00
Jake Dallimore 668cba6e7e MDL-67593 core_iplookup: update lang string describing download process
Let users know they need to register on maxmind before granted download
access.
2020-01-01 20:53:48 +01:00
Jake Dallimore 2bc8f72dff MDL-67593 core_iplookup: use MaxMind test database in unit tests
Instead of downloading a live database (now not available publicly)
use a local test database.
2020-01-01 20:52:33 +01:00
Jun Pataleta 4d504d86b7 Merge branch 'MDL-63996-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-12-31 15:18:49 +08:00
Adrian Greeve 10e40f0366 Merge branch 'MDL-65809-36-onlyenv' of git://github.com/sarjona/moodle into MOODLE_36_STABLE 2019-12-24 14:57:21 +08:00
AMOS bot 53bc7655aa Automatically generated installer lang files 2019-12-21 00:11:13 +00:00
Andrew Nicols 1c127290cf MDL-63996 core/tags: Pending JS for all tag code 2019-12-18 12:02:40 +08:00
Andrew Nicols dd8f4b46d4 MDL-63996 behat: Fix multi-tag autocomplete usage 2019-12-18 10:25:52 +08:00
AMOS bot 920fb333c0 Automatically generated installer lang files 2019-12-14 00:11:08 +00:00
Jun Pataleta 4c24a03e08 MDL-67469 tool_dataprivacy: Put back missing test code
This patch simply brings back the missing test code for
\tool_dataprivacy_api_testcase::test_approve_data_request_non_dpo_user()
2019-12-13 10:04:59 +08:00
AMOS bot 2c0c7e5e71 Automatically generated installer lang files 2019-12-13 00:11:25 +00:00
AMOS bot 26a05fb33f Automatically generated installer lang files 2019-12-11 13:50:23 +00:00
AMOS bot 6f7aea5351 Automatically generated installer lang files 2019-12-06 00:09:57 +00:00
Sara Arjona c66e551c11 MDL-65809 environment: mbstring extension required 2019-12-05 14:02:07 +01:00
Sara Arjona 526fbf8a47 MDL-65809 environment: PHP 7.2 required 2019-12-05 14:02:07 +01:00
Sara Arjona 64d99256ef MDL-65809 environment: postgres requirement up to 9.5 2019-12-05 14:02:07 +01:00
Sara Arjona 8b39496a87 MDL-65809 environment: mariadb requirement up to 10.2 2019-12-05 14:02:07 +01:00
Sara Arjona 577b37cb2c MDL-65809 environment: 3.5 (LTS) required 2019-12-05 14:02:07 +01:00
Sara Arjona 205201f7b3 MDL-65809 environment: 3.9 base information
This is a direct copy of the 3.8 branch to have changes
under control easier in next commits.
2019-12-05 14:02:07 +01:00
Eloy Lafuente (stronk7) 08c86b9e9b weekly release 3.6.7+ 2019-11-22 00:17:05 +01:00
Andrew Nicols 3aa4bf022a Merge branch 'MDL-48024_36' of https://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-11-21 19:46:37 +08:00
Eloy Lafuente (stronk7) 1f2d7d154a MDL-48024 quiz: return void is only php >= 71
this branch supports php 70, so taking rid of it
2019-11-21 12:31:43 +01:00
Tim Hunt 5884f9a07b MDL-48024 behat: allow plugins to have data generators
This extends the step
Given the following "users" exist:
to also support things like
Given the following "mod_quiz > user overrides" exist:

Instructions are on the behat_data_generators and
behat_generator_base classes.
2019-11-21 09:37:08 +08:00
Eloy Lafuente (stronk7) 27d0c2181b Moodle release 3.6.7 2019-11-09 11:57:42 +01:00
Sara Arjona c6b6921b4e weekly release 3.6.6+ 2019-11-08 15:39:41 +01:00
Sara Arjona 1328297d48 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-11-08 15:39:38 +01:00
Adrian Greeve b5c18dedf0 Merge branch 'MDL-67169_36' of https://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-11-08 10:45:30 +08:00
Jake Dallimore 4c9c8e00db Merge branch 'MDL-67016-36-user-profile-see-own-courses' of https://github.com/danowar2k/moodle into MOODLE_36_STABLE 2019-11-08 10:22:58 +08:00
Sara Arjona 0c79de9112 Merge branch 'MDL-66683-36' of git://github.com/cescobedo/moodle into MOODLE_36_STABLE 2019-11-07 17:41:43 +01:00
cescobedo 829c7c9a1b MDL-66683 core: Revert MDL-66181 because created regressions
This reverts commit ed080a580f.
This issue reverts the behaviour modified in MDL-66181, as that change
negatively impacted course-creation workflows. As this appears to be
the intended functionality, the Security team has agreed to revert
this change.
2019-11-07 17:31:04 +01:00
Jake Dallimore abd981c6a7 MDL-66257 tool_cohortroles: unit test for users in multiple cohorts 2019-11-07 23:48:34 +08:00
cescobedo 4d10388df2 MDL-66257 tool_cohortroles: Unassign the role on removal cohortroles. 2019-11-07 23:48:34 +08:00
Eloy Lafuente (stronk7) d89e40d7d6 MDL-67169 phpunit: fix clear flaw in unit test provider
Basically the provider is ignoring the CRLF to LF normalization
results and loading the original file again.

This doesn't have any impact normally, because all moodle
files are LF ones and people using other systems have their
git configurations set to work that way (not modify or force LF).

But there may be checkouts out there (for example travis) where
the git configuration by defult is to convert to the OS, causing
windows runs to fail badly there. See the issue for more info
and links.
2019-11-07 13:43:30 +01:00
Jun Pataleta 3efab60a57 Merge branch 'MDL-67084-36' of git://github.com/junpataleta/moodle into MOODLE_36_STABLE 2019-11-07 19:37:40 +08:00
Marina Glancy 1d7543be8c MDL-67084 core_form: duration element should export arrays 2019-11-07 19:22:15 +08:00
Jun Pataleta 116d8541d2 MDL-66598 auth_oauth2: OAuth2 upgrade step
This basically does two things:
1. Updates all non-Facebook/Google/Microsoft issuers and sets their
'requireconfirmation' field to 1 so that future OAuth2 logins on these
issuers will always have an email confirmation sent to them.
2. Deletes the linked logins of users with non-Facebook/Google/Microsoft
OAuth2 issuers.
2019-11-07 18:44:43 +08:00
Jun Pataleta 78d51b1fc6 MDL-66598 auth_oauth2: Add warning messages in confirm emails 2019-11-07 18:44:43 +08:00
Jun Pataleta fd753889a2 MDL-66598 tool_oauth2: Make account confirmation required by default
* Only Facebook, Google, and Microsoft issuers can optionally offer to
require account confirmation via email. We will require email
confirmation for the rest of the issuers.
2019-11-07 18:44:43 +08:00
Eloy Lafuente (stronk7) f6822347de Merge branch 'MDL-42638-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-11-06 22:47:41 +01:00
Sara Arjona dcd13e2b08 Merge branch 'MDL-66984-change_password_url-with-user-MOODLE_36_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_36_STABLE 2019-11-06 08:31:01 +01:00
Michael Hawkins 1137b7d072 MDL-66161 output: Escaping fatal error message and URL strings 2019-11-06 01:26:37 +01:00
Juan Leyva c7a5fc2f35 MDL-66377 user: Only allow active users to retrieve files via tokenpluginfile.php 2019-11-06 01:26:37 +01:00
Paul Holden 167a8dc276 MDL-66228 mod_lesson: ensure return URL parameters are always local. 2019-11-06 01:26:37 +01:00
AMOS bot bf569af16b Automatically generated installer lang files 2019-11-06 00:16:42 +00:00
Adrian Greeve 7c34492487 Merge branch 'MDL-67136-36' of git://github.com/mihailges/moodle into MOODLE_36_STABLE 2019-11-06 08:16:41 +08:00
Luca Bösch 9d1ded28c2 MDL-42638 filters: Have emoticons respect <pre>. 2019-11-05 16:09:04 +01:00
Eloy Lafuente (stronk7) a9749a86b8 weekly release 3.6.6+ 2019-11-05 13:34:23 +01:00
Eloy Lafuente (stronk7) 030b9db219 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-11-05 13:34:21 +01:00
Mihail Geshoski 3cbb18b105 MDL-67136 mod_assign: Fix expand/collapse text submission in clean 2019-11-05 13:28:14 +08:00
Jake Dallimore b50f1289b6 Merge branch 'MDL-66455-36' of git://github.com/lameze/moodle into MOODLE_36_STABLE 2019-11-05 11:43:31 +08:00
AMOS bot 23c4e59166 Automatically generated installer lang files 2019-11-05 00:10:35 +00:00
Brendan Heywood ddc5472056 MDL-66984 auth: Allow $USER to be used in change_password_url 2019-11-05 10:32:47 +11:00
Jun Pataleta 3139dba346 Merge branch 'MDL-66582-36' of git://github.com/jleyva/moodle into MOODLE_36_STABLE 2019-11-04 19:35:11 +08:00
Juan Leyva 768057b4db MDL-66582 tool_mobile: Clean URLs from auth plugins
In order to avoid the WebService to break we must double check that URLs coming from auth plugins are valid.
2019-11-04 10:21:19 +01:00
Johan Dobbelstein e91e315d19 MDL-66582 auth: Fix empty auth_logo in Shibboleth auth plugins
* set $idp['iconurl'] = null if no auth_logo
* lib/templates/loginform.mustache will skip NULL iconurls
* lib/ajax/service?info=tool_mobile_get_public_config will validate the NULL values
2019-11-04 10:13:48 +01:00
Jake Dallimore c8238b4d45 Merge branch 'MDL-67093-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-11-04 15:41:32 +08:00
Jake Dallimore dcb601fede Merge branch 'MDL-67009_36' of https://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-11-04 14:56:35 +08:00
Adrian Greeve 1fc5f07ed3 Merge branch 'MDL-43189-36' of git://github.com/snake/moodle into MOODLE_36_STABLE 2019-11-04 09:25:17 +08:00
Eloy Lafuente (stronk7) 1652dfe456 Merge branch 'MDL-66990-36-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_36_STABLE 2019-11-03 23:15:29 +01:00
AMOS bot 3a4b7e8995 Automatically generated installer lang files 2019-11-02 00:09:38 +00:00
Helen Foster 716143b33c MDL-66990 lang: Import fixed English strings (en_fix)
Significant string changes:

* configenablecompletion,core_completion - including reason for setting
  activity completion conditions
* setuplink_desc,tool_mobile - including where the app download page
  link is displayed and leaving the setting empty
2019-11-01 11:28:31 +01:00
Shamim Rezaie 74ac275d08 MDL-43189 core: improve validating db settings during cli install 2019-11-01 15:39:55 +08:00
Shamim Rezaie 7a902dea3a MDL-43189 core: Validate db prefix during installation 2019-11-01 15:39:55 +08:00
Daniel Poggenpohl 88b7f71a50 MDL-67016 profile: current user should see his own courses 2019-10-31 14:40:53 +01:00
Eloy Lafuente (stronk7) a78ed9eed1 weekly release 3.6.6+ 2019-10-31 13:33:12 +01:00
Simey Lameze b4f299ec91 MDL-66455 calendar: add coverage for event types in subscription page 2019-10-31 18:48:15 +08:00
Simey Lameze 74d9dbf696 MDL-66455 calendar: show site level subscriptions 2019-10-31 18:48:15 +08:00
Adrian Greeve 567fa6adc3 Merge branch 'MDL-66247-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-10-31 14:41:10 +08:00
Andrew Nicols 4c3a2ea83c MDL-67093 grading: Fetch cm with get_fast_modinfo 2019-10-31 13:29:00 +08:00
Andrew Nicols c3cad10fcf Merge branch 'MDL-67088-36' of git://github.com/marinaglancy/moodle into MOODLE_36_STABLE 2019-10-31 11:08:34 +08:00
Marina Glancy e6993ed682 MDL-67088 mod_assign: compare time without case for MacOS compat 2019-10-30 19:21:43 +01:00
Andrew Nicols ac2b9ee95c MDL-66247 accessibility: Correct notification alert role support 2019-10-30 09:01:18 +08:00
Eloy Lafuente (stronk7) 55749ae39f weekly release 3.6.6+ 2019-10-29 21:01:40 +01:00
Eloy Lafuente (stronk7) d56954a828 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-10-29 21:01:33 +01:00
Jake Dallimore 4eb1e079b3 Merge branch 'MDL-66945_36' of git://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-10-29 14:56:35 +08:00
Andrew Nicols d673f8abd7 Merge branch 'MDL-67027-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-10-29 09:36:07 +08:00
Andrew Nicols 398dde36b3 MDL-66945 composer: Update behat extension
(using php70 for this branch)

This uses a new version of the moodlehq-behat-extension which ensures
that a node is visible and in the view port before it is clicked on.

This resolves an issue with Firefox on Ubuntu 18.04 whereby the node is
only brought into the viewport instead of clicked on.
2019-10-28 13:40:23 +01:00
Jun Pataleta c92e401361 Merge branch 'm36_MDL-65811_Fix_Incorrect_ORDER_BY_Search' of https://github.com/scara/moodle into MOODLE_36_STABLE 2019-10-28 11:30:24 +08:00
AMOS bot ebb4054cd6 Automatically generated installer lang files 2019-10-28 00:09:26 +00:00
AMOS bot 7a68e34f61 Automatically generated installer lang files 2019-10-27 00:09:23 +00:00
Matteo Scaramuccia 9c82b32001 MDL-65811 database: Fix subsetting in MSSQL 2019-10-25 23:06:58 +02:00
Paul Holden 99c79db0c7 MDL-67027 calendar: fix event update form validation. 2019-10-25 17:36:47 +01:00
Eloy Lafuente (stronk7) 3f26d44a6f weekly release 3.6.6+ 2019-10-25 15:29:37 +02:00
Eloy Lafuente (stronk7) 48878c24fd Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-10-25 15:29:34 +02:00
Jake Dallimore 8dd23a1375 Merge branch 'MOODLE_36_MDL-66973' of https://github.com/golenkovm/moodle into MOODLE_36_STABLE 2019-10-25 11:10:42 +08:00
Jun Pataleta d1bd09fa41 Merge branch 'MDL-66543-36' of github.com:junpataleta/moodle into MOODLE_36_STABLE 2019-10-24 23:17:08 +08:00
Jun Pataleta db88f1f307 MDL-66543 core_form: Fix illegal whitespace 2019-10-24 23:14:47 +08:00
Jun Pataleta 03f1265690 Merge branch 'MDL-66543-36' of git://github.com/tobiasreischmann/moodle into MOODLE_36_STABLE 2019-10-24 23:08:29 +08:00
Tobias Reischmann 8fd70353e6 MDL-66543 forms: Make (hard) frozen textareas readonly (or disabled) 2019-10-24 13:43:07 +02:00
Eloy Lafuente (stronk7) 9d57a8057f Merge branch 'MDL-67001-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-10-24 13:27:54 +02:00
Eloy Lafuente (stronk7) 1f77d72592 MDL-67009 behat: get rid of invalid void type hinting for php70 2019-10-24 10:48:12 +02:00
Eloy Lafuente (stronk7) e2442de0b6 Merge branch 'MDL-66935-lock-clashes-MOODLE_36_STABLE' of https://github.com/brendanheywood/moodle into MOODLE_36_STABLE 2019-10-24 10:03:55 +02:00
Adrian Greeve 5d5d2e6e42 Merge branch 'MDL-66876-36' of git://github.com/jleyva/moodle into MOODLE_36_STABLE 2019-10-24 15:17:25 +08:00
Luca Bösch 4112274408 MDL-67001 question: alignment and form spaces. 2019-10-24 07:59:24 +02:00
Brendan Heywood 1aabe01886 MDL-66935 core_lock: Fix resource key clashes in db and postgres locks 2019-10-24 15:07:49 +11:00
AMOS bot 734a176cf0 Automatically generated installer lang files 2019-10-24 00:09:34 +00:00
Eloy Lafuente (stronk7) d1d8f42cde Merge branch 'MDL-64298-36' of git://github.com/jleyva/moodle into MOODLE_36_STABLE 2019-10-23 22:22:00 +02:00
Eloy Lafuente (stronk7) 0123b42676 Merge branch 'MDL-67001-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-10-23 22:17:48 +02:00
Juan Leyva cb63696054 MDL-64298 gradereport_user: Fix WS returned parameter description
feedbackformat must be optional always
2019-10-23 17:16:30 +02:00
Juan Leyva a3bc3ce5b6 MDL-66876 core_filter: Fix context in Web Service warning 2019-10-23 17:07:47 +02:00
Luca Bösch d029483cde MDL-67001 question: alignment and form spaces. 2019-10-23 11:08:50 +02:00
Adrian Greeve 19115e20a7 Merge branch 'MDL-63125-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-10-23 11:10:31 +08:00
Sara Arjona 8cda42019a weekly release 3.6.6+ 2019-10-22 14:48:02 +02:00
Sara Arjona 4aca40f697 Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-10-22 14:47:59 +02:00
Mikhail Golenkov 84a8b1b2df MDL-66973 search: Reset Content writer after test. 2019-10-22 09:43:15 +11:00
Paul Holden 880dcd0f94 MDL-63125 forms: Behat test for form autocomplete element. 2019-10-21 23:25:21 +01:00
Eloy Lafuente (stronk7) 269bb26b3c Merge branch 'MDL-66980_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-21 20:27:03 +02:00
Sara Arjona 7d87eef1fc Merge branch 'MDL-61121-36-5' of git://github.com/mihailges/moodle into MOODLE_36_STABLE 2019-10-21 14:46:42 +02:00
Tim Hunt de672b1357 MDL-66980 question bank: fix load_many_for_cache missing record check 2019-10-21 11:19:06 +01:00
Jun Pataleta f48f788115 Merge branch 'MDL-66009-36' of https://github.com/grabs/moodle into MOODLE_36_STABLE 2019-10-21 16:15:07 +08:00
Jake Dallimore a0a3400c59 Merge branch 'MDL-66915-36' of https://github.com/MartinGauk/moodle into MOODLE_36_STABLE 2019-10-21 15:56:50 +08:00
Andrew Nicols 49592cea31 Merge branch 'MDL-66962-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-10-21 14:24:10 +08:00
Luca Bösch b4bc353659 MDL-66962 questions: Question bank table T title non breaking. 2019-10-21 08:17:45 +02:00
Andrew Nicols f074a0ee86 Merge branch 'MDL-66944_36' of https://github.com/t-schroeder/moodle into MOODLE_36_STABLE 2019-10-21 13:49:12 +08:00
Andrew Nicols 9c2abf9a02 Merge branch 'MDL-66946_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-21 13:08:34 +08:00
Jake Dallimore 17d08f6cc5 Merge branch 'MDL-66930-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-10-21 11:56:10 +08:00
Jake Dallimore 85fec2dfe4 Merge branch 'MDL-66960-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-10-21 10:42:12 +08:00
AMOS bot cd99faeb67 Automatically generated installer lang files 2019-10-19 00:09:27 +00:00
Tim Schroeder 9e0c4e13d7 MDL-66944 course: fixed copy-paste-error in comment 2019-10-19 00:06:58 +02:00
Tim Hunt ee2c305e37 MDL-66946 quiz reports: incorrectly show teachers sometimes 2019-10-18 17:43:23 +01:00
Luca Bösch 4a3222dc50 MDL-66960 questions: Top align all question bank titles exc "select all" 2019-10-18 16:35:30 +02:00
Luca Bösch 0abefe1f2b MDL-66930 quiz: Question type icon size and alignment in Boost. 2019-10-18 13:51:39 +02:00
Eloy Lafuente (stronk7) caa6f445e4 weekly release 3.6.6+ 2019-10-18 10:31:24 +02:00
Mihail Geshoski 907312d17a MDL-61121 assign: Declare variables in the local scope 2019-10-18 14:00:55 +08:00
Mihail Geshoski 14b13ec478 MDL-61121 assign: Improve accessibility in quick grading page tables 2019-10-18 14:00:55 +08:00
Mihail Geshoski 9e687b46e9 MDL-61121 assign: Improve accessibility - view full/view summary control 2019-10-18 14:00:55 +08:00
Jun Pataleta 5cd189b68d Merge branch 'MDL-66806_36' of git://github.com/dmonllao/moodle into MOODLE_36_STABLE 2019-10-18 09:34:24 +08:00
Andrew Nicols 5a774101e0 Merge branch 'MDL-66919_36' of https://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-10-18 08:28:26 +08:00
Eloy Lafuente (stronk7) 6019d849b2 Merge branch 'MDL-64064-m36' of https://github.com/NeillM/moodle into MOODLE_36_STABLE 2019-10-17 23:09:24 +02:00
Andreas Grabs 3b1d619baf MDL-66009 mod_feedback: Nested dependency fails again 2019-10-17 09:19:43 +02:00
Eloy Lafuente (stronk7) 9eb88d21ba MDL-66919 behat: fix typo in error message
Also fix a couple of phpdocs that were incorrect.
2019-10-16 00:49:13 +02:00
Eloy Lafuente (stronk7) f2d10a9bb9 weekly release 3.6.6+ 2019-10-15 22:59:53 +02:00
Martin Gauk 580d8124c0 MDL-66915 assign: Notify only if grade was updated in past 24 hours
Send notifications only if a grade was updated in the past 24 hours,
whether marking workflow is enabled or not.
2019-10-15 15:55:06 +02:00
Tim Hunt af46f59162 MDL-66796 question bank: fix more bugs with category editing 2019-10-15 11:23:20 +08:00
Jun Pataleta e194ef059f Merge branch 'MDL-66821_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-15 07:36:31 +08:00
Andrew Nicols a9be3e27e3 Merge branch 'MDL-66335_36' of https://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-10-15 07:31:42 +08:00
Eloy Lafuente (stronk7) 0f9ed5c5e0 MDL-66335 behat: Avoid double processing the page type
resolve_page_instance_helper() already processes the type, returning
the correct context that should be processing the navigation URL.

With that extra call to parse_page_name() the 2nd call always returns
"core", ultimately leading to tons of behat failures because "core" is
not aware of those (plugin, quiz for now) pages typology.
2019-10-15 00:04:11 +02:00
Eloy Lafuente (stronk7) 989faa4667 Merge branch 'MDL-66335_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-14 18:56:50 +02:00
Paul Holden 45d210a442 MDL-63125 forms: allow item removal from single-select autocomplete. 2019-10-14 17:07:46 +01:00
Eloy Lafuente (stronk7) d0577075b6 Merge branch 'MDL-66559-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-10-14 16:41:05 +02:00
Tim Hunt 96e9075ac9 MDL-66335 quiz behat: using the new generic navigation steps
This converts all the navigation to quiz pages when that is not
the thing under test. Also, I decided that the Quiz settings form
belonged to the course, so did not do that here.
2019-10-14 13:14:45 +01:00
Tim Hunt d714e336b6 MDL-66335 behat: new step to log in and go straight to a particular page
I did not think thought through if this new URL parameter would be a
potential security hole. The simple cop-out option is to make it only
work on Behat sites for now.
2019-10-14 13:14:41 +01:00
Tim Hunt 10bf14282c MDL-66335 behat: generic step for navigating direct to specific pages 2019-10-14 13:13:32 +01:00
Tim Hunt fa963675f4 MDL-66821 question behat: new step for acting on questions in the bank
There is a proposed change MDL-66816 which will change the question
bank UI. This will break any Behat tests which uses low-level steps
like

    When I click on "Duplicate" "link" in the "Test question" "table_row"

to perform an action on a question in the question bank. This commit
introduces a new step:

    When I choose "Duplicate" action for "Test question" in the question bank

This commit also converts all core Behat tests to use the new step.
2019-10-14 12:00:03 +01:00
Sara Arjona 7511cf3462 Merge branch 'MDL-66836-m36' of https://github.com/sammarshallou/moodle into MOODLE_36_STABLE 2019-10-14 12:27:23 +02:00
Jake Dallimore 78be4e8724 Merge branch 'MDL-66659-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-10-14 15:34:32 +08:00
Andrew Nicols 86a58a82d8 MDL-66559 behat: Register component selectors earlier 2019-10-14 14:24:05 +08:00
Andrew Nicols 17342a4ff3 MDL-66559 behat: Update running suite 2019-10-14 14:17:47 +08:00
Jun Pataleta 3e50a250e9 Merge branch 'MDL-66796-36-fix' of https://github.com/snake/moodle into MOODLE_36_STABLE 2019-10-14 13:48:16 +08:00
Jake Dallimore 0143e8bcf4 MDL-66796 mod_quiz: only update the id number if changed
If the idnumber is present in the DB, it's set to null. In this case,
don't update the value.
2019-10-14 13:41:40 +08:00
Jake Dallimore 21ee8ef703 Merge branch 'MDL-66559-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-10-14 11:10:35 +08:00
Jake Dallimore 77ccb0f467 Merge branch 'MDL-66796_36' of git://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-14 07:42:10 +08:00
Eloy Lafuente (stronk7) d12b2d9822 Merge branch 'MDL-66851-36' of git://github.com/mihailges/moodle into MOODLE_36_STABLE 2019-10-13 16:51:27 +02:00
Eloy Lafuente (stronk7) 6a81c53788 Merge branch 'MDL-65243-36' of git://github.com/mihailges/moodle into MOODLE_36_STABLE 2019-10-13 16:31:37 +02:00
Eloy Lafuente (stronk7) e2a4284326 Merge branch 'MDL-66779-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-10-13 02:13:27 +02:00
Eloy Lafuente (stronk7) ed9c55b892 Merge branch 'MOODLE_36_MDL-66864' of https://github.com/golenkovm/moodle into MOODLE_36_STABLE 2019-10-13 02:09:01 +02:00
Eloy Lafuente (stronk7) 4462ed30c7 Merge branch 'MDL-65584-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-10-13 01:49:59 +02:00
Eloy Lafuente (stronk7) badb6a92c4 weekly release 3.6.6+ 2019-10-11 22:43:37 +02:00
Eloy Lafuente (stronk7) c6f435069e Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-10-11 22:43:25 +02:00
Neill Magill ff9be7de2c MDL-64064 block_timeline: Confusing when event is not in this year
If an event is not in the current year it can be confusing as the
months and days may appear to be in the wrong order.

This change adds the year to the displayed date to make the reason
for the order clear.
2019-10-11 08:39:14 +01:00
Tim Hunt eec220f2fc MDL-66559 behat: Documentation for component selectors 2019-10-11 12:58:16 +08:00
Andrew Nicols 8694eaac19 MDL-66559 behat: Allow per-component selectors and replacements 2019-10-11 12:58:16 +08:00
Jake Dallimore 8aeddd78bf Merge branch 'MDL-66804-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-10-11 09:58:49 +08:00
Jun Pataleta 3df36d632c Merge branch 'MDL-66450-36' of git://github.com/bmbrands/moodle into MOODLE_36_STABLE 2019-10-11 09:20:21 +08:00
AMOS bot 7c31894342 Automatically generated installer lang files 2019-10-11 00:11:43 +00:00
Eloy Lafuente (stronk7) 8f89e0bde5 Merge branch 'MDL-66815_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-11 00:50:51 +02:00
Bas Brands 102e20c11b MDL-66450 theme_bootstrapbase: form autocomplete truncate listitems 2019-10-10 17:18:22 +02:00
David Monllaó ff698a03ec MDL-66806 analytics: No predictions for hidden courses 2019-10-10 10:09:43 +08:00
AMOS bot c917c9860c Automatically generated installer lang files 2019-10-10 00:09:35 +00:00
sam marshall fdf8e3668f MDL-66836 Behat: Reset unknown config variables between scenarios
In the Behat CLI run (not in the individual web requests), if you
modified an existing $CFG variable then this would be reset at the
start of the next scenario. However, if you added a completely new
one, it would not be reset. This change removes those variables.
2019-10-09 17:49:56 +01:00
Jun Pataleta 6d791cfa86 Merge branch 'MDL-66835_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-09 20:44:27 +08:00
Jun Pataleta e3d4c8d5a4 Merge branch 'MDL-66450-36' of git://github.com/bmbrands/moodle into MOODLE_36_STABLE 2019-10-09 20:39:15 +08:00
Bas Brands 6594812c15 MDL-66450 themes: form autocomplete truncate listitems 2019-10-09 14:28:05 +02:00
Tim Hunt ece21a4a2b MDL-66835 behat: steps for setting/checking fields in containers 2019-10-09 13:24:19 +01:00
Sara Arjona 479eda9446 Merge branch 'MDL-66852-36' of github.com:lucaboesch/moodle into MOODLE_36_STABLE 2019-10-09 12:58:16 +02:00
Damyon Wiese d498f9b7da MDL-65243 badges: Use real time api
Never add or subtract timestamps - use the time api to do it correctly.
2019-10-09 11:56:12 +08:00
Andrew Nicols 976ad2a7de MDL-66779 phpunit: Correct component name for core_grades 2019-10-09 09:35:16 +08:00
Andrew Nicols 507928af8a Merge branch 'MDL-66118-36-byebyemoodlenet' of git://github.com/mudrd8mz/moodle into MOODLE_36_STABLE 2019-10-09 08:51:55 +08:00
Luca Bösch 6b8b0e2468 MDL-66852 quiz: Style "Try another question like this one" button. 2019-10-08 11:26:08 +02:00
Eloy Lafuente (stronk7) df05ccb9af weekly release 3.6.6+ 2019-10-08 10:43:25 +02:00
Eloy Lafuente (stronk7) 1d82d302bd Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-10-08 10:43:18 +02:00
Mihail Geshoski 10a1109b79 MDL-66851 block_starredcourses: Hide 'hidden' courses from students
Thanks to Mark Sharp for the bug report and fix suggestion.
2019-10-08 09:54:23 +08:00
AMOS bot d6a6c93a88 Automatically generated installer lang files 2019-10-08 00:10:13 +00:00
Paul Holden d6fdedd4ab MDL-65584 blog: safer deletion of associations in privacy provider.
It's possible that the given context list contains no posts, which caused
an exception to be thrown when passing an empty array to get_in_or_equal.
2019-10-08 00:23:43 +01:00
Eloy Lafuente (stronk7) a3de11a763 Merge branch 'MDL-66801_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-08 01:16:57 +02:00
Eloy Lafuente (stronk7) 051e6b38e2 Merge branch 'MDL-66764_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-10-07 22:51:25 +02:00
Mikhail Golenkov 2d1b49b953 MDL-66864 upgrade: Delete non-mutual contacts in chunks. 2019-10-07 16:34:42 +11:00
David Mudrák 71f49c970e MDL-66118 hub: Remove the mentions of moodle.net
This is an update of the site registration admin page and some relevant
backend code to remove the mentions of moodle.net.

AMOS BEGIN
 CPY [registerwithmoodleorg,core_admin],[registerwithmoodleorg,core_hub]
AMOS END
2019-10-04 21:44:02 +02:00
David Mudrák 3bef0a6cf2 MDL-66118 hub: Stop using the hub URL as the setting name suffix
Site indicators shared with the registration hub used to have the hub
URL in the relevant setting names - such as site_name_httpsmoodlenet.
This upgrade step converts all such settings and drops the URL suffix
because we do not support alternative hubs any more.

Additionally the upgrade step renames the official hub and updates its
URL so that existing registrations with https://moodle.net are still
valid.
2019-10-04 21:44:02 +02:00
David Mudrák 168a1fed2a MDL-66118 hub: Define the new sites directory URL
The Moodle sites now register with stats.moodle.org so use that as a new
official hub's URL. Beside that, allow for the alternative value be
provided in config.php for development and testing purposes.
2019-10-04 21:42:09 +02:00
Eloy Lafuente (stronk7) 3016cb824d weekly release 3.6.6+ 2019-10-04 16:01:35 +02:00
Jun Pataleta 9b1c66d4e5 Merge branch 'MDL-65315-36' of git://github.com/peterRd/moodle into MOODLE_36_STABLE 2019-10-04 10:24:59 +08:00
Peter 496eeb0f73 MDL-65315 badges: Update the class and issuer OBv2.0 url 2019-10-04 07:46:53 +08:00
Eloy Lafuente (stronk7) 77414d0d57 Merge branch 'MDL-56649-36' of git://github.com/bmbrands/moodle into MOODLE_36_STABLE 2019-10-03 19:37:34 +02:00
Jun Pataleta d1dbe6db4a Merge branch 'MDL-61450-36' of git://github.com/lameze/moodle into MOODLE_36_STABLE 2019-10-03 15:42:01 +08:00
Jun Pataleta 7070a23d97 MDL-61450 calendar: Unit test for calendar_view_event_allowed()
* Unit test for calendar_view_event_allowed() when dealing with course
events.
2019-10-03 15:39:25 +08:00
Simey Lameze dec2ad8603 MDL-61450 calendar: fix course event type permissions 2019-10-03 15:39:25 +08:00
Eloy Lafuente (stronk7) c89a1b99fd Merge branch 'MDL-66774-36-macedonia' of git://github.com/mudrd8mz/moodle into MOODLE_36_STABLE 2019-10-03 00:59:15 +02:00
Eloy Lafuente (stronk7) f30091c8dc Merge branch 'MDL-66197-36' of git://github.com/marinaglancy/moodle into MOODLE_36_STABLE 2019-10-03 00:45:52 +02:00
Eloy Lafuente (stronk7) 6f32cfee2b Merge branch 'MDL-65335_36_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_36_STABLE 2019-10-01 23:22:43 +02:00
Tim Hunt d6f442bf41 MDL-66815 behat: question category generator must find right parent id
This is implemented in a bit of a hacky way, because the only other
alternative would be a large rewrite of the whole class, which is
not feasible for me right now. Note that many other types of thing
that can be generated suffer from the same issue. (E.g. if you ever
wanted to generate two groups with the same name in two different
courses and then add group memebers.)

It is worth doing a special-case fix for question categories, because
way Moodle works, it is inevitable that we end up with many categories
called 'top' in the database.
2019-10-01 16:48:41 +01:00
Eloy Lafuente (stronk7) 896db11641 Merge branch 'MDL-65522-m36' of https://github.com/NeillM/moodle into MOODLE_36_STABLE 2019-10-01 16:13:16 +02:00
Eloy Lafuente (stronk7) fb23adbcd3 Merge branch 'MDL-66542_36' of https://github.com/t-schroeder/moodle into MOODLE_36_STABLE 2019-10-01 15:58:58 +02:00
Paul Holden 9bdca4fbe0 MDL-66659 core: observe viewfullnames capability in flexible_table. 2019-10-01 10:15:25 +01:00
Paul Holden 6442cf75ee MDL-66804 user: consistent user access times in privacy export. 2019-09-30 23:15:05 +01:00
Tim Hunt ed3fc39176 MDL-66801 questions: XML import/export should include category idnumbers 2019-09-30 19:00:37 +01:00
Tim Hunt eaca013a20 MDL-66796 question bank: 0 is a valid question category idnumber 2019-09-30 14:19:22 +01:00
Tim Schroeder 864cd27438 MDL-66542 lib: Fix quote escaping in JS quote helper 2019-09-30 10:11:33 +02:00
Neill Magill 0aa44e4539 MDL-65522 block_social_activities: Improve behat steps documentation
The documentation for these steps was not helpful in the Acceptance
testing admin tool page.
2019-09-30 09:00:15 +01:00
Jun Pataleta 4897a4a166 weekly release 3.6.6+ 2019-09-27 11:12:20 +08:00
Jun Pataleta 0bad3d746d Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-09-27 11:12:19 +08:00
David Mudrák 67125ee5f4 MDL-66774 lang: Update the list of countries as per ISO 3166-1
Source: https://www.iso.org/obp/ui/

Two significant changes are:

* North Macedonia
* Eswatini

All other changes are formal, such as changing the letter case of the
"And" (the current ISO uses the lower case "and").  Our own existing
modifications of the list (such as having just "United States" and
"United Kingdom" instead of the full long name) were kept.
2019-09-26 10:55:29 +02:00
Jun Pataleta 9d30d31afb Merge branch 'MDL-66262_36' of git://github.com/stronk7/moodle into MOODLE_36_STABLE 2019-09-26 11:34:33 +08:00
Eloy Lafuente (stronk7) cff6fab1cd Merge branch 'MDL-51327-36' of git://github.com/mihailges/moodle into MOODLE_36_STABLE 2019-09-26 00:05:06 +02:00
Eloy Lafuente (stronk7) d3843bbc7e Merge branch 'MDL-66685_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-09-25 23:58:07 +02:00
Eloy Lafuente (stronk7) f47a98b31f Merge branch 'MDL-66675-36' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-09-25 20:06:25 +02:00
Marina Glancy 48d8fb92ff MDL-66197 core: correct get parent language 2019-09-25 17:41:45 +02:00
Bas Brands d5f83a1a23 MDL-56649 themes: filepicker file exists buttons spacing 2019-09-25 12:25:10 +02:00
Tim Hunt a29971b021 MDL-66764 quiz: redo question should not repeat random questions
Before this fix, it was only considering questions seen in previous attempts.

It should avoid the questions in the current attmept too.
2019-09-25 11:05:24 +01:00
Jun Pataleta 16ec7c1d7c Merge branch 'MDL-66354-36' of http://github.com/dravek/moodle into MOODLE_36_STABLE 2019-09-25 16:42:46 +08:00
David Matamoros 4f4d28b56b MDL-66354 core_calendar: Notices in error.log on calendar events 2019-09-25 09:13:03 +02:00
Jun Pataleta 6de29467ce Merge branch 'MDL-66644-36-versionrequires' of git://github.com/mudrd8mz/moodle into MOODLE_36_STABLE 2019-09-25 14:53:20 +08:00
Eloy Lafuente (stronk7) cfc96245ba Merge branch 'MDL-65621-dimmed-courses-MOODLE_3.6' of https://github.com/stopfstedt/moodle into MOODLE_36_STABLE 2019-09-24 19:09:22 +02:00
Mihail Geshoski 935d259396 MDL-51327 core_course: Allow subdirs in edit section form 2019-09-24 09:09:38 +08:00
AMOS bot 9cfbcde257 Automatically generated installer lang files 2019-09-22 00:09:27 +00:00
Sara Arjona 9d7fd4b062 Merge branch 'MDL-46978-MOODLE_36_STABLE' of github.com:tuanngocnguyen/moodle into MOODLE_36_STABLE 2019-09-20 13:08:15 +02:00
Sara Arjona f1659f3f40 Merge branch 'MDL-66090_36' of git://github.com/dmonllao/moodle into MOODLE_36_STABLE 2019-09-20 12:46:36 +02:00
Mark Johnson c63863df2b MDL-65335 auth: Make oauth2 enabled check more efficient 2019-09-20 08:56:06 +01:00
Jake Dallimore 2fb35f856c Merge branch 'MDL-65970-36' of git://github.com/jleyva/moodle into MOODLE_36_STABLE 2019-09-20 14:29:29 +08:00
Sara Arjona 6709fdbb6d weekly release 3.6.6+ 2019-09-19 21:19:16 +02:00
Stefan Topfstedt 7f9e015071 MDL-66433 block_myoverview: tag courses as "hidden from students"
This is intended to visually separate hidden course from open courses in the course overview block
by applying a "Hidden from students" tag to the various views in this block.
To achive this, the course summary exporter's output must be augmented with a "visiblity" attribute,
carrying the given course's corresponding visibility setting.
Since the exporter now expects this data point as part of its input, the output of the course_get_recent_courses()
function had to also be augmented with the course visibility setting to provide this value.
2019-09-19 10:09:39 -07:00
Eloy Lafuente (stronk7) da01d735a1 Merge branch 'MDL-65878-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-09-19 15:57:58 +02:00
Luca Bösch 8ad9815afc MDL-65878 core_output: Move button not sticky to select field. 2019-09-19 12:16:45 +02:00
Luca Bösch a1ed46a130 MDL-65878 core_output: Move button not sticky to select field. 2019-09-19 12:04:15 +02:00
Eloy Lafuente (stronk7) c62a946756 Merge branch 'MDL-65878-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-09-19 09:41:26 +02:00
Luca Bösch 0846707178 MDL-65878 forum: add padding for export to portfolio option. 2019-09-19 09:23:22 +02:00
Nathan Nguyen 9b6d7fc1e0 MDL-46978 core_grades: preserve category total visibility 2019-09-19 14:11:52 +10:00
David Monllaó 51e71e8aa9 MDL-66090 analytics: Support user for notifications 2019-09-19 08:00:26 +08:00
Andrew Nicols e46ad4a1a1 MDL-66675 behat: Fix typo in step function name 2019-09-19 07:30:42 +08:00
Andrew Nicols dec33c29aa MDL-66675 behat: Add option to pause on behat failures 2019-09-19 07:30:41 +08:00
Andrew Nicols e44811963c MDL-66675 CLI: Add ANSI formatting options 2019-09-19 07:30:40 +08:00
Eloy Lafuente (stronk7) cb5ae56e63 Merge branch 'MDL-66641_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-09-18 20:30:14 +02:00
Eloy Lafuente (stronk7) 10f73026e9 Merge branch 'MDL-65878-36' of https://github.com/lucaboesch/moodle into MOODLE_36_STABLE 2019-09-18 20:08:09 +02:00
Luca Bösch d30be99a47 MDL-65878 core_output: Move button not sticky to select field. 2019-09-18 19:10:50 +02:00
Eloy Lafuente (stronk7) 9467ac7707 Merge branch 'MDL-63895-36' of git://github.com/vmdef/moodle into MOODLE_36_STABLE 2019-09-18 17:33:36 +02:00
Sara Arjona 4bac2a4bdb Merge branch 'MDL-66614_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-09-18 17:11:15 +02:00
Sara Arjona 790cae52ca Merge branch 'MDL-63293-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-09-18 13:40:16 +02:00
Sara Arjona e943107851 Merge branch 'MDL-66156-36' of https://github.com/snake/moodle into MOODLE_36_STABLE 2019-09-18 12:25:55 +02:00
Eloy Lafuente (stronk7) 3ff1ef47f8 Merge branch 'MDL-65026-36' of git://github.com/jleyva/moodle into MOODLE_36_STABLE 2019-09-18 01:01:55 +02:00
Juan Leyva 305111bcd3 MDL-65970 airnotifier: Set lower timeout for Push curl requests 2019-09-17 16:51:39 +02:00
Eloy Lafuente (stronk7) aadce0acfa Merge branch 'MDL-62915-36' of https://github.com/paulholden/moodle into MOODLE_36_STABLE 2019-09-17 16:22:16 +02:00
Sara Arjona fd0a5bef1e Merge branch 'MDL-66113-36' of git://github.com/jleyva/moodle into MOODLE_36_STABLE 2019-09-17 12:04:04 +02:00
Paul Holden e8c2c263b7 MDL-62915 tool_dataprivacy: don't let primary admin delete themselves. 2019-09-16 23:41:05 +01:00
Eloy Lafuente (stronk7) 878e330148 Merge branch 'MDL-66293-36' of git://github.com/rezaies/moodle into MOODLE_36_STABLE 2019-09-16 20:38:41 +02:00
Tim Hunt fd4de847ce MDL-66685 questions: should able to save an empty question usage 2019-09-16 14:36:17 +01:00
Juan Leyva a25615ff66 MDL-66113 assign: Apply user overrides in get_submission_status WS 2019-09-16 12:08:42 +02:00
Paul Holden 56d043a636 MDL-63293 enrol_manual: observe user paging config in enrol dialog. 2019-09-15 21:48:22 +01:00
Eloy Lafuente (stronk7) 1ed4e401f1 MDL-66262 env: Moodle 3.6.x and 3.7.x do not support PHP 7.4 2019-09-13 17:44:36 +02:00
Jake Dallimore f1246ad631 weekly release 3.6.6+ 2019-09-13 11:30:17 +08:00
Jake Dallimore b91f9efddc Merge branch 'install_36_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_36_STABLE 2019-09-13 11:30:16 +08:00
Eloy Lafuente (stronk7) 4c03ce0895 Merge branch 'MDL-66550-36-2' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-09-12 15:32:01 +02:00
Víctor Déniz Falcón 470e23e25b MDL-63895 user: Hide suspended enrolments to user without capability
Users without course:viewsuspendedusers capability should not view
suspended users on the participant list
2019-09-12 11:58:09 +01:00
Shamim Rezaie 2af29ca628 MDL-66293 javascript: set maximum paging bar size to 10 2019-09-12 18:05:59 +10:00
Shamim Rezaie 5cb6386af1 MDL-66293 theme_bootstrapbase: Support setting bar size for paging bars 2019-09-12 18:05:59 +10:00
Andrew Nicols 0ac32aff37 MDL-66550 admin: The execute wrapper MUST be used in behat 2019-09-12 16:04:16 +08:00
Andrew Nicols 9400966aa9 MDL-66550 theme: Wrap JS calls in pendingJS 2019-09-12 14:59:17 +08:00
Jake Dallimore 55f56db61f MDL-66156 block_myoverview: remove orphaned course favourite records 2019-09-12 13:12:13 +08:00
Jake Dallimore 09b691381c MDL-66156 block_myoverview: purge course favourites on course deletion. 2019-09-12 13:12:12 +08:00
Shamim Rezaie 37e349dd89 MDL-66293 javascript: Added support to set bar size for paging bars 2019-09-12 14:24:34 +10:00
Andrew Nicols ddd9d6e95e Merge branch 'MDL-66498_36' of git://github.com/dmonllao/moodle into MOODLE_36_STABLE 2019-09-12 11:18:11 +08:00
Jake Dallimore 34a5bd4223 Merge branch 'MDL-64917-MOODLE_36_STABLE' of https://github.com/tuanngocnguyen/moodle into MOODLE_36_STABLE 2019-09-12 09:28:32 +08:00
Nathan Nguyen 734cd75ed3 MDL-64917 filepicker: change event dispatch 2019-09-12 11:00:43 +10:00
AMOS bot ee73cabac3 Automatically generated installer lang files 2019-09-12 00:09:30 +00:00
Andrew Nicols 9455300763 Merge branch 'MDL-66489-36' of git://github.com/rezaies/moodle into MOODLE_36_STABLE 2019-09-12 07:08:17 +08:00
Shamim Rezaie 5f4a113242 MDL-66489 enrol: Send all form data to WS and do all busines logic there
It is discouraged to use JS Date functions. We should pass all raw data to PHP.
2019-09-11 20:35:04 +10:00
Andrew Nicols b680e40303 Merge branch 'MDL-65429-36' of git://github.com/peterRd/moodle into MOODLE_36_STABLE 2019-09-11 14:23:04 +08:00
Jake Dallimore d1221854c8 Merge branch 'MDL-65493-36-2' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-09-11 13:45:56 +08:00
David Monllaó ec77087e21 MDL-66498 analytics: get_samples() with no params limit 2019-09-11 12:46:54 +08:00
David Monllaó af06a498dc MDL-66498 analytics: Avoid get_in_or_equal for big arrays
Also, join directly with context table.
2019-09-11 12:46:55 +08:00
Andrew Nicols 2ba7a4066d Merge branch 'MDL-66328_36' of https://github.com/timhunt/moodle into MOODLE_36_STABLE 2019-09-11 12:21:45 +08:00
Jake Dallimore 3475c90d37 Merge branch 'MDL-66550-36-2' of git://github.com/andrewnicols/moodle into MOODLE_36_STABLE 2019-09-11 10:40:32 +08:00
Eloy Lafuente (stronk7) f6c82c8a86 Merge branch 'MDL-65310-36' of https://github.com/tsmilan/moodle into MOODLE_36_STABLE 2019-09-11 00:44:53 +02:00
David Mudrák 8a65065551 MDL-66644 admin: Display required moodle version only when declared
The minimum required Moodle version specified in the plugin's
version.php file is not a mandatory field. If it is not declared, do not
display "Moodle {$a}".
2019-09-10 18:11:35 +02:00
Andrew Nicols ec372682b8 MDL-66550 forum: Target fields in a fieldset for behat test 2019-09-10 21:24:20 +08:00
Andrew Nicols 85b30e2ac5 MDL-66550 behat: Transform fields to search in a fieldset 2019-09-10 21:24:20 +08:00
Andrew Nicols 0c7478e4fa MDL-66550 behat: Standardise finding in core functionality 2019-09-10 21:24:20 +08:00
Andrew Nicols 1b52ec70f0 MDL-66550 behat: Add ability to transform a specific selector 2019-09-10 21:24:15 +08:00
Andrew Nicols f4f245e011 MDL-66550 behat: Normalise selectors better 2019-09-10 21:24:07 +08:00
Tim Hunt 7d8ad43bd2 MDL-66641 quiz stats: discriminativeefficiency is already out of 100 2019-09-10 12:12:16 +01:00
Jake Dallimore a3de6b7961 Merge branch 'MDL-66409-edit-numerical/moodle36' of https://github.com/RaAstons/moodle into MOODLE_36_STABLE 2019-09-10 13:35:21 +08:00
Andrew Nicols 153502a7f5 Merge branch 'MDL-63250-36' of https://github.com/Kathrin84/moodle into MOODLE_36_STABLE 2019-09-10 12:41:01 +08:00
Tim Hunt d5bb3640d5 MDL-66328 groups: overview page can require lots of memory 2019-09-09 11:20:30 +01:00
Raphaël Santos 5c37c61b42 MDL-66409 mod_lesson: Fix editing of numerical pages
This avoids using the "magic" `isset` function implemented
within the lesson_base class (which returns the `empty` function).
In the case of the answer beeing `0`, the test fails and the answer
is considered to be deleted.
2019-09-09 09:41:49 +02:00
David Monllao 926ff49e12 MDL-66498 analytics: SQL IN in chunks 2019-09-06 13:35:54 +08:00
Trisha Milan 90b9c2e2d3 MDL-65310 block_timeline: Hide activities without due date 2019-09-06 13:49:00 +10:00
Andrew Nicols c50947b75e MDL-65493 core: Add pendingJS around pubsub.publish 2019-09-06 08:41:11 +08:00
Andrew Nicols c61928e007 MDL-65493 message: The execute wrapper MUST be used 2019-09-06 08:41:11 +08:00
Andrew Nicols 6f09229a3d MDL-65493 message: JS fixes for random behat fails 2019-09-06 08:41:11 +08:00
Andrew Nicols 16291ec5bd MDL-65493 theme_bootstrapbase: Emulate transition ends for BS2 events 2019-09-06 08:41:11 +08:00
Andrew Nicols d96c728295 MDL-65493 theme_bootstrapbase: Pending JS checks for transitions 2019-09-06 08:41:11 +08:00
Andrew Nicols 17da93d42b MDL-66614 pgsql DML: Update get_records_sql to consume less memory
This is a backport of MDL-66327.

It's more memory efficient to use `pg_fetch_assoc` for each row than to
call `pg_fetch_all` and release memory immediately. This is because we
can treat the assoc fetch like an iterator and it only fetches the
current record into memory one at a time, whilst the all fetch fetches
all records and never unsets them. Attempting to unset them is extremely
time consuming.
2019-09-05 16:05:27 +01:00
Peter e49444d535 MDL-65429 mod_forum: Indicate subs fetch completion with no subs
Unit tests updated to make sure only a single query is executed after
multiple reads
2019-08-30 09:08:19 +08:00
Juan Leyva 19cedc5bf8 MDL-65026 course: Fix modules intro formatting in WS
The Web Service seems to be doing excessive text cleaning.
2019-08-16 11:55:13 +01:00
Kathrin Osswald 9d2fbd521b MDL-63250 mediaplugin: Fixed video player size in specific tables 2019-07-18 13:53:36 +02:00
422 changed files with 7955 additions and 3019 deletions
+97 -88
View File
@@ -514,100 +514,105 @@ if ($interactive) {
$database = $databases[$CFG->dbtype];
// ask for db host
if ($interactive) {
cli_separator();
cli_heading(get_string('databasehost', 'install'));
if ($options['dbhost'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
// We cannot do any validation until all DB connection data is provided.
$hintdatabase = '';
do {
echo $hintdatabase;
// Ask for db host.
if ($interactive) {
cli_separator();
cli_heading(get_string('databasehost', 'install'));
if ($options['dbhost'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbhost']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbhost = cli_input($prompt, $options['dbhost']);
} else {
$prompt = get_string('clitypevalue', 'admin');
$CFG->dbhost = $options['dbhost'];
}
$CFG->dbhost = cli_input($prompt, $options['dbhost']);
} else {
$CFG->dbhost = $options['dbhost'];
}
// Ask for db name.
if ($interactive) {
cli_separator();
cli_heading(get_string('databasename', 'install'));
if ($options['dbname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbname = cli_input($prompt, $options['dbname']);
// ask for db name
if ($interactive) {
cli_separator();
cli_heading(get_string('databasename', 'install'));
if ($options['dbname'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbname']);
} else {
$prompt = get_string('clitypevalue', 'admin');
$CFG->dbname = $options['dbname'];
}
$CFG->dbname = cli_input($prompt, $options['dbname']);
} else {
$CFG->dbname = $options['dbname'];
}
// Ask for db prefix.
if ($interactive) {
cli_separator();
cli_heading(get_string('dbprefix', 'install'));
//TODO: solve somehow the prefix trouble for oci.
if ($options['prefix'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->prefix = cli_input($prompt, $options['prefix']);
// ask for db prefix
if ($interactive) {
cli_separator();
cli_heading(get_string('dbprefix', 'install'));
//TODO: solve somehow the prefix trouble for oci
if ($options['prefix'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['prefix']);
} else {
$prompt = get_string('clitypevalue', 'admin');
$CFG->prefix = $options['prefix'];
}
$CFG->prefix = cli_input($prompt, $options['prefix']);
} else {
$CFG->prefix = $options['prefix'];
}
// Ask for db port.
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseport', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbport']);
$CFG->dboptions['dbport'] = (int) cli_input($prompt, $options['dbport']);
// ask for db port
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseport', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbport']);
$CFG->dboptions['dbport'] = (int)cli_input($prompt, $options['dbport']);
} else {
$CFG->dboptions['dbport'] = (int)$options['dbport'];
}
if ($CFG->dboptions['dbport'] <= 0) {
$CFG->dboptions['dbport'] = '';
}
// ask for db socket
if ($CFG->ostype === 'WINDOWS') {
$CFG->dboptions['dbsocket'] = '';
} else if ($interactive and empty($CFG->dboptions['dbport'])) {
cli_separator();
cli_heading(get_string('databasesocket', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbsocket']);
$CFG->dboptions['dbsocket'] = cli_input($prompt, $options['dbsocket']);
} else {
$CFG->dboptions['dbsocket'] = $options['dbsocket'];
}
// ask for db user
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseuser', 'install'));
if ($options['dbuser'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
} else {
$prompt = get_string('clitypevalue', 'admin');
$CFG->dboptions['dbport'] = (int) $options['dbport'];
}
if ($CFG->dboptions['dbport'] <= 0) {
$CFG->dboptions['dbport'] = '';
}
$CFG->dbuser = cli_input($prompt, $options['dbuser']);
} else {
$CFG->dbuser = $options['dbuser'];
}
// Ask for db socket.
if ($CFG->ostype === 'WINDOWS') {
$CFG->dboptions['dbsocket'] = '';
} else if ($interactive and empty($CFG->dboptions['dbport'])) {
cli_separator();
cli_heading(get_string('databasesocket', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbsocket']);
$CFG->dboptions['dbsocket'] = cli_input($prompt, $options['dbsocket']);
} else {
$CFG->dboptions['dbsocket'] = $options['dbsocket'];
}
// Ask for db user.
if ($interactive) {
cli_separator();
cli_heading(get_string('databaseuser', 'install'));
if ($options['dbuser'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbuser']);
} else {
$prompt = get_string('clitypevalue', 'admin');
}
$CFG->dbuser = cli_input($prompt, $options['dbuser']);
} else {
$CFG->dbuser = $options['dbuser'];
}
// Ask for db password.
if ($interactive) {
cli_separator();
cli_heading(get_string('databasepass', 'install'));
// ask for db password
if ($interactive) {
cli_separator();
cli_heading(get_string('databasepass', 'install'));
do {
if ($options['dbpass'] !== '') {
$prompt = get_string('clitypevaluedefault', 'admin', $options['dbpass']);
} else {
@@ -615,19 +620,23 @@ if ($interactive) {
}
$CFG->dbpass = cli_input($prompt, $options['dbpass']);
if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation
$distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']), $distro);
if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation.
$distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']),
$distro);
}
$hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']));
} while ($hint_database !== '');
$hintdatabase = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']));
} else {
$CFG->dbpass = $options['dbpass'];
$hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']));
if ($hint_database !== '') {
cli_error(get_string('dbconnectionerror', 'install'));
} else {
$CFG->dbpass = $options['dbpass'];
$hintdatabase = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix,
array('dbpersist' => 0, 'dbport' => $CFG->dboptions['dbport'], 'dbsocket' => $CFG->dboptions['dbsocket']));
if ($hintdatabase !== '') {
cli_error(get_string('dbconnectionerror', 'install'));
}
}
}
} while ($hintdatabase !== '');
// ask for fullname
if ($interactive) {
+183
View File
@@ -2451,6 +2451,7 @@
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.0.0" level="required">
<RESTRICT function="restrict_php_version_74" message="unsupportedphpversion74" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -2632,6 +2633,7 @@
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.1.0" level="required">
<RESTRICT function="restrict_php_version_74" message="unsupportedphpversion74" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -2980,4 +2982,185 @@
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.9" requires="3.5">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="10.2.29" />
<VENDOR name="mysql" version="5.6" />
<VENDOR name="postgres" version="9.5" />
<VENDOR name="mssql" version="11.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.2.0" level="required">
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="required">
<FEEDBACK>
<ON_ERROR message="mbstringrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
<FEEDBACK>
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+1 -1
View File
@@ -46,7 +46,7 @@ $error = optional_param('error', '', PARAM_ALPHANUM);
admin_externalpage_setup('registrationmoodleorg');
if ($url !== HUB_MOODLEORGHUBURL) {
// Allow other plugins to confirm registration on hubs other than moodle.net . Plugins implementing this
// 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');
foreach ($callbacks as $plugintype => $plugins) {
+1 -2
View File
@@ -32,5 +32,4 @@
defined('MOODLE_INTERNAL') || die();
debugging('Support for alternative hubs has been removed from Moodle in 3.4. For communication with moodle.net ' .
'see lib/classes/hub/ .', DEBUG_DEVELOPER);
debugging('Support for alternative hubs has been removed from Moodle in 3.4.', DEBUG_DEVELOPER);
+6 -6
View File
@@ -22,7 +22,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
*
* This page displays the site registration form for Moodle.net.
* This page displays the site registration form.
* It handles redirection to the hub to continue the registration workflow process.
* It also handles update operation by web service.
*/
@@ -48,7 +48,7 @@ if ($unregistration && \core\hub\registration::is_registered()) {
}
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', 'Moodle.net'), 3, 'main');
echo $OUTPUT->heading(get_string('registerwithmoodleorgremove', 'core_hub'), 3, 'main');
$siteunregistrationform->display();
echo $OUTPUT->footer();
exit;
@@ -82,7 +82,7 @@ if ($fromform = $siteregistrationform->get_data()) {
echo $OUTPUT->header();
// Current status of registration on Moodle.net.
// Current status of registration.
$notificationtype = \core\output\notification::NOTIFY_ERROR;
if (\core\hub\registration::is_registered()) {
@@ -104,11 +104,11 @@ if (\core\hub\registration::is_registered()) {
// Heading.
if (\core\hub\registration::is_registered()) {
echo $OUTPUT->heading(get_string('updatesite', 'hub', 'Moodle.net'));
echo $OUTPUT->heading(get_string('registerwithmoodleorgupdate', 'core_hub'));
} else if ($isinitialregistration) {
echo $OUTPUT->heading(get_string('completeregistration', 'hub'));
echo $OUTPUT->heading(get_string('registerwithmoodleorgcomplete', 'core_hub'));
} else {
echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'core_hub'));
}
$renderer = $PAGE->get_renderer('core', 'admin');
+2 -2
View File
@@ -40,7 +40,7 @@ $token = optional_param('token', '', PARAM_TEXT);
admin_externalpage_setup('registrationmoodleorg');
if ($url !== HUB_MOODLEORGHUBURL) {
// Allow other plugins to renew registration on hubs other than moodle.net . Plugins implementing this
// 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');
foreach ($callbacks as $plugintype => $plugins) {
@@ -56,7 +56,7 @@ if ($url !== HUB_MOODLEORGHUBURL) {
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('renewregistration', 'hub'), 3, 'main');
$hublink = html_writer::tag('a', 'Moodle.net', array('href' => HUB_MOODLEORGHUBURL));
$hublink = html_writer::tag('a', HUB_MOODLEORGHUBURL, array('href' => HUB_MOODLEORGHUBURL));
$deletedregmsg = get_string('previousregistrationdeleted', 'hub', $hublink);
+27 -4
View File
@@ -1449,9 +1449,11 @@ class core_admin_renderer extends plugin_renderer_base {
$class = 'requires-failed';
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'label label-important');
}
$requires[] = html_writer::tag('li',
html_writer::span(get_string('moodleversion', 'core_plugin', $plugin->versionrequires), 'dep dep-core').
' '.$label, array('class' => $class));
if ($reqinfo->reqver != ANY_VERSION) {
$requires[] = html_writer::tag('li',
html_writer::span(get_string('moodleversion', 'core_plugin', $plugin->versionrequires), 'dep dep-core').
' '.$label, array('class' => $class));
}
} else {
$actions = array();
@@ -2090,6 +2092,27 @@ class core_admin_renderer extends plugin_renderer_base {
* @return string
*/
public function moodleorg_registration_message() {
return format_text(get_string('registermoodlenet', 'admin'), FORMAT_HTML, ['noclean' => true]);
$out = format_text(get_string('registerwithmoodleorginfo', 'core_hub'), FORMAT_MARKDOWN);
$out .= html_writer::link(
new moodle_url('/admin/settings.php', ['section' => 'moodleservices']),
$this->output->pix_icon('i/info', '').' '.get_string('registerwithmoodleorginfoapp', 'core_hub'),
['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
);
$out .= html_writer::link(
HUB_MOODLEORGHUBURL,
$this->output->pix_icon('i/stats', '').' '.get_string('registerwithmoodleorginfostats', 'core_hub'),
['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
);
$out .= html_writer::link(
HUB_MOODLEORGHUBURL.'/sites',
$this->output->pix_icon('i/location', '').' '.get_string('registerwithmoodleorginfosites', 'core_hub'),
['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
);
return $this->output->box($out);
}
}
+4 -1
View File
@@ -98,7 +98,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));
+5 -29
View File
@@ -48,7 +48,6 @@ class behat_admin extends behat_base {
* @param TableNode $table
*/
public function i_set_the_following_administration_settings_values(TableNode $table) {
if (!$data = $table->getRowsHash()) {
return;
}
@@ -57,17 +56,12 @@ class behat_admin extends behat_base {
// We expect admin block to be visible, otherwise go to homepage.
if (!$this->getSession()->getPage()->find('css', '.block_settings')) {
$this->getSession()->visit($this->locate_path('/'));
$this->wait(self::get_timeout() * 1000, self::PAGE_READY_JS);
$this->execute('behat_forms::i_am_on_homepage');
}
// Search by label.
$searchbox = $this->find_field(get_string('searchinsettings', 'admin'));
$searchbox->setValue($label);
$submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]');
$submitsearch->press();
$this->wait(self::get_timeout() * 1000, self::PAGE_READY_JS);
$this->execute('behat_forms::i_set_the_field_to', [get_string('searchinsettings', 'admin'), $label]);
$this->execute("behat_general::i_click_on_in_the", [get_string('search', 'admin'), 'button', '.block_settings', 'css_element']);
// Admin settings does not use the same DOM structure than other moodle forms
// but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
@@ -83,35 +77,17 @@ class behat_admin extends behat_base {
"@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]";
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
"/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div");
} catch (ElementNotFoundException $e) {
// Multi element settings, interacting only the first one.
$fieldxpath = "//*[label[normalize-space(.)= $label]|span[normalize-space(.)= $label]]/" .
"ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
"/descendant::div[@class='form-group']/descendant::*[self::input | self::textarea | self::select]" .
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
$fieldnode = $this->find('xpath', $fieldxpath);
// It is the same one that contains the type.
$formfieldtypenode = $fieldnode;
}
// Getting the class which contains the field type.
$classes = explode(' ', $formfieldtypenode->getAttribute('class'));
foreach ($classes as $class) {
if (substr($class, 0, 5) == 'form-') {
$type = substr($class, 5);
}
}
// Instantiating the appropiate field type.
$field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession());
$field->set_value($value);
$this->find_button(get_string('savechanges'))->press();
$this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]);
$this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']);
}
}
@@ -0,0 +1,27 @@
@tool_behat
Feature: Behat steps for interacting with form work
In order to test my Moodle code
As a developer
I need the Behat steps for form elements to work reliably
@javascript
Scenario: Test fields in containers
Given the following "courses" exist:
| fullname | shortname |
| Course 1 | C1 |
When I log in as "admin"
And I am on "Course 1" course homepage
# Just get to any form.
And I navigate to "Edit settings" in current page administration
And I set the field "Course full name" in the "General" "fieldset" to "Frog"
And I set the following fields in the "Appearance" "fieldset" to these values:
| Show activity reports | Yes |
| Number of announcements | 1 |
Then the field "Show activity reports" in the "Appearance" "fieldset" matches value "Yes"
And the field "Show activity reports" in the "Appearance" "fieldset" does not match value "No"
And the following fields in the "region-main" "region" match these values:
| Course full name | Frog |
| Number of announcements | 1 |
And the following fields in the "region-main" "region" do not match these values:
| Course full name | Course 1 |
| Number of announcements | 5 |
+42
View File
@@ -222,6 +222,48 @@ class api {
}
}
// Clean the legacy role assignments which are stale.
$paramsclean['usercontext'] = CONTEXT_USER;
$paramsclean['component'] = 'tool_cohortroles';
$sql = 'SELECT DISTINCT(ra.id), ra.roleid, ra.userid, ra.contextid, ctx.instanceid
FROM {role_assignments} ra
JOIN {context} ctx ON ctx.id = ra.contextid AND ctx.contextlevel = :usercontext
JOIN {cohort_members} cm ON cm.userid = ctx.instanceid
LEFT JOIN {tool_cohortroles} tc ON tc.cohortid = cm.cohortid
AND tc.userid = ra.userid
AND tc.roleid = ra.roleid
WHERE ra.component = :component
AND tc.id is null';
if ($candidatelegacyassignments = $DB->get_records_sql($sql, $paramsclean)) {
$sql = 'SELECT DISTINCT(ra.id)
FROM {role_assignments} ra
JOIN {context} ctx ON ctx.id = ra.contextid AND ctx.contextlevel = :usercontext
JOIN {cohort_members} cm ON cm.userid = ctx.instanceid
JOIN {tool_cohortroles} tc ON tc.cohortid = cm.cohortid AND tc.userid = ra.userid
WHERE ra.component = :component';
if ($currentvalidroleassignments = $DB->get_records_sql($sql, $paramsclean)) {
foreach ($candidatelegacyassignments as $candidate) {
if (!array_key_exists($candidate->id, $currentvalidroleassignments)) {
role_unassign($candidate->roleid, $candidate->userid, $candidate->contextid, 'tool_cohortroles');
$rolesremoved[] = array(
'useridassignedto' => $candidate->userid,
'useridassignedover' => $candidate->instanceid,
'roleid' => $candidate->roleid
);
}
}
} else {
foreach ($candidatelegacyassignments as $candidate) {
role_unassign($candidate->roleid, $candidate->userid, $candidate->contextid, 'tool_cohortroles');
$rolesremoved[] = array(
'useridassignedto' => $candidate->userid,
'useridassignedover' => $candidate->instanceid,
'roleid' => $candidate->roleid
);
}
}
}
return array('rolesadded' => $rolesadded, 'rolesremoved' => $rolesremoved);
}
@@ -103,5 +103,4 @@ class cohort_role_assignment extends persistent {
return true;
}
}
+82 -7
View File
@@ -50,8 +50,6 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
* Setup function- we will create a course and add an assign instance to it.
*/
protected function setUp() {
global $DB;
$this->resetAfterTest(true);
// Create some users.
@@ -133,14 +131,91 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
public function test_delete_cohort_role_assignment() {
$this->setAdminUser();
$params = (object) array(
// Create a cohort role assigment.
$params = (object) [
'userid' => $this->userassignto->id,
'roleid' => $this->roleid,
'cohortid' => $this->cohort->id
);
$result = api::create_cohort_role_assignment($params);
$worked = api::delete_cohort_role_assignment($result->get('id'));
$this->assertTrue($worked);
];
$cohortroleassignment = api::create_cohort_role_assignment($params);
$sync = api::sync_all_cohort_roles();
$rolesadded = [
[
'useridassignedto' => $this->userassignto->id,
'useridassignedover' => $this->userassignover->id,
'roleid' => $this->roleid
]
];
$expected = [
'rolesadded' => $rolesadded,
'rolesremoved' => []
];
$this->assertEquals($sync, $expected);
// Delete the cohort role assigment and confirm the roles are removed.
$result = api::delete_cohort_role_assignment($cohortroleassignment->get('id'));
$this->assertTrue($result);
$sync = api::sync_all_cohort_roles();
$expected = [
'rolesadded' => [],
'rolesremoved' => $rolesadded
];
$this->assertEquals($expected, $sync);
}
/**
* Test case verifying that syncing won't remove role assignments if they are valid for another cohort role assignment.
*/
public function test_delete_cohort_role_assignment_cohorts_having_same_members() {
$this->setAdminUser();
// Create 2 cohorts, with a 1 user (user1) present in both,
// and user2 and user3 members of 1 cohort each.
$cohort1 = $this->getDataGenerator()->create_cohort();
$cohort2 = $this->getDataGenerator()->create_cohort();
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
cohort_add_member($cohort1->id, $user1->id);
cohort_add_member($cohort1->id, $user2->id);
cohort_add_member($cohort2->id, $user1->id);
cohort_add_member($cohort2->id, $user3->id);
// And a role and a user to assign that role to.
$user4 = $this->getDataGenerator()->create_user(); // A cohort manager, for example.
$roleid = create_role('Role 1', 'myrole', 'test');
// Assign the role for user4 in both cohorts.
$params = (object) [
'userid' => $user4->id,
'roleid' => $roleid,
'cohortid' => $cohort1->id
];
$cohort1roleassignment = api::create_cohort_role_assignment($params);
$params->cohortid = $cohort2->id;
$cohort2roleassignment = api::create_cohort_role_assignment($params);
$sync = api::sync_all_cohort_roles();
// There is no guarantee about the order of roles assigned.
// so confirm we have 3 role assignments, and they are for the users 1, 2 and 3.
$this->assertCount(3, $sync['rolesadded']);
$addedusers = array_column($sync['rolesadded'], 'useridassignedover');
$this->assertContains($user1->id, $addedusers);
$this->assertContains($user2->id, $addedusers);
$this->assertContains($user3->id, $addedusers);
// Remove the role assignment for user4/cohort1.
// Verify only 1 role is unassigned as the others are still valid for the other cohort role assignment.
$result = api::delete_cohort_role_assignment($cohort1roleassignment->get('id'));
$this->assertTrue($result);
$sync = api::sync_all_cohort_roles();
$this->assertCount(0, $sync['rolesadded']);
$this->assertCount(1, $sync['rolesremoved']);
$removedusers = array_column($sync['rolesremoved'], 'useridassignedover');
$this->assertContains($user2->id, $removedusers);
}
public function test_list_cohort_role_assignments() {
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates"],function(a,b,c,d,e,f,g){function h(a){var e={methodname:"tool_dataprivacy_contact_dpo",args:{message:a}},f="success";b.call([e])[0].then(function(a){return a.result?d.get_string("requestsubmitted","tool_dataprivacy"):(f="error",a.warnings.join("<br>"))}).done(function(a){c.addNotification({message:a,type:f})}).fail(c.exception)}var i={CANCEL_REQUEST:'[data-action="cancel"]',CONTACT_DPO:'[data-action="contactdpo"]'},j=function(){this.registerEvents()};return j.prototype.registerEvents=function(){a(i.CANCEL_REQUEST).click(function(g){g.preventDefault();var h=a(this).data("requestid"),i=[{key:"cancelrequest",component:"tool_dataprivacy"},{key:"cancelrequestconfirmation",component:"tool_dataprivacy"}];d.get_strings(i).then(function(a){var d=a[0],g=a[1];return e.create({title:d,body:g,type:e.types.SAVE_CANCEL}).then(function(a){return a.setSaveButtonText(d),a.getRoot().on(f.save,function(){var a={requestid:h},d={methodname:"tool_dataprivacy_cancel_data_request",args:a};b.call([d])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a})}).done(function(a){a.show()}).fail(c.exception)}),a(i.CONTACT_DPO).click(function(b){b.preventDefault();var i=a(this).data("replytoemail"),j=[{key:"contactdataprotectionofficer",component:"tool_dataprivacy"},{key:"send",component:"tool_dataprivacy"}],k="";d.get_strings(j).then(function(a){var b=a[0];k=a[1];var c={replytoemail:i};return e.create({title:b,body:g.render("tool_dataprivacy/contact_dpo",c),type:e.types.SAVE_CANCEL,large:!0})}).done(function(b){b.setSaveButtonText(k),b.getRoot().on(f.save,function(b){var c=a("#message").val().trim();0===c.length?(b.preventDefault(),a('[data-region="messageinput"]').addClass("has-danger notifyproblem"),a("#id_error_message").removeAttr("hidden")):h(c)}),b.getRoot().on(f.hidden,function(){b.destroy()}),b.show()}).fail(c.exception)})},{init:function(){return new j}}});
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates","core/pending"],function(a,b,c,d,e,f,g,h){function i(a){var e={methodname:"tool_dataprivacy_contact_dpo",args:{message:a}},f="success";b.call([e])[0].then(function(a){return a.result?d.get_string("requestsubmitted","tool_dataprivacy"):(f="error",a.warnings.join("<br>"))}).done(function(a){c.addNotification({message:a,type:f})}).fail(c.exception)}var j={CANCEL_REQUEST:'[data-action="cancel"]',CONTACT_DPO:'[data-action="contactdpo"]'},k=function(){this.registerEvents()};return k.prototype.registerEvents=function(){a(j.CANCEL_REQUEST).click(function(g){g.preventDefault();var h=a(this).data("requestid"),i=[{key:"cancelrequest",component:"tool_dataprivacy"},{key:"cancelrequestconfirmation",component:"tool_dataprivacy"}];d.get_strings(i).then(function(a){var d=a[0],g=a[1];return e.create({title:d,body:g,type:e.types.SAVE_CANCEL}).then(function(a){return a.setSaveButtonText(d),a.getRoot().on(f.save,function(){var a={requestid:h},d={methodname:"tool_dataprivacy_cancel_data_request",args:a};b.call([d])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a})}).done(function(a){a.show()}).fail(c.exception)}),a(j.CONTACT_DPO).click(function(b){var j=new h("dataprivacy/crud:initModal:contactdpo");b.preventDefault();var k=a(this).data("replytoemail"),l=[{key:"contactdataprotectionofficer",component:"tool_dataprivacy"},{key:"send",component:"tool_dataprivacy"}],m="";d.get_strings(l).then(function(a){var b=a[0];m=a[1];var c={replytoemail:k};return e.create({title:b,body:g.render("tool_dataprivacy/contact_dpo",c),type:e.types.SAVE_CANCEL,large:!0})}).then(function(b){b.setSaveButtonText(m),b.show(),b.getRoot().on(f.save,function(b){var c=a("#message").val().trim();0===c.length?(b.preventDefault(),a('[data-region="messageinput"]').addClass("has-danger notifyproblem"),a("#id_error_message").removeAttr("hidden")):i(c)}),b.getRoot().on(f.hidden,function(){b.destroy()})}).then(j.resolve)["catch"](c.exception)})},{init:function(){return new k}}});
@@ -28,8 +28,9 @@ define([
'core/str',
'core/modal_factory',
'core/modal_events',
'core/templates'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
'core/templates',
'core/pending'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, Pending) {
/**
* List of action selectors.
@@ -118,6 +119,7 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
});
$(ACTIONS.CONTACT_DPO).click(function(e) {
var pendingPromise = new Pending('dataprivacy/crud:initModal:contactdpo');
e.preventDefault();
var replyToEmail = $(this).data('replytoemail');
@@ -146,9 +148,12 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
type: ModalFactory.types.SAVE_CANCEL,
large: true
});
}).done(function(modal) {
}).then(function(modal) {
modal.setSaveButtonText(sendButtonText);
// Show the modal!
modal.show();
// Handle send event.
modal.getRoot().on(ModalEvents.save, function(e) {
var message = $('#message').val().trim();
@@ -169,9 +174,9 @@ function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
modal.destroy();
});
// Show the modal!
modal.show();
}).fail(Notification.exception);
return;
}).then(pendingPromise.resolve)
.catch(Notification.exception);
});
};
@@ -127,13 +127,17 @@ class process_data_request_task extends adhoc_task {
$thing = $fs->create_file_from_pathname($filerecord, $exportedcontent);
$completestatus = api::DATAREQUEST_STATUS_DOWNLOAD_READY;
} else if ($request->type == api::DATAREQUEST_TYPE_DELETE) {
// Delete the data.
$manager = new \core_privacy\manager();
$manager->set_observer(new \tool_dataprivacy\manager_observer());
// Delete the data for users other than the primary admin, which is rejected.
if (is_primary_admin($foruser->id)) {
$completestatus = api::DATAREQUEST_STATUS_REJECTED;
} else {
$manager = new \core_privacy\manager();
$manager->set_observer(new \tool_dataprivacy\manager_observer());
$manager->delete_data_for_user($approvedclcollection);
$completestatus = api::DATAREQUEST_STATUS_DELETED;
$deleteuser = !$foruser->deleted;
$manager->delete_data_for_user($approvedclcollection);
$completestatus = api::DATAREQUEST_STATUS_DELETED;
$deleteuser = !$foruser->deleted;
}
}
// When the preparation of the metadata finishes, update the request status to awaiting approval.
@@ -134,6 +134,10 @@ class tool_dataprivacy_data_request_form extends moodleform {
$errors['type'] = get_string('errorrequestalreadyexists', 'tool_dataprivacy');
}
if ($data['type'] == api::DATAREQUEST_TYPE_DELETE && is_primary_admin($data['userid'])) {
$errors['type'] = get_string('errorcannotdeleteadmin', 'tool_dataprivacy');
}
return $errors;
}
}
@@ -124,6 +124,7 @@ $string['editpurposes'] = 'Edit purposes';
$string['effectiveretentionperiodcourse'] = '{$a} (after the course end date)';
$string['effectiveretentionperioduser'] = '{$a} (since the last time the user accessed the site)';
$string['emailsalutation'] = 'Dear {$a},';
$string['errorcannotdeleteadmin'] = 'Cannot create deletion request for the primary site admin';
$string['errorinvalidrequestcreationmethod'] = 'Invalid request creation method!';
$string['errorinvalidrequeststatus'] = 'Invalid request status!';
$string['errorinvalidrequesttype'] = 'Invalid request type!';
+1 -1
View File
@@ -78,7 +78,7 @@ function tool_dataprivacy_myprofile_navigation(tree $tree, $user, $iscurrentuser
// Check if the user has an ongoing data deletion request.
$hasdeleterequest = \tool_dataprivacy\api::has_ongoing_request($user->id, \tool_dataprivacy\api::DATAREQUEST_TYPE_DELETE);
// Show data deletion link only if the user doesn't have an ongoing data deletion request.
if (!$hasdeleterequest) {
if (!$hasdeleterequest && !is_primary_admin($user->id)) {
$deleteparams = ['type' => \tool_dataprivacy\api::DATAREQUEST_TYPE_DELETE];
$deleteurl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php', $deleteparams);
$deletenode = new core_user\output\myprofile\node('privacyandpolicies', 'requestdatadeletion',
+28
View File
@@ -301,6 +301,34 @@ class tool_dataprivacy_api_testcase extends advanced_testcase {
$datarequest = api::create_data_request($student->id, api::DATAREQUEST_TYPE_EXPORT);
$requestid = $datarequest->get('id');
// Login as a user without DPO role.
$this->setUser($teacher);
$this->expectException(required_capability_exception::class);
api::approve_data_request($requestid);
}
/**
* Test that deletion requests for the primary admin are rejected
*/
public function test_reject_data_deletion_request_primary_admin() {
$this->resetAfterTest();
$this->setAdminUser();
$datarequest = api::create_data_request(get_admin()->id, api::DATAREQUEST_TYPE_DELETE);
// Approve the request and execute the ad-hoc process task.
ob_start();
api::approve_data_request($datarequest->get('id'));
$this->runAdhocTasks('\tool_dataprivacy\task\process_data_request_task');
ob_end_clean();
$request = api::get_request($datarequest->get('id'));
$this->assertEquals(api::DATAREQUEST_STATUS_REJECTED, $request->get('status'));
// Confirm they weren't deleted.
$user = core_user::get_user($request->get('userid'));
core_user::require_active_user($user);
}
/**
@@ -88,6 +88,12 @@ Feature: Data delete from the privacy API
And I navigate to "Users > Privacy and policies > Data requests" in site administration
And I should see "Deleted"
@javascript
Scenario: As a primary admin, the link to create a data deletion request should not be shown.
Given I log in as "admin"
When I follow "Profile" in the user menu
Then I should not see "Delete my account"
@javascript
Scenario: As a parent, request account and data deletion for my child
Given I log in as "parent"
@@ -75,7 +75,7 @@ class manage_competency_frameworks_page implements renderable, templatable {
);
$this->navigation[] = $addpage;
$competenciesrepository = new single_button(
new moodle_url('https://moodle.net/competencies'),
new moodle_url('https://archive.moodle.net/competencies'),
get_string('competencyframeworksrepository', 'tool_lp'),
'get'
);
+6
View File
@@ -206,6 +206,12 @@ class api {
$identityprovidersdata = \auth_plugin_base::prepare_identity_providers_for_output($identityproviders, $OUTPUT);
if (!empty($identityprovidersdata)) {
$settings['identityproviders'] = $identityprovidersdata;
// Clean URLs to avoid breaking Web Services.
// We can't do it in prepare_identity_providers_for_output() because it may break the web output.
foreach ($settings['identityproviders'] as &$ip) {
$ip['url'] = (!empty($ip['url'])) ? clean_param($ip['url'], PARAM_URL) : '';
$ip['iconurl'] = (!empty($ip['iconurl'])) ? clean_param($ip['iconurl'], PARAM_URL) : '';
}
}
// If age is verified, return also the admin contact details.
+1 -1
View File
@@ -89,7 +89,7 @@ $string['pluginnotenabledorconfigured'] = 'Plugin not enabled or configured.';
$string['remoteaddons'] = 'Remote add-ons';
$string['selfsignedoruntrustedcertificatewarning'] = 'It seems that the HTTPS certificate is self-signed or not trusted. The mobile app will only work with trusted sites.';
$string['setuplink'] = 'App download page';
$string['setuplink_desc'] = 'URL of page with links to download the mobile app from the App Store and Google Play.';
$string['setuplink_desc'] = 'URL of page with options to download the mobile app from the App Store and Google Play. The app download page link is displayed in the page footer and in a user\'s profile. Leave blank to not display a link.';
$string['smartappbanners'] = 'App Banners';
$string['typeoflogin'] = 'Type of login';
$string['typeoflogin_desc'] = 'If the site uses a SSO authentication method, then select via a browser window or via an embedded browser. An embedded browser provides a better user experience, though it doesn\'t work with all SSO plugins.';
@@ -98,6 +98,7 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
);
$this->assertEquals($expected, $result);
$this->setAdminUser();
// Change some values.
set_config('registerauth', 'email');
$authinstructions = 'Something with <b>html tags</b>';
@@ -111,6 +112,18 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
set_config('lang', 'a_b'); // Set invalid lang.
set_config('disabledfeatures', 'myoverview', 'tool_mobile');
// Enable couple of issuers.
$issuer = \core\oauth2\api::create_standard_issuer('google');
$irecord = $issuer->to_record();
$irecord->clientid = 'mock';
$irecord->clientsecret = 'mock';
core\oauth2\api::update_issuer($irecord);
set_config('user_attribute', 'test', 'auth_shibboleth');
set_config('auth_logo', 'http://invalidurl.com//invalid/', 'auth_shibboleth');
set_config('auth', 'oauth2,shibboleth');
list($authinstructions, $notusedformat) = external_format_text($authinstructions, FORMAT_MOODLE, $context->id);
$expected['registerauth'] = 'email';
$expected['authinstructions'] = $authinstructions;
@@ -132,7 +145,26 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
$result = external::get_public_config();
$result = external_api::clean_returnvalue(external::get_public_config_returns(), $result);
// First check providers.
$identityproviders = $result['identityproviders'];
unset($result['identityproviders']);
$this->assertEquals('Google', $identityproviders[0]['name']);
$this->assertEquals($irecord->image, $identityproviders[0]['iconurl']);
$this->assertContains($CFG->wwwroot, $identityproviders[0]['url']);
$this->assertEquals('Shibboleth Login', $identityproviders[1]['name']);
$this->assertEmpty($identityproviders[1]['iconurl']);
$this->assertContains($CFG->wwwroot, $identityproviders[1]['url']);
$this->assertEquals($expected, $result);
// Change providers img.
$newurl = 'validimage.png';
set_config('auth_logo', $newurl, 'auth_shibboleth');
$result = external::get_public_config();
$result = external_api::clean_returnvalue(external::get_public_config_returns(), $result);
$this->assertContains($newurl, $result['identityproviders'][1]['iconurl']);
}
/**
+2 -1
View File
@@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
use \tool_monitor\privacy\provider;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\approved_userlist;
use \core_privacy\tests\provider_testcase;
/**
* Privacy test for the event monitor
@@ -37,7 +38,7 @@ use \core_privacy\local\request\approved_userlist;
* @copyright 2018 Adrian Greeve <adriangreeve.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_monitor_privacy_testcase extends advanced_testcase {
class tool_monitor_privacy_testcase extends provider_testcase {
/**
* Set up method.
+9 -3
View File
@@ -46,6 +46,9 @@ class issuer extends persistent {
/** @var string $type */
protected $type;
/** @var boolean $showrequireconfirm Whether to show the require confirmation email checkbox or not. */
protected $showrequireconfirm;
/**
* Constructor.
*
@@ -71,6 +74,7 @@ class issuer extends persistent {
if (array_key_exists('type', $customdata)) {
$this->type = $customdata['type'];
}
$this->showrequireconfirm = !empty($customdata['showrequireconfirm']);
parent::__construct($action, $customdata, $method, $target, $attributes, $editable, $ajaxformdata);
}
@@ -157,9 +161,11 @@ class issuer extends persistent {
$mform->addElement('checkbox', 'showonloginpage', get_string('issuershowonloginpage', 'tool_oauth2'));
$mform->addHelpButton('showonloginpage', 'issuershowonloginpage', 'tool_oauth2');
// Require confirmation email for new accounts.
$mform->addElement('advcheckbox', 'requireconfirmation', get_string('issuerrequireconfirmation', 'tool_oauth2'));
$mform->addHelpButton('requireconfirmation', 'issuerrequireconfirmation', 'tool_oauth2');
if ($this->showrequireconfirm) {
// Require confirmation email for new accounts.
$mform->addElement('advcheckbox', 'requireconfirmation', get_string('issuerrequireconfirmation', 'tool_oauth2'));
$mform->addHelpButton('requireconfirmation', 'issuerrequireconfirmation', 'tool_oauth2');
}
$mform->addElement('hidden', 'sortorder');
$mform->setType('sortorder', PARAM_INT);
+37 -7
View File
@@ -58,7 +58,24 @@ if ($action == 'edit') {
$PAGE->navbar->add(get_string('createnewissuer', 'tool_oauth2'));
}
$mform = new \tool_oauth2\form\issuer(null, ['persistent' => $issuer]);
$showrequireconfirm = false;
if (!empty($issuerid)) {
// Show the "Require confirmation email" checkbox for trusted issuers like Google, Facebook and Microsoft.
$likefacebook = $DB->sql_like('url', ':facebook');
$likegoogle = $DB->sql_like('url', ':google');
$likemicrosoft = $DB->sql_like('url', ':microsoft');
$params = [
'issuerid' => $issuerid,
'facebook' => '%facebook%',
'google' => '%google%',
'microsoft' => '%microsoft%',
];
$select = "issuerid = :issuerid AND ($likefacebook OR $likegoogle OR $likemicrosoft)";
// We're querying from the oauth2_endpoint table because the base URLs of FB and Microsoft can be empty in the issuer table.
$showrequireconfirm = $DB->record_exists_select('oauth2_endpoint', $select, $params);
}
$mform = new \tool_oauth2\form\issuer(null, ['persistent' => $issuer, 'showrequireconfirm' => $showrequireconfirm]);
}
if ($mform && $mform->is_cancelled()) {
@@ -108,9 +125,11 @@ if ($mform && $mform->is_cancelled()) {
$type = required_param('type', PARAM_ALPHA);
$docs = required_param('docslink', PARAM_ALPHAEXT);
$showrequireconfirm = optional_param('showrequireconfirm', false, PARAM_BOOL);
require_sesskey();
$issuer = core\oauth2\api::init_standard_issuer($type);
$mform = new \tool_oauth2\form\issuer(null, ['persistent' => $issuer, 'type' => $type]);
$mform = new \tool_oauth2\form\issuer(null, ['persistent' => $issuer, 'type' => $type,
'showrequireconfirm' => $showrequireconfirm]);
echo $OUTPUT->header();
$mform->display();
@@ -178,26 +197,37 @@ if ($mform && $mform->is_cancelled()) {
$issuers = core\oauth2\api::get_all_issuers();
echo $renderer->issuers_table($issuers);
// Google template.
$docs = 'admin/tool/oauth2/issuers/google';
$params = ['action' => 'edittemplate', 'type' => 'google', 'sesskey' => sesskey(), 'docslink' => $docs];
$params = ['action' => 'edittemplate', 'type' => 'google', 'sesskey' => sesskey(), 'docslink' => $docs,
'showrequireconfirm' => true];
$addurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params);
echo $renderer->single_button($addurl, get_string('createnewgoogleissuer', 'tool_oauth2'));
// Microsoft template.
$docs = 'admin/tool/oauth2/issuers/microsoft';
$params = ['action' => 'edittemplate', 'type' => 'microsoft', 'sesskey' => sesskey(), 'docslink' => $docs];
$params = ['action' => 'edittemplate', 'type' => 'microsoft', 'sesskey' => sesskey(), 'docslink' => $docs,
'showrequireconfirm' => true];
$addurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params);
echo $renderer->single_button($addurl, get_string('createnewmicrosoftissuer', 'tool_oauth2'));
// Facebook template.
$docs = 'admin/tool/oauth2/issuers/facebook';
$params = ['action' => 'edittemplate', 'type' => 'microsoft', 'sesskey' => sesskey(), 'docslink' => $docs];
$params = ['action' => 'edittemplate', 'type' => 'facebook', 'sesskey' => sesskey(), 'docslink' => $docs];
$params = ['action' => 'edittemplate', 'type' => 'facebook', 'sesskey' => sesskey(), 'docslink' => $docs,
'showrequireconfirm' => true];
$addurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params);
echo $renderer->single_button($addurl, get_string('createnewfacebookissuer', 'tool_oauth2'));
$addurl = new moodle_url('/admin/tool/oauth2/issuers.php', ['action' => 'edit']);
// Nextcloud template.
$docs = 'admin/tool/oauth2/issuers/nextcloud';
$params = ['action' => 'edittemplate', 'type' => 'nextcloud', 'sesskey' => sesskey(), 'docslink' => $docs];
$addurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params);
echo $renderer->single_button($addurl, get_string('createnewnextcloudissuer', 'tool_oauth2'));
// Generic issuer.
$addurl = new moodle_url('/admin/tool/oauth2/issuers.php', ['action' => 'edit']);
echo $renderer->single_button($addurl, get_string('createnewissuer', 'tool_oauth2'));
echo $OUTPUT->footer();
}
+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)';
+1 -1
View File
@@ -257,7 +257,7 @@ class manager {
'title' => get_string('importtour', 'tool_usertours'),
],
(object) [
'link' => new \moodle_url('https://moodle.net/tours'),
'link' => new \moodle_url('https://archive.moodle.net/tours'),
'linkproperties' => [
'target' => '_blank',
],
+1 -1
View File
@@ -198,7 +198,7 @@ abstract class base extends \core_analytics\calculable {
$message->component = 'moodle';
$message->name = 'insights';
$message->userfrom = \core_user::get_noreply_user();
$message->userfrom = \core_user::get_support_user();
$message->userto = $user;
$insighturl = new \moodle_url('/report/insights/insights.php?modelid=' . $modelid . '&contextid=' . $context->id);
+43 -26
View File
@@ -547,45 +547,62 @@ class manager {
public static function cleanup() {
global $DB;
// Clean up stuff that depends on contexts that do not exist anymore.
$sql = "SELECT DISTINCT ap.contextid FROM {analytics_predictions} ap
LEFT JOIN {context} ctx ON ap.contextid = ctx.id
WHERE ctx.id IS NULL";
$apcontexts = $DB->get_records_sql($sql);
$DB->execute("DELETE FROM {analytics_prediction_actions} WHERE predictionid IN
(SELECT ap.id FROM {analytics_predictions} ap
LEFT JOIN {context} ctx ON ap.contextid = ctx.id
WHERE ctx.id IS NULL)");
$sql = "SELECT DISTINCT aic.contextid FROM {analytics_indicator_calc} aic
LEFT JOIN {context} ctx ON aic.contextid = ctx.id
WHERE ctx.id IS NULL";
$indcalccontexts = $DB->get_records_sql($sql);
$contexts = $apcontexts + $indcalccontexts;
if ($contexts) {
list($sql, $params) = $DB->get_in_or_equal(array_keys($contexts));
$DB->execute("DELETE FROM {analytics_prediction_actions} WHERE predictionid IN
(SELECT ap.id FROM {analytics_predictions} ap WHERE ap.contextid $sql)", $params);
$DB->delete_records_select('analytics_predictions', "contextid $sql", $params);
$DB->delete_records_select('analytics_indicator_calc', "contextid $sql", $params);
}
$contextsql = "SELECT id FROM {context} ctx";
$DB->delete_records_select('analytics_predictions', "contextid NOT IN ($contextsql)");
$DB->delete_records_select('analytics_indicator_calc', "contextid NOT IN ($contextsql)");
// Clean up stuff that depends on analysable ids that do not exist anymore.
$models = self::get_all_models();
foreach ($models as $model) {
// We first dump into memory the list of analysables we have in the database (we could probably do this with 1 single
// query for the 3 tables, but it may be safer to do it separately).
$predictsamplesanalysableids = $DB->get_fieldset_select('analytics_predict_samples', 'DISTINCT analysableid',
'modelid = :modelid', ['modelid' => $model->get_id()]);
$predictsamplesanalysableids = array_flip($predictsamplesanalysableids);
$trainsamplesanalysableids = $DB->get_fieldset_select('analytics_train_samples', 'DISTINCT analysableid',
'modelid = :modelid', ['modelid' => $model->get_id()]);
$trainsamplesanalysableids = array_flip($trainsamplesanalysableids);
$usedanalysablesanalysableids = $DB->get_fieldset_select('analytics_used_analysables', 'DISTINCT analysableid',
'modelid = :modelid', ['modelid' => $model->get_id()]);
$usedanalysablesanalysableids = array_flip($usedanalysablesanalysableids);
$analyser = $model->get_analyser(array('notimesplitting' => true));
$analysables = $analyser->get_analysables();
if (!$analysables) {
continue;
}
$analysableids = array_map(function($analysable) {
return $analysable->get_id();
}, $analysables);
foreach ($analysables as $analysable) {
unset($predictsamplesanalysableids[$analysable->get_id()]);
unset($trainsamplesanalysableids[$analysable->get_id()]);
unset($usedanalysablesanalysableids[$analysable->get_id()]);
}
list($notinsql, $params) = $DB->get_in_or_equal($analysableids, SQL_PARAMS_NAMED, 'param', false);
$params['modelid'] = $model->get_id();
$param = ['modelid' => $model->get_id()];
$DB->delete_records_select('analytics_predict_samples', "modelid = :modelid AND analysableid $notinsql", $params);
$DB->delete_records_select('analytics_train_samples', "modelid = :modelid AND analysableid $notinsql", $params);
if ($predictsamplesanalysableids) {
list($idssql, $idsparams) = $DB->get_in_or_equal(array_flip($predictsamplesanalysableids), SQL_PARAMS_NAMED);
$DB->delete_records_select('analytics_predict_samples', "modelid = :modelid AND analysableid $idssql",
$param + $idsparams);
}
if ($trainsamplesanalysableids) {
list($idssql, $idsparams) = $DB->get_in_or_equal(array_flip($trainsamplesanalysableids), SQL_PARAMS_NAMED);
$DB->delete_records_select('analytics_train_samples', "modelid = :modelid AND analysableid $idssql",
$param + $idsparams);
}
if ($usedanalysablesanalysableids) {
list($idssql, $idsparams) = $DB->get_in_or_equal(array_flip($usedanalysablesanalysableids), SQL_PARAMS_NAMED);
$DB->delete_records_select('analytics_used_analysables', "modelid = :modelid AND analysableid $idssql",
$param + $idsparams);
}
}
}
+61 -3
View File
@@ -923,7 +923,7 @@ class model {
}
// Get all samples data.
list($sampleids, $samplesdata) = $this->get_analyser()->get_samples($sampleids);
list($sampleids, $samplesdata) = $this->get_samples($sampleids);
// Calculate the targets.
$predictions = array();
@@ -1233,7 +1233,7 @@ class model {
return $prediction->sampleid;
}, $predictions);
list($unused, $samplesdata) = $this->get_analyser()->get_samples($sampleids);
list($unused, $samplesdata) = $this->get_samples($sampleids);
$current = 0;
@@ -1275,7 +1275,7 @@ class model {
*/
public function prediction_sample_data($predictionobj) {
list($unused, $samplesdata) = $this->get_analyser()->get_samples(array($predictionobj->sampleid));
list($unused, $samplesdata) = $this->get_samples(array($predictionobj->sampleid));
if (empty($samplesdata[$predictionobj->sampleid])) {
throw new \moodle_exception('errorsamplenotavailable', 'analytics');
@@ -1533,6 +1533,64 @@ class model {
$DB->update_record('analytics_models', $this->model);
}
/**
* Wrapper around analyser's get_samples to skip DB's max-number-of-params exception.
*
* @param array $sampleids
* @return array
*/
public function get_samples(array $sampleids): array {
if (empty($sampleids)) {
throw new \coding_exception('No sample ids provided');
}
$chunksize = count($sampleids);
// We start with just 1 chunk, if it is too large for the db we split the list of sampleids in 2 and we
// try again. We repeat this process until the chunk is small enough for the db engine to process. The
// >= has been added in case there are other \dml_read_exceptions unrelated to the max number of params.
while (empty($done) && $chunksize >= 1) {
$chunks = array_chunk($sampleids, $chunksize);
$allsampleids = [];
$allsamplesdata = [];
foreach ($chunks as $index => $chunk) {
try {
list($chunksampleids, $chunksamplesdata) = $this->get_analyser()->get_samples($chunk);
} catch (\dml_read_exception $e) {
// Reduce the chunksize, we use floor() so the $chunksize is always less than the previous $chunksize value.
$chunksize = floor($chunksize / 2);
break;
}
// We can sum as these two arrays are indexed by sampleid and there are no collisions.
$allsampleids = $allsampleids + $chunksampleids;
$allsamplesdata = $allsamplesdata + $chunksamplesdata;
if ($index === count($chunks) - 1) {
// We successfully processed all the samples in all chunks, we are done.
$done = true;
}
}
}
if (empty($done)) {
if (!empty($e)) {
// Throw the last exception we caught, the \dml_read_exception we have been catching is unrelated to the max number
// of param's exception.
throw new \dml_read_exception($e);
} else {
throw new \coding_exception('We should never reach this point, there is a bug in ' .
'core_analytics\\model::get_samples\'s code');
}
}
return [$allsampleids, $allsamplesdata];
}
/**
* Purges the insights cache.
*/
+2 -6
View File
@@ -306,13 +306,9 @@ class provider implements
$idssql = "SELECT ap.id FROM {analytics_predictions} ap
WHERE ap.contextid = :contextid AND ap.modelid = :modelid";
$idsparams = ['contextid' => $context->id, 'modelid' => $modelid];
$predictionids = $DB->get_fieldset_sql($idssql, $idsparams);
if ($predictionids) {
list($predictionidssql, $params) = $DB->get_in_or_equal($predictionids, SQL_PARAMS_NAMED);
$DB->delete_records_select('analytics_prediction_actions', "predictionid IN ($idssql)", $idsparams);
$DB->delete_records_select('analytics_predictions', "id $predictionidssql", $params);
}
$DB->delete_records_select('analytics_prediction_actions', "predictionid IN ($idssql)", $idsparams);
$DB->delete_records_select('analytics_predictions', "contextid = :contextid AND modelid = :modelid", $idsparams);
}
// We delete them all this table is just a cache and we don't know which model filled it.
+4 -2
View File
@@ -134,8 +134,9 @@ class analytics_manager_testcase extends advanced_testcase {
$model->train();
$model->predict();
$npredictsamples = $DB->count_records('analytics_predict_samples');
$ntrainsamples = $DB->count_records('analytics_train_samples');
$this->assertNotEmpty($DB->count_records('analytics_predict_samples'));
$this->assertNotEmpty($DB->count_records('analytics_train_samples'));
$this->assertNotEmpty($DB->count_records('analytics_used_analysables'));
// Now we delete an analysable, stored predict and training samples should be deleted.
$deletedcontext = \context_course::instance($coursepredict1->id);
@@ -145,6 +146,7 @@ class analytics_manager_testcase extends advanced_testcase {
$this->assertEmpty($DB->count_records('analytics_predict_samples', array('analysableid' => $coursepredict1->id)));
$this->assertEmpty($DB->count_records('analytics_train_samples', array('analysableid' => $coursepredict1->id)));
$this->assertEmpty($DB->count_records('analytics_used_analysables', array('analysableid' => $coursepredict1->id)));
set_config('enabled_stores', '', 'tool_log');
get_log_manager(true);
+53
View File
@@ -341,6 +341,59 @@ class analytics_model_testcase extends advanced_testcase {
$this->assertLessThanOrEqual(2, $DB->count_records('analytics_used_analysables', $params));
}
/**
* Tests model::get_samples()
*
* @return null
*/
public function test_get_samples() {
$this->resetAfterTest();
if (!PHPUNIT_LONGTEST) {
$this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
}
// 10000 should be enough to make oracle and mssql fail, if we want pgsql to fail we need around 70000
// users, that is a few minutes just to create the users.
$nusers = 10000;
$userids = [];
for ($i = 0; $i < $nusers; $i++) {
$user = $this->getDataGenerator()->create_user();
$userids[] = $user->id;
}
$target = \core_analytics\manager::get_target('test_target_site_users');
$indicator = \core_analytics\manager::get_indicator('test_indicator_max');
$model = \core_analytics\model::create($target, ['test_indicator_max' => $indicator],
'\core\analytics\time_splitting\single_range');
list($sampleids, $samplesdata) = $model->get_samples($userids);
$this->assertCount($nusers, $sampleids);
$this->assertCount($nusers, $samplesdata);
$subset = array_slice($userids, 0, 100);
list($sampleids, $samplesdata) = $model->get_samples($subset);
$this->assertCount(100, $sampleids);
$this->assertCount(100, $samplesdata);
$subset = array_slice($userids, 0, 2);
list($sampleids, $samplesdata) = $model->get_samples($subset);
$this->assertCount(2, $sampleids);
$this->assertCount(2, $samplesdata);
$subset = array_slice($userids, 0, 1);
list($sampleids, $samplesdata) = $model->get_samples($subset);
$this->assertCount(1, $sampleids);
$this->assertCount(1, $samplesdata);
// Unexisting, so nothing returned, but still 2 arrays.
list($sampleids, $samplesdata) = $model->get_samples([1231231231231231]);
$this->assertEmpty($sampleids);
$this->assertEmpty($samplesdata);
}
/**
* Generates a model log record.
*/
+1 -2
View File
@@ -402,7 +402,6 @@ class api {
* @return bool
*/
public static function is_enabled() {
$plugininfo = \core_plugin_manager::instance()->get_plugin_info('auth_oauth2');
return $plugininfo->is_enabled();
return is_enabled_auth('oauth2');
}
}
+34
View File
@@ -50,5 +50,39 @@ function xmldb_auth_oauth2_upgrade($oldversion) {
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2018120301) {
// Fetch Facebook, Google, and Microsoft issuers. We use the URL field to determine the issuer type as it's the only
// field that contains the keyword that can somewhat let us reliably determine the issuer type.
$likefacebook = $DB->sql_like('oe.url', ':facebook');
$likegoogle = $DB->sql_like('oe.url', ':google');
$likemicrosoft = $DB->sql_like('oe.url', ':microsoft');
$params = [
'facebook' => '%facebook%',
'google' => '%google%',
'microsoft' => '%microsoft%',
];
// We're querying from the oauth2_endpoint table because the base URLs of FB and Microsoft can be empty in the issuer table.
$subsql = "
SELECT DISTINCT oe.issuerid
FROM {oauth2_endpoint} oe
WHERE $likefacebook
OR $likegoogle
OR $likemicrosoft";
// Update non-Facebook/Google/Microsoft issuers and set requireconfirmation to 1.
$updatesql = "
UPDATE {oauth2_issuer}
SET requireconfirmation = 1
WHERE id NOT IN ({$subsql})";
$DB->execute($updatesql, $params);
// Delete linked logins for non-Facebook/Google/Microsoft issuers. They can easily re-link their logins anyway.
$DB->delete_records_select('auth_oauth2_linked_login', "issuerid NOT IN ($subsql)", $params);
upgrade_plugin_savepoint(true, 2018120301, 'auth', 'oauth2');
}
return true;
}
+8 -2
View File
@@ -40,7 +40,10 @@ then cut and paste the address into the address
line at the top of your web browser window.
If you need help, please contact the site administrator,
{$a->admin}';
{$a->admin}
If you did not do this, someone else could be trying to compromise your account.
Please contact the site administrator immediately.';
$string['confirmaccountemailsubject'] = '{$a}: account confirmation';
$string['confirmationinvalid'] = 'The confirmation link is either invalid, or has expired. Please start the login process again to generate a new confirmation email.';
$string['confirmationpending'] = 'This account is pending email confirmation.';
@@ -60,7 +63,10 @@ then cut and paste the address into the address
line at the top of your web browser window.
If you need help, please contact the site administrator,
{$a->admin}';
{$a->admin}
If you did not do this, someone else could be trying to compromise your account.
Please contact the site administrator immediately.';
$string['confirmlinkedloginemailsubject'] = '{$a}: linked login confirmation';
$string['createaccountswarning'] = 'This authentication plugin allows users to create accounts on your site. You may want to enable the setting "authpreventaccountcreation" if you use this plugin.';
$string['createnewlinkedlogin'] = 'Link a new account ({$a})';
+19
View File
@@ -140,4 +140,23 @@ class auth_oauth2_external_testcase extends advanced_testcase {
$this->assertEquals($newuser->id, $match->get('userid'));
}
/**
* Test that is_enabled correctly identifies when the plugin is enabled.
*/
public function test_is_enabled() {
$this->resetAfterTest();
set_config('auth', 'manual,oauth2');
$this->assertTrue(\auth_oauth2\api::is_enabled());
}
/**
* Test that is_enabled correctly identifies when the plugin is disabled.
*/
public function test_is_enabled_disabled() {
$this->resetAfterTest();
set_config('auth', 'manual');
$this->assertFalse(\auth_oauth2\api::is_enabled());
}
}
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018120300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2018120301; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2018112800; // Requires this Moodle version.
$plugin->component = 'auth_oauth2'; // Full name of the plugin (used for diagnostics).
+13 -6
View File
@@ -294,12 +294,19 @@ class auth_plugin_shibboleth extends auth_plugin_base {
}
$url = new moodle_url('/auth/shibboleth/index.php');
$iconurl = moodle_url::make_pluginfile_url(context_system::instance()->id,
'auth_shibboleth',
'logo',
null,
'/',
$config->auth_logo);
if ($config->auth_logo) {
$iconurl = moodle_url::make_pluginfile_url(
context_system::instance()->id,
'auth_shibboleth',
'logo',
null,
null,
$config->auth_logo);
} else {
$iconurl = null;
}
$result[] = ['url' => $url, 'iconurl' => $iconurl, 'name' => $config->login_name];
return $result;
}
+10 -2
View File
@@ -42,10 +42,18 @@ class behat_auth extends behat_base {
* Logs in the user. There should exist a user with the same value as username and password.
*
* @Given /^I log in as "(?P<username_string>(?:[^"]|\\")*)"$/
* @param string $username the user to log in as.
* @param moodle_url|null $wantsurl optional, URL to go to after logging in.
*/
public function i_log_in_as($username) {
public function i_log_in_as(string $username, moodle_url $wantsurl = null) {
$loginurl = new moodle_url('/login/index.php');
if ($wantsurl !== null) {
$loginurl->param('wantsurl', $wantsurl->out_as_local_url());
}
// Visit login page.
$this->getSession()->visit($this->locate_path('login/index.php'));
$this->getSession()->visit($this->locate_path($loginurl->out_as_local_url()));
// Enter username and password.
$this->execute('behat_forms::i_set_the_field_to', array('Username', $this->escape($username)));
+19 -6
View File
@@ -98,8 +98,14 @@ class core_badges_assertion {
if ($this->_data) {
$hash = $this->_data->uniquehash;
$email = empty($this->_data->backpackemail) ? $this->_data->email : $this->_data->backpackemail;
$assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash));
$classurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'action' => 1));
$assertionurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion));
if ($this->_obversion == OPEN_BADGES_V2) {
$badgeid = $this->_data ? $this->_data->id : 0;
$classurl = new moodle_url('/badges/badge_json.php', array('id' => $badgeid));
} else {
$classurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'action' => 1));
}
// Required.
$assertion['uid'] = $hash;
@@ -136,13 +142,19 @@ class core_badges_assertion {
} else {
$context = context_course::instance($this->_data->courseid);
}
$issuerurl = new moodle_url('/badges/assertion.php', array('b' => $this->_data->uniquehash, 'action' => 0));
// Required.
$class['name'] = $this->_data->name;
$class['description'] = $this->_data->description;
$class['image'] = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $this->_data->id, '/', 'f1')->out(false);
$class['criteria'] = $this->_url->out(false); // Currently issued badge URL.
if ($this->_obversion == OPEN_BADGES_V2) {
$badgeid = $this->_data ? $this->_data->id : 0;
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $badgeid, 'action' => 0));
} else {
$issuerurl = new moodle_url('/badges/assertion.php', array('b' => $this->_data->uniquehash, 'action' => 0));
}
$class['issuer'] = $issuerurl->out(false);
$this->embed_data_badge_version2($class, OPEN_BADGES_V2_TYPE_BADGE);
}
@@ -265,12 +277,13 @@ class core_badges_assertion {
}
$hash = $this->_data->uniquehash;
$badgeid = $this->_data ? $this->_data->id : 0;
$assertionsurl = new moodle_url('/badges/assertion.php', array('b' => $hash, 'obversion' => $this->_obversion));
$classurl = new moodle_url(
'/badges/assertion.php',
array('b' => $hash, 'action' => 1, 'obversion' => $this->_obversion)
'/badges/badge_json.php',
array('id' => $badgeid)
);
$issuerurl = new moodle_url('/badges/assertion.php', array('b' => $this->_data->uniquehash, 'action' => 0,
$issuerurl = new moodle_url('/badges/badge_json.php', array('id' => $badgeid, 'action' => 0,
'obversion' => $this->_obversion));
// For assertion.
if ($type == OPEN_BADGES_V2_TYPE_ASSERTION) {
+58
View File
@@ -0,0 +1,58 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file keeps track of upgrades to the myoverview block
* @since 3.6.7
* @package block_myoverview
* @copyright 2019 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Upgrade code for the MyOverview block.
*
* @param int $oldversion
*/
function xmldb_block_myoverview_upgrade($oldversion) {
global $DB;
if ($oldversion < 2018120301) {
// Remove orphaned course favourites, which weren't being deleted when the course was deleted.
$sql = 'SELECT f.id
FROM {favourite} f
LEFT JOIN {course} c
ON (c.id = f.itemid)
WHERE f.component = :component
AND f.itemtype = :itemtype
AND c.id IS NULL';
$params = ['component' => 'core_course', 'itemtype' => 'courses'];
if ($records = $DB->get_fieldset_sql($sql, $params)) {
$chunks = array_chunk($records, 1000);
foreach ($chunks as $chunk) {
list($insql, $inparams) = $DB->get_in_or_equal($chunk);
$DB->delete_records_select('favourite', "id $insql", $inparams);
}
}
upgrade_block_savepoint(true, 2018120301, 'myoverview', false);
}
return true;
}
@@ -35,7 +35,7 @@ $string['aria:displaydropdown'] = 'Display drop-down menu';
$string['aria:favourites'] = 'Show starred courses';
$string['aria:future'] = 'Show future courses';
$string['aria:groupingdropdown'] = 'Grouping drop-down menu';
$string['aria:inprogress'] = 'Show in courses in progress';
$string['aria:inprogress'] = 'Show courses in progress';
$string['aria:lastaccessed'] = 'Sort courses by last accessed date';
$string['aria:list'] = 'Switch to list view';
$string['aria:title'] = 'Sort courses by course name';
+11
View File
@@ -115,3 +115,14 @@ function block_myoverview_user_preferences() {
return $preferences;
}
/**
* Pre-delete course hook to cleanup any records with references to the deleted course.
*
* @param stdClass $course The deleted course
*/
function block_myoverview_pre_course_delete(\stdClass $course) {
// Removing any starred courses which have been created for users, for this course.
global $DB;
$DB->delete_records('favourite', ['component' => 'core_course', 'itemtype' => 'courses', 'itemid' => $course->id]);
}
@@ -28,7 +28,8 @@
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"hasprogress": true,
"progress": 10
"progress": 10,
"visible": true
}
]
}
+21 -13
View File
@@ -28,7 +28,8 @@
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"hasprogress": true,
"progress": 10
"progress": 10,
"visible": true
}
]
}
@@ -41,21 +42,28 @@
data-course-id="{{{id}}}">
<div class="row-fluid">
<div class="{{#hasprogress}}col-md-6 span6{{/hasprogress}}{{^hasprogress}}col-md-11 span11{{/hasprogress}} d-flex align-items-center">
<a href="{{viewurl}}" class="coursename">
{{#showshortname}}
<div>
<a href="{{viewurl}}" class="coursename">
{{#showshortname}}
<span class="sr-only">
{{#str}}aria:courseshortname, core_course{{/str}}
</span>
<div class="text-muted muted">
{{{shortname}}}
</div>
{{/showshortname}}
{{> core_course/favouriteicon }}
<span class="sr-only">
{{#str}}aria:courseshortname, core_course{{/str}}
{{#str}}aria:coursename, core_course{{/str}}
</span>
<div class="text-muted muted">
{{{shortname}}}
{{{fullname}}}
</a>
{{^visible}}
<div class="hiddenmessage">
<span class="badge badge-info">{{#str}} hiddenfromstudents {{/str}}</span>
</div>
{{/showshortname}}
{{> core_course/favouriteicon }}
<span class="sr-only">
{{#str}}aria:coursename, core_course{{/str}}
</span>
{{{fullname}}}
</a>
{{/visible}}
</div>
</div>
{{#hasprogress}}
<div class="col-md-5 span5 pt-1">
@@ -29,7 +29,8 @@
"fullname": "course 3",
"summary": "This course is about assignments",
"hasprogress": true,
"progress": 10
"progress": 10,
"visible": true
}
]
}
@@ -48,21 +49,28 @@
<div class="align-self-stretch d-flex flex-column w-100">
<div class="d-flex mb-1">
<a href="{{viewurl}}" class="coursename">
{{#showshortname}}
<div>
<a href="{{viewurl}}" class="coursename">
{{#showshortname}}
<span class="sr-only">
{{#str}}aria:courseshortname, core_course{{/str}}
</span>
<div class="text-muted muted mb-1">
{{{shortname}}}
</div>
{{/showshortname}}
{{> core_course/favouriteicon }}
<span class="sr-only">
{{#str}}aria:courseshortname, core_course{{/str}}
{{#str}}aria:coursename, core_course{{/str}}
</span>
<div class="text-muted muted mb-1">
{{{shortname}}}
<h6 class="d-inline h5">{{{fullname}}}</h6>
</a>
{{^visible}}
<div class="hiddenmessage">
<span class="badge badge-info">{{#str}} hiddenfromstudents {{/str}}</span>
</div>
{{/showshortname}}
{{> core_course/favouriteicon }}
<span class="sr-only">
{{#str}}aria:coursename, core_course{{/str}}
</span>
<h6 class="d-inline h5">{{{fullname}}}</h6>
</a>
{{/visible}}
</div>
{{> block_myoverview/course-action-menu }}
</div>
<div class="summary">
@@ -78,4 +86,4 @@
</div>
</div>
{{/courses}}
</div>
</div>
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018120300; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2018120301; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2018112800; // Requires this Moodle version.
$plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics).
@@ -114,12 +114,8 @@ class behat_block_site_main_menu extends behat_base {
protected function get_site_menu_activity_element($element, $selectortype, $activityname) {
$activitynode = $this->get_site_menu_activity_node($activityname);
// Transforming to Behat selector/locator.
list($selector, $locator) = $this->transform_selector($selectortype, $element);
$exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' .
$selectortype . '" in "' . $activityname . '" ');
return $this->find($selector, $locator, $exception, $activitynode);
$exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'");
return $this->find($selectortype, $element, $exception, $activitynode);
}
/**
@@ -56,7 +56,11 @@ class behat_block_social_activities extends behat_base {
}
/**
* Checks that the specified activity's action menu contains an item.
* Checks that the specified activity in the social activities block should have the specified editing icon.
*
* This includes items in the action menu for the item (does not require it to be open)
*
* You should be in the course page with editing mode turned on.
*
* @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should have "(?P<icon_name_string>(?:[^"]|\\")*)" editing icon$/
* @param string $activityname
@@ -71,7 +75,11 @@ class behat_block_social_activities extends behat_base {
}
/**
* Checks that the specified activity's action menu contains an item.
* Checks that the specified activity in the social activities block should not have the specified editing icon.
*
* This includes items in the action menu for the item (does not require it to be open)
*
* You should be in the course page with editing mode turned on.
*
* @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should not have "(?P<icon_name_string>(?:[^"]|\\")*)" editing icon$/
* @param string $activityname
@@ -103,7 +111,7 @@ class behat_block_social_activities extends behat_base {
}
/**
* Clicks on the specified element inside the activity container.
* Finds the element containing a specific activity in the social activity block.
*
* @throws ElementNotFoundException
* @param string $element
@@ -114,16 +122,12 @@ class behat_block_social_activities extends behat_base {
protected function get_social_block_activity_element($element, $selectortype, $activityname) {
$activitynode = $this->get_social_block_activity_node($activityname);
// Transforming to Behat selector/locator.
list($selector, $locator) = $this->transform_selector($selectortype, $element);
$exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' .
$selectortype . '" in "' . $activityname . '" ');
return $this->find($selector, $locator, $exception, $activitynode);
$exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'");
return $this->find($selectortype, $element, $exception, $activitynode);
}
/**
* Checks that the specified activity is hidden.
* Checks that the specified activity is hidden in the social activities block.
*
* @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should be hidden$/
* @param string $activityname
@@ -133,7 +137,7 @@ class behat_block_social_activities extends behat_base {
}
/**
* Checks that the specified activity is hidden.
* Checks that the specified activity is hidden in the social activities block.
*
* @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" activity in social activities block should be available but hidden from course page$/
* @param string $activityname
@@ -143,7 +147,7 @@ class behat_block_social_activities extends behat_base {
}
/**
* Opens an activity actions menu if it is not already opened.
* Opens an activity actions menu in the social activities block if it is not already opened.
*
* @Given /^I open "(?P<activity_name_string>(?:[^"]|\\")*)" actions menu in social activities block$/
* @throws DriverException The step is not available when Javascript is disabled
+9 -4
View File
@@ -88,13 +88,18 @@ class block_starredcourses_external extends core_course_external {
return ($a->timemodified > $b->timemodified) ? -1 : 1;
});
$formattedcourses = array_map(function($favourite) use ($renderer) {
$formattedcourses = array();
foreach ($favourites as $favourite) {
$course = get_course($favourite->itemid);
$context = \context_course::instance($favourite->itemid);
$canviewhiddencourses = has_capability('moodle/course:viewhiddencourses', $context);
$exporter = new course_summary_exporter($course, ['context' => $context, 'isfavourite' => true]);
return $exporter->export($renderer);
}, $favourites);
if ($course->visible || $canviewhiddencourses) {
$exporter = new course_summary_exporter($course, ['context' => $context, 'isfavourite' => true]);
$formattedcourse = $exporter->export($renderer);
$formattedcourses[] = $formattedcourse;
}
}
return $formattedcourses;
}
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/notification","core/templates","core/paged_content_factory","core/str","core/user_date","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f,g){var h=86400,i={EMPTY_MESSAGE:'[data-region="empty-message"]',ROOT:'[data-region="event-list-container"]',EVENT_LIST_CONTENT:'[data-region="event-list-content"]',EVENT_LIST_LOADING_PLACEHOLDER:'[data-region="event-list-loading-placeholder"]'},j={EVENT_LIST_CONTENT:"block_timeline/event-list-content"},k={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,ariaLabels:{itemsperpagecomponents:"ariaeventlistpagelimit, block_timeline"}},l=function(a){a.find(i.EVENT_LIST_CONTENT).addClass("hidden"),a.find(i.EMPTY_MESSAGE).removeClass("hidden")},m=function(a){a.find(i.EVENT_LIST_CONTENT).removeClass("hidden"),a.find(i.EMPTY_MESSAGE).addClass("hidden")},n=function(a){a.find(i.EVENT_LIST_CONTENT).empty()},o=function(a,b){var c={},d={eventsbyday:[]};return a.forEach(function(a){var d=f.getUserMidnightForTimestamp(a.timesort,b);c[d]?c[d].push(a):c[d]=[a]}),Object.keys(c).forEach(function(a){var e=c[a];d.eventsbyday.push({past:a<b,dayTimestamp:a,events:e})}),d},p=function(a,b){var d=o(a,b),e=j.EVENT_LIST_CONTENT;return c.render(e,d)},q=function(a,b,c,d,e,f){var i=a+c*h,j=void 0!=d&&a+d*h,k={starttime:i,limit:b};return e&&(k.aftereventid=e),j&&(k.endtime=j),f?(k.courseid=f,g.queryByCourse(k)):g.queryByTime(k)},r=function(a,b,c,d,e,f,g,h){for(var i=a.pageNumber,j=a.limit,k=i;!d.hasOwnProperty(k);)k--;var l=d[k],m=null;return m=e&&e.hasOwnProperty(i)?e[i]:q(c,j+1,g,h,l,f),m.then(function(a){if(!a.events.length)return b.allItemsLoaded(i),[];var c=a.events,d=c.length<=j;return d?b.allItemsLoaded(i):c.pop(),c})},s=function(c,f,g,h,i,j,l,m,n){var o={1:0},q=!1,s=a.extend({},k,n);return e.get_string("ariaeventlistpagelimit","block_timeline",a.isArray(c)?c[0].value:c).then(function(a){return s.ariaLabels.itemsperpage=a,s.ariaLabels.paginationnav=m,a}).then(function(){return d.createWithLimit(c,function(c,d){var e=[];return c.forEach(function(a){var c=a.pageNumber,h=r(a,d,g,o,f,i,j,l).then(function(a){if(a.length){q=!0;var b=a[a.length-1].id;return o[c+1]=b,p(a,g)}return a})["catch"](b.exception);e.push(h)}),a.when.apply(a,e).then(function(){h.resolve(q)})["catch"](function(){h.resolve(q)}),e},s)})},t=function(d,e,f,g,h){d=a(d);var j=a.Deferred(),k=d.find(i.EVENT_LIST_CONTENT),o=d.find(i.EVENT_LIST_LOADING_PLACEHOLDER),p=d.attr("data-course-id"),q=parseInt(d.attr("data-days-offset"),10),r=d.attr("data-days-limit"),t=parseInt(d.attr("data-midnight"),10);return n(d),m(d),o.removeClass("hidden"),void 0!=r&&(r=parseInt(r,10)),s(e,f,t,j,p,q,r,g,h).then(function(b,e){return b=a(b),b.addClass("hidden"),c.replaceNodeContents(k,b,e),j.then(function(a){return b.removeClass("hidden"),o.addClass("hidden"),a||l(d),a})["catch"](function(){return!1}),b})["catch"](b.exception)};return{init:t,rootSelector:i.ROOT}});
define(["jquery","core/notification","core/templates","core/paged_content_factory","core/str","core/user_date","block_timeline/calendar_events_repository"],function(a,b,c,d,e,f,g){var h=86400,i={EMPTY_MESSAGE:'[data-region="empty-message"]',ROOT:'[data-region="event-list-container"]',EVENT_LIST_CONTENT:'[data-region="event-list-content"]',EVENT_LIST_LOADING_PLACEHOLDER:'[data-region="event-list-loading-placeholder"]'},j={EVENT_LIST_CONTENT:"block_timeline/event-list-content"},k={ignoreControlWhileLoading:!0,controlPlacementBottom:!0,ariaLabels:{itemsperpagecomponents:"ariaeventlistpagelimit, block_timeline"}},l=function(a){a.find(i.EVENT_LIST_CONTENT).addClass("hidden"),a.find(i.EMPTY_MESSAGE).removeClass("hidden")},m=function(a){a.find(i.EVENT_LIST_CONTENT).removeClass("hidden"),a.find(i.EMPTY_MESSAGE).addClass("hidden")},n=function(a){a.find(i.EVENT_LIST_CONTENT).empty()},o=function(a,b){var c={},d={eventsbyday:[]};return a.forEach(function(a){var d=f.getUserMidnightForTimestamp(a.timesort,b);c[d]?c[d].push(a):c[d]=[a]}),Object.keys(c).forEach(function(a){var e=c[a];d.eventsbyday.push({past:a<b,dayTimestamp:a,events:e})}),d},p=function(a,b){var d=o(a,b),e=j.EVENT_LIST_CONTENT;return c.render(e,d)},q=function(a,b,c,d,e,f){var i=a+c*h,j=void 0!=d&&a+d*h,k={starttime:i,limit:b};return e&&(k.aftereventid=e),j&&(k.endtime=j),f?(k.courseid=f,g.queryByCourse(k)):g.queryByTime(k)},r=function(a,b,c,d,e,f,g,h){for(var i=a.pageNumber,j=a.limit,k=i;!d.hasOwnProperty(k);)k--;var l=d[k],m=null;return m=e&&e.hasOwnProperty(i)?e[i]:q(c,j+1,g,h,l,f),m.then(function(a){if(!a.events.length)return b.allItemsLoaded(i),[];var c=a.events.filter(function(a){return"open"!=a.eventtype&&"opensubmission"!=a.eventtype}),d=c.length<=j;return d?b.allItemsLoaded(i):c.pop(),c})},s=function(c,f,g,h,i,j,l,m,n){var o={1:0},q=!1,s=a.extend({},k,n);return e.get_string("ariaeventlistpagelimit","block_timeline",a.isArray(c)?c[0].value:c).then(function(a){return s.ariaLabels.itemsperpage=a,s.ariaLabels.paginationnav=m,a}).then(function(){return d.createWithLimit(c,function(c,d){var e=[];return c.forEach(function(a){var c=a.pageNumber,h=r(a,d,g,o,f,i,j,l).then(function(a){if(a.length){q=!0;var b=a[a.length-1].id;return o[c+1]=b,p(a,g)}return a})["catch"](b.exception);e.push(h)}),a.when.apply(a,e).then(function(){h.resolve(q)})["catch"](function(){h.resolve(q)}),e},s)})},t=function(d,e,f,g,h){d=a(d);var j=a.Deferred(),k=d.find(i.EVENT_LIST_CONTENT),o=d.find(i.EVENT_LIST_LOADING_PLACEHOLDER),p=d.attr("data-course-id"),q=parseInt(d.attr("data-days-offset"),10),r=d.attr("data-days-limit"),t=parseInt(d.attr("data-midnight"),10);return n(d),m(d),o.removeClass("hidden"),void 0!=r&&(r=parseInt(r,10)),s(e,f,t,j,p,q,r,g,h).then(function(b,e){return b=a(b),b.addClass("hidden"),c.replaceNodeContents(k,b,e),j.then(function(a){return b.removeClass("hidden"),o.addClass("hidden"),a||l(d),a})["catch"](function(){return!1}),b})["catch"](b.exception)};return{init:t,rootSelector:i.ROOT}});
+4 -1
View File
@@ -265,7 +265,10 @@ function(
return [];
}
var calendarEvents = result.events;
var calendarEvents = result.events.filter(function(event) {
// Do not include events that does not have a due date.
return event.eventtype != "open" && event.eventtype != "opensubmission";
});
// We expect to receive limit + 1 events back from the server.
// Any less means there are no more events to load.
var loadedAll = calendarEvents.length <= limit;
@@ -65,7 +65,7 @@
}}
<div class="border-bottom pb-2">
{{#eventsbyday}}
<h5 class="h6 mt-3 mb-0 {{#past}}text-danger{{/past}}">{{#userdate}} {{dayTimestamp}}, {{#str}} strftimedayshort, core_langconfig {{/str}} {{/userdate}}</h5>
<h5 class="h6 mt-3 mb-0 {{#past}}text-danger{{/past}}">{{#userdate}} {{dayTimestamp}}, {{#str}} strftimedaydate, core_langconfig {{/str}} {{/userdate}}</h5>
{{> block_timeline/event-list-items }}
{{/eventsbyday}}
</div>
+1 -2
View File
@@ -460,8 +460,7 @@ class provider implements
$params = array_merge($inparams, ['userid' => $userid]);
$associds = $DB->get_fieldset_sql($sql, $params);
list($insql, $inparams) = $DB->get_in_or_equal($associds, SQL_PARAMS_NAMED, 'param', true);
$DB->delete_records_select('blog_association', "id $insql", $inparams);
$DB->delete_records_list('blog_association', 'id', $associds);
}
}
+31
View File
@@ -370,6 +370,37 @@ class core_blog_privacy_testcase extends provider_testcase {
$this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes']));
}
/**
* Test provider delete_data_for_user with a context that contains no entries
*
* @return void
*/
public function test_delete_data_for_user_empty_context() {
global $DB;
$user = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$context = context_course::instance($course->id);
// Create a blog entry for user, associated with course.
$entry = new blog_entry($this->create_post(['userid' => $user->id, 'courseid' => $course->id])->id);
$entry->add_association($context->id);
// Generate list of contexts for user.
$contexts = provider::get_contexts_for_userid($user->id);
$this->assertContains($context->id, $contexts->get_contextids());
// Now delete the blog entry.
$entry->delete();
// Try to delete user data using contexts obtained prior to entry deletion.
$contextlist = new approved_contextlist($user, 'core_blog', $contexts->get_contextids());
provider::delete_data_for_user($contextlist);
// Sanity check to ensure blog_associations is really empty.
$this->assertEmpty($DB->get_records('blog_association', ['contextid' => $context->id]));
}
public function test_delete_data_for_all_users_in_context() {
global $DB;
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core_calendar/selectors","core_calendar/events","core/str","core/templates"],function(a,b,c,d,e){var f=function(d){d.on("click",b.eventFilterItem,function(b){var c=a(b.currentTarget);g(c),b.preventDefault()}),a("body").on(c.viewUpdated,function(){var c=d.find(b.eventFilterItem);c.each(function(b,c){if(c=a(c),c.data("eventtype-hidden")){var d=i(c);h(d)}})})},g=function(a){var b=i(a);return b.hidden=!b.hidden,d.get_string("eventtype"+b.eventtype,"calendar").then(function(a){return b.name=a,b}).then(function(a){return e.render("core_calendar/event_filter_key",a)}).then(function(b,c){return e.replaceNode(a,b,c)}).then(function(){h(b)})},h=function(b){M.util.js_pending("month-mini-filterChanged"),a("body").trigger(c.filterChanged,{type:b.eventtype,hidden:b.hidden}),M.util.js_complete("month-mini-filterChanged")},i=function(a){return{eventtype:a.data("eventtype"),hidden:a.data("eventtype-hidden")}};return{init:function(b){b=a(b),f(b)}}});
define(["jquery","core_calendar/selectors","core_calendar/events","core/str","core/templates"],function(a,b,c,d,e){var f=function(d){d.on("click",b.eventFilterItem,function(b){var c=a(b.currentTarget);g(c),b.preventDefault()}),a("body").on(c.viewUpdated,function(){var c=d.find(b.eventFilterItem);c.each(function(b,c){if(c=a(c),c.data("eventtype-hidden")){var d=i(c);h(d)}})})},g=function(a){var b=i(a);return b.hidden=!b.hidden,d.get_string("eventtype"+b.eventtype,"calendar").then(function(a){return b.name=a,b.icon=!0,b.key="i/"+b.eventtype+"event",b.component="core",b}).then(function(a){return e.render("core_calendar/event_filter_key",a)}).then(function(b,c){return e.replaceNode(a,b,c)}).then(function(){h(b)})},h=function(b){M.util.js_pending("month-mini-filterChanged"),a("body").trigger(c.filterChanged,{type:b.eventtype,hidden:b.hidden}),M.util.js_complete("month-mini-filterChanged")},i=function(a){return{eventtype:a.data("eventtype"),hidden:a.data("eventtype-hidden")}};return{init:function(b){b=a(b),f(b)}}});
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/modal_event_form","core_calendar/repository","core_calendar/events","core_calendar/modal_delete","core_calendar/selectors"],function(a,b,c,d,e,f,g,h,i,j,k,l,m){function n(d,e,f){var i=[{key:"deleteevent",component:"calendar"}];f=parseInt(f,10);var m,n=f>1;n?(i.push({key:"confirmeventseriesdelete",component:"calendar",param:{name:e,count:f}}),m=g.create({type:l.TYPE})):(i.push({key:"confirmeventdelete",component:"calendar",param:e}),m=g.create({type:g.types.SAVE_CANCEL})),m.then(function(a){a.show()}).fail(c.exception);var o=b.get_strings(i),p=a.when(o,m).then(function(b,e){return e.setTitle(b[0]),e.setBody(b[1]),n||e.setSaveButtonText(b[0]),e.getRoot().on(h.save,function(){j.deleteEvent(d,!1).then(function(){a("body").trigger(k.deleted,[d,!1])})["catch"](c.exception)}),e.getRoot().on(k.deleteAll,function(){j.deleteEvent(d,!0).then(function(){a("body").trigger(k.deleted,[d,!0])})["catch"](c.exception)}),e}).fail(c.exception);return p}function o(b){b.on("click",m.actions.remove,function(b){var c=a(this).closest(m.eventItem),d=c.data("eventId"),e=c.data("eventTitle"),f=c.data("eventCount");n(d,e,f),b.preventDefault()})}function p(b,d){return d.then(function(c){a("body").on(k.editEvent,function(a,d){var e=b.find(m.wrapper);c.setEventId(d),c.setContextId(e.data("contextId")),c.show(),a.stopImmediatePropagation()})}).fail(c.exception),d}var q=function(b){var d=g.create({type:i.TYPE,large:!0});return b.on("click",m.actions.create,function(a){d.then(function(a){var c=b.find(m.wrapper),d=c.data("categoryid");"undefined"!=typeof d&&a.setCategoryId(d);var e=b.find(m.today),f=b.find(m.day);!e.length&&f.length&&a.setStartTime(f.data("newEventTimestamp")),a.setContextId(c.data("contextId")),a.setCourseId(c.data("courseid")),a.show()}).fail(c.exception),a.preventDefault()}),b.on("click",m.actions.edit,function(b){b.preventDefault();var e=a(b.currentTarget),f=e.closest(m.wrapper),g=e.closest(m.eventItem);d.then(function(a){a.setEventId(g.data("eventId")),a.setContextId(f.data("contextId")),a.show(),b.stopImmediatePropagation()}).fail(c.exception)}),d};return{registerRemove:o,registerEditListeners:p,registerEventFormModal:q}});
define(["jquery","core/str","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","core/modal_factory","core/modal_events","core_calendar/modal_event_form","core_calendar/repository","core_calendar/events","core_calendar/modal_delete","core_calendar/selectors","core/pending"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n){function o(d,e,f){var i=[{key:"deleteevent",component:"calendar"}];f=parseInt(f,10);var m,o=f>1;o?(i.push({key:"confirmeventseriesdelete",component:"calendar",param:{name:e,count:f}}),m=g.create({type:l.TYPE})):(i.push({key:"confirmeventdelete",component:"calendar",param:e}),m=g.create({type:g.types.SAVE_CANCEL}));var p=b.get_strings(i),q=a.when(p,m).then(function(b,e){return e.setTitle(b[0]),e.setBody(b[1]),o||e.setSaveButtonText(b[0]),e.show(),e.getRoot().on(h.save,function(){var b=new n("calendar/crud:initModal:deletedevent");j.deleteEvent(d,!1).then(function(){a("body").trigger(k.deleted,[d,!1])}).then(b.resolve)["catch"](c.exception)}),e.getRoot().on(k.deleteAll,function(){var b=new n("calendar/crud:initModal:deletedallevent");j.deleteEvent(d,!0).then(function(){a("body").trigger(k.deleted,[d,!0])}).then(b.resolve)["catch"](c.exception)}),e})["catch"](c.exception);return q}function p(b){b.on("click",m.actions.remove,function(b){var c=a(this).closest(m.eventItem),d=c.data("eventId"),e=c.data("eventTitle"),f=c.data("eventCount");o(d,e,f),b.preventDefault()})}function q(b,d){return d.then(function(c){a("body").on(k.editEvent,function(a,d){var e=b.find(m.wrapper);c.setEventId(d),c.setContextId(e.data("contextId")),c.show(),a.stopImmediatePropagation()})}).fail(c.exception),d}var r=function(b){var d=g.create({type:i.TYPE,large:!0});return b.on("click",m.actions.create,function(a){d.then(function(a){var c=b.find(m.wrapper),d=c.data("categoryid");"undefined"!=typeof d&&a.setCategoryId(d);var e=b.find(m.today),f=b.find(m.day);!e.length&&f.length&&a.setStartTime(f.data("newEventTimestamp")),a.setContextId(c.data("contextId")),a.setCourseId(c.data("courseid")),a.show()}).fail(c.exception),a.preventDefault()}),b.on("click",m.actions.edit,function(b){b.preventDefault();var e=a(b.currentTarget),f=e.closest(m.wrapper),g=e.closest(m.eventItem);d.then(function(a){a.setEventId(g.data("eventId")),a.setContextId(f.data("contextId")),a.show(),b.stopImmediatePropagation()}).fail(c.exception)}),d};return{registerRemove:p,registerEditListeners:q,registerEventFormModal:r}});
+3
View File
@@ -67,6 +67,9 @@ function(
return Str.get_string('eventtype' + data.eventtype, 'calendar')
.then(function(nameStr) {
data.name = nameStr;
data.icon = true;
data.key = 'i/' + data.eventtype + 'event';
data.component = 'core';
return data;
})
+10 -9
View File
@@ -35,6 +35,7 @@ define([
'core_calendar/events',
'core_calendar/modal_delete',
'core_calendar/selectors',
'core/pending',
],
function(
$,
@@ -49,7 +50,8 @@ function(
CalendarRepository,
CalendarEvents,
ModalDelete,
CalendarSelectors
CalendarSelectors,
Pending
) {
/**
@@ -101,13 +103,6 @@ function(
);
}
deletePromise.then(function(deleteModal) {
deleteModal.show();
return;
})
.fail(Notification.exception);
var stringsPromise = Str.get_strings(deleteStrings);
var finalPromise = $.when(stringsPromise, deletePromise)
@@ -118,27 +113,33 @@ function(
deleteModal.setSaveButtonText(strings[0]);
}
deleteModal.show();
deleteModal.getRoot().on(ModalEvents.save, function() {
var pendingPromise = new Pending('calendar/crud:initModal:deletedevent');
CalendarRepository.deleteEvent(eventId, false)
.then(function() {
$('body').trigger(CalendarEvents.deleted, [eventId, false]);
return;
})
.then(pendingPromise.resolve)
.catch(Notification.exception);
});
deleteModal.getRoot().on(CalendarEvents.deleteAll, function() {
var pendingPromise = new Pending('calendar/crud:initModal:deletedallevent');
CalendarRepository.deleteEvent(eventId, true)
.then(function() {
$('body').trigger(CalendarEvents.deleted, [eventId, true]);
return;
})
.then(pendingPromise.resolve)
.catch(Notification.exception);
});
return deleteModal;
})
.fail(Notification.exception);
.catch(Notification.exception);
return finalPromise;
}
@@ -70,11 +70,13 @@ class create_update_form_mapper implements create_update_form_mapper_interface {
'format' => $data->format
];
// We don't want to return the context because it's not a
// form value and breaks the validation.
// Don't return context or subscription because they're not form values and break validation.
if (isset($data->context)) {
unset($data->context);
}
if (isset($data->subscription)) {
unset($data->subscription);
}
return $data;
}
+5 -2
View File
@@ -2203,8 +2203,8 @@ function calendar_view_event_allowed(calendar_event $event) {
if (has_capability('moodle/calendar:manageentries', $event->context)) {
return true;
}
$mycourses = enrol_get_my_courses('id');
return isset($mycourses[$event->courseid]);
return can_access_course(get_course($event->courseid));
} else if ($event->userid) {
if ($event->userid != $USER->id) {
// No-one can ever see another users events.
@@ -3661,6 +3661,9 @@ function calendar_get_filter_types() {
return [
'eventtype' => $type,
'name' => get_string("eventtype{$type}", "calendar"),
'icon' => true,
'key' => 'i/'.$type.'event',
'component' => 'core'
];
}, $types);
}
+10 -4
View File
@@ -127,7 +127,8 @@ $searches = [];
$params = [];
$usedefaultfilters = true;
if (!empty($courseid) && $courseid == SITEID && !empty($types['site'])) {
if (!empty($types['site'])) {
$searches[] = "(eventtype = 'site')";
$usedefaultfilters = false;
}
@@ -144,9 +145,14 @@ if (!empty($courseid) && !empty($types['course'])) {
$usedefaultfilters = false;
}
if (!empty($categoryid) && !empty($types['category'])) {
$searches[] = "(eventtype = 'category' AND categoryid = :categoryid)";
$params += ['categoryid' => $categoryid];
if (!empty($types['category'])) {
if (!empty($categoryid)) {
$searches[] = "(eventtype = 'category' AND categoryid = :categoryid)";
$params += ['categoryid' => $categoryid];
} else {
$searches[] = "(eventtype = 'category')";
}
$usedefaultfilters = false;
}
+1 -1
View File
@@ -37,5 +37,5 @@
{{#pix}} icon, {{modulename}} {{/pix}}
{{/modulename}}
{{^modulename}}
{{#pix}} i/{{eventtype}}event, core {{/pix}}
{{#icon}}{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}{{/icon}}
{{/modulename}}
+1 -6
View File
@@ -136,12 +136,7 @@
{{$content}}
{{#events}}
<div data-popover-eventtype-{{calendareventtype}}="1">
{{#modulename}}
{{#pix}} icon, {{modulename}} {{/pix}}
{{/modulename}}
{{^modulename}}
{{#pix}} i/{{eventtype}}event, core {{/pix}}
{{/modulename}}
{{> core_calendar/event_icon}}
{{{popupname}}}
</div>
{{/events}}
@@ -47,3 +47,30 @@ Feature: Import and edit calendar events
And I view the calendar for "2" "2017"
And I should not see "Event on 2-25-2017"
And I should not see "Event on 2-20-2017"
Scenario: Import events using different event types.
Given I log in as "admin"
And I view the calendar for "1" "2016"
And I press "Manage subscriptions"
And I set the following fields to these values:
| Calendar name | Test Import |
| Import from | Calendar file (.ics) |
| Type of event | User |
And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
And I press "Add"
And I should see "User events"
And I set the following fields to these values:
| Calendar name | Test Import |
| Import from | Calendar file (.ics) |
| Type of event | Category |
| Category | Miscellaneous |
And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
And I press "Add"
And I should see "Category events"
And I set the following fields to these values:
| Calendar name | Test Import |
| Import from | Calendar file (.ics) |
| Type of event | Site |
And I upload "calendar/tests/fixtures/import.ics" file to "Calendar file (.ics)" filemanager
And I press "Add"
And I should see "Site events"
+68
View File
@@ -772,4 +772,72 @@ class core_calendar_lib_testcase extends advanced_testcase {
$this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids);
$this->assertEquals($users[1]->id, $userid);
}
/**
* Test for calendar_view_event_allowed for course event types.
*/
public function test_calendar_view_event_allowed_course_event() {
global $USER;
$this->setAdminUser();
$generator = $this->getDataGenerator();
// A student in a course.
$student = $generator->create_user();
// Some user not enrolled in any course.
$someuser = $generator->create_user();
// A course with manual enrolments.
$manualcourse = $generator->create_course();
// Enrol the student to the manual enrolment course.
$generator->enrol_user($student->id, $manualcourse->id);
// A course that allows guest access.
$guestcourse = $generator->create_course(
(object)[
'shortname' => 'guestcourse',
'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
'enrol_guest_password_0' => ''
]);
$manualevent = (object)[
'name' => 'Manual course event',
'description' => '',
'format' => 1,
'categoryid' => 0,
'courseid' => $manualcourse->id,
'groupid' => 0,
'userid' => $USER->id,
'modulename' => 0,
'instance' => 0,
'eventtype' => 'course',
'timestart' => time(),
'timeduration' => 86400,
'visible' => 1
];
$caleventmanual = calendar_event::create($manualevent, false);
// Create a course event for the course with guest access.
$guestevent = clone $manualevent;
$guestevent->name = 'Guest course event';
$guestevent->courseid = $guestcourse->id;
$caleventguest = calendar_event::create($guestevent, false);
// Viewing as admin.
$this->assertTrue(calendar_view_event_allowed($caleventmanual));
$this->assertTrue(calendar_view_event_allowed($caleventguest));
// Viewing as someone enrolled in a course.
$this->setUser($student);
$this->assertTrue(calendar_view_event_allowed($caleventmanual));
// Viewing as someone not enrolled in any course.
$this->setUser($someuser);
// Viewing as someone not enrolled in a course without guest access on.
$this->assertFalse(calendar_view_event_allowed($caleventmanual));
// Viewing as someone not enrolled in a course with guest access on.
$this->assertTrue(calendar_view_event_allowed($caleventguest));
}
}
+1 -1
View File
@@ -13,7 +13,7 @@
"require-dev": {
"phpunit/phpunit": "6.5.*",
"phpunit/dbunit": "3.0.*",
"moodlehq/behat-extension": "3.36.1",
"moodlehq/behat-extension": "3.36.3",
"mikey179/vfsstream": "^1.6",
"instaclick/php-webdriver": "dev-local as 1.x-dev"
}
Generated
+111 -112
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c5f05bdc99eb03364db93ed9b7f6d17e",
"content-hash": "6333f2093f75686fe706fe129cc5d8c5",
"packages": [],
"packages-dev": [
{
@@ -619,27 +619,28 @@
},
{
"name": "guzzlehttp/guzzle",
"version": "6.3.3",
"version": "6.4.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba"
"reference": "0895c932405407fd3a7368b6910c09a24d26db11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba",
"reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/0895c932405407fd3a7368b6910c09a24d26db11",
"reference": "0895c932405407fd3a7368b6910c09a24d26db11",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.4",
"guzzlehttp/psr7": "^1.6.1",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.0"
"psr/log": "^1.1"
},
"suggest": {
"psr/log": "Required for using the Log middleware"
@@ -651,12 +652,12 @@
}
},
"autoload": {
"files": [
"src/functions_include.php"
],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -680,7 +681,7 @@
"rest",
"web service"
],
"time": "2018-04-22T15:46:56+00:00"
"time": "2019-10-23T15:58:00+00:00"
},
{
"name": "guzzlehttp/promises",
@@ -903,8 +904,8 @@
"authors": [
{
"name": "Frank Kleine",
"role": "Developer",
"homepage": "http://frankkleine.de/"
"homepage": "http://frankkleine.de/",
"role": "Developer"
}
],
"description": "Virtual file system to mock the real file system in unit tests.",
@@ -913,16 +914,16 @@
},
{
"name": "moodlehq/behat-extension",
"version": "v3.36.1",
"version": "v3.36.3",
"source": {
"type": "git",
"url": "https://github.com/moodlehq/moodle-behat-extension.git",
"reference": "a3c38c2864e7259b1de834218abfe49eecc03417"
"reference": "3bee9012d8818dd24c72cc7a6614dea7ccf9c1fb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/moodlehq/moodle-behat-extension/zipball/a3c38c2864e7259b1de834218abfe49eecc03417",
"reference": "a3c38c2864e7259b1de834218abfe49eecc03417",
"url": "https://api.github.com/repos/moodlehq/moodle-behat-extension/zipball/3bee9012d8818dd24c72cc7a6614dea7ccf9c1fb",
"reference": "3bee9012d8818dd24c72cc7a6614dea7ccf9c1fb",
"shasum": ""
},
"require": {
@@ -931,7 +932,7 @@
"behat/mink-extension": "~2.2",
"behat/mink-goutte-driver": "~1.2",
"behat/mink-selenium2-driver": "~1.3",
"php": ">=5.4.4",
"php": ">=7.0.0",
"symfony/process": "2.8.*"
},
"type": "library",
@@ -947,9 +948,9 @@
"authors": [
{
"name": "David Monllaó",
"role": "Developer",
"email": "david.monllao@gmail.com",
"homepage": "http://moodle.com"
"homepage": "http://moodle.com",
"role": "Developer"
}
],
"description": "Moodle behat extension",
@@ -958,7 +959,7 @@
"Behat",
"moodle"
],
"time": "2019-07-18T08:33:39+00:00"
"time": "2019-10-28T11:42:22+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -1043,18 +1044,18 @@
"authors": [
{
"name": "Arne Blankerts",
"role": "Developer",
"email": "arne@blankerts.de"
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"role": "Developer",
"email": "sebastian@phpeople.de"
"email": "sebastian@phpeople.de",
"role": "Developer"
},
{
"name": "Sebastian Bergmann",
"role": "Developer",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "Developer"
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
@@ -1090,18 +1091,18 @@
"authors": [
{
"name": "Arne Blankerts",
"role": "Developer",
"email": "arne@blankerts.de"
"email": "arne@blankerts.de",
"role": "Developer"
},
{
"name": "Sebastian Heuer",
"role": "Developer",
"email": "sebastian@phpeople.de"
"email": "sebastian@phpeople.de",
"role": "Developer"
},
{
"name": "Sebastian Bergmann",
"role": "Developer",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "Developer"
}
],
"description": "Library for handling version information and constraints",
@@ -1163,26 +1164,26 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "4.3.1",
"version": "4.3.2",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c"
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
"reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"reference": "b83ff7cfcfee7827e1e78b637a5904fe6a96698e",
"shasum": ""
},
"require": {
"php": "^7.0",
"phpdocumentor/reflection-common": "^1.0.0",
"phpdocumentor/type-resolver": "^0.4.0",
"phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0",
"phpdocumentor/type-resolver": "~0.4 || ^1.0.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
"doctrine/instantiator": "~1.0.5",
"doctrine/instantiator": "^1.0.5",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.4"
},
@@ -1210,29 +1211,29 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2019-04-30T17:48:53+00:00"
"time": "2019-09-12T14:27:41+00:00"
},
{
"name": "phpdocumentor/type-resolver",
"version": "0.4.0",
"version": "0.5.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7"
"reference": "cf842904952e64e703800d094cdf34e715a8a3ae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7",
"reference": "9c977708995954784726e25d0cd1dddf4e65b0f7",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/cf842904952e64e703800d094cdf34e715a8a3ae",
"reference": "cf842904952e64e703800d094cdf34e715a8a3ae",
"shasum": ""
},
"require": {
"php": "^5.5 || ^7.0",
"php": "^7.0",
"phpdocumentor/reflection-common": "^1.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^5.2||^4.8.24"
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.4"
},
"type": "library",
"extra": {
@@ -1242,9 +1243,7 @@
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src/"
]
"phpDocumentor\\Reflection\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1257,26 +1256,26 @@
"email": "me@mikevanriel.com"
}
],
"time": "2017-07-14T14:27:02+00:00"
"time": "2017-12-30T13:23:38+00:00"
},
{
"name": "phpspec/prophecy",
"version": "1.8.1",
"version": "1.9.0",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76"
"reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
"reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203",
"reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
"sebastian/comparator": "^1.1|^2.0|^3.0",
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
},
@@ -1320,7 +1319,7 @@
"spy",
"stub"
],
"time": "2019-06-13T12:50:23+00:00"
"time": "2019-10-03T11:07:50+00:00"
},
{
"name": "phpunit/dbunit",
@@ -1425,8 +1424,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
@@ -1473,8 +1472,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sb@sebastian-bergmann.de"
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
@@ -1515,8 +1514,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Simple template engine.",
@@ -1564,8 +1563,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sb@sebastian-bergmann.de"
"email": "sb@sebastian-bergmann.de",
"role": "lead"
}
],
"description": "Utility class for timing",
@@ -1695,8 +1694,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "The PHP Unit Testing framework.",
@@ -1869,16 +1868,16 @@
},
{
"name": "psr/log",
"version": "1.1.0",
"version": "1.1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
"reference": "bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
"url": "https://api.github.com/repos/php-fig/log/zipball/bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2",
"reference": "bf73deb2b3b896a9d9c75f3f0d88185d2faa27e2",
"shasum": ""
},
"require": {
@@ -1887,7 +1886,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -1912,7 +1911,7 @@
"psr",
"psr-3"
],
"time": "2018-11-20T15:27:04+00:00"
"time": "2019-10-25T08:06:51+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -2167,16 +2166,16 @@
},
{
"name": "sebastian/exporter",
"version": "3.1.1",
"version": "3.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "06a9a5947f47b3029d76118eb5c22802e5869687"
"reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/06a9a5947f47b3029d76118eb5c22802e5869687",
"reference": "06a9a5947f47b3029d76118eb5c22802e5869687",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e",
"reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e",
"shasum": ""
},
"require": {
@@ -2230,7 +2229,7 @@
"export",
"exporter"
],
"time": "2019-08-11T12:43:14+00:00"
"time": "2019-09-14T09:02:43+00:00"
},
{
"name": "sebastian/global-state",
@@ -2505,8 +2504,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
@@ -2515,16 +2514,16 @@
},
{
"name": "symfony/browser-kit",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/browser-kit.git",
"reference": "1a3406a6b9b61b492592a816ca056afcc9e976c0"
"reference": "abe4bf2c934ddd1fd490a7d9147df7827b5fff0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/1a3406a6b9b61b492592a816ca056afcc9e976c0",
"reference": "1a3406a6b9b61b492592a816ca056afcc9e976c0",
"url": "https://api.github.com/repos/symfony/browser-kit/zipball/abe4bf2c934ddd1fd490a7d9147df7827b5fff0f",
"reference": "abe4bf2c934ddd1fd490a7d9147df7827b5fff0f",
"shasum": ""
},
"require": {
@@ -2568,11 +2567,11 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com",
"time": "2019-08-26T07:52:58+00:00"
"time": "2019-09-10T10:13:59+00:00"
},
{
"name": "symfony/class-loader",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/class-loader.git",
@@ -2628,16 +2627,16 @@
},
{
"name": "symfony/config",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "24a60c0d7ad98a0fa5d1f892e9286095a389404f"
"reference": "717ad66b5257e9752ae3c5722b5810bb4c40b236"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/24a60c0d7ad98a0fa5d1f892e9286095a389404f",
"reference": "24a60c0d7ad98a0fa5d1f892e9286095a389404f",
"url": "https://api.github.com/repos/symfony/config/zipball/717ad66b5257e9752ae3c5722b5810bb4c40b236",
"reference": "717ad66b5257e9752ae3c5722b5810bb4c40b236",
"shasum": ""
},
"require": {
@@ -2688,7 +2687,7 @@
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2019-08-26T07:52:57+00:00"
"time": "2019-09-19T15:32:51+00:00"
},
{
"name": "symfony/console",
@@ -2760,16 +2759,16 @@
},
{
"name": "symfony/css-selector",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "e18c5c4b35e7f17513448a25d02f7af34a4bdb41"
"reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/e18c5c4b35e7f17513448a25d02f7af34a4bdb41",
"reference": "e18c5c4b35e7f17513448a25d02f7af34a4bdb41",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/f819f71ae3ba6f396b4c015bd5895de7d2f1f85f",
"reference": "f819f71ae3ba6f396b4c015bd5895de7d2f1f85f",
"shasum": ""
},
"require": {
@@ -2809,20 +2808,20 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"time": "2019-08-20T13:31:17+00:00"
"time": "2019-10-01T11:57:37+00:00"
},
{
"name": "symfony/debug",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "0b600300918780001e2821db77bc28b677794486"
"reference": "b3e7ce815d82196435d16dc458023f8fb6b36ceb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/0b600300918780001e2821db77bc28b677794486",
"reference": "0b600300918780001e2821db77bc28b677794486",
"url": "https://api.github.com/repos/symfony/debug/zipball/b3e7ce815d82196435d16dc458023f8fb6b36ceb",
"reference": "b3e7ce815d82196435d16dc458023f8fb6b36ceb",
"shasum": ""
},
"require": {
@@ -2865,7 +2864,7 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2019-08-20T13:31:17+00:00"
"time": "2019-09-19T15:32:51+00:00"
},
{
"name": "symfony/dependency-injection",
@@ -2939,16 +2938,16 @@
},
{
"name": "symfony/dom-crawler",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/dom-crawler.git",
"reference": "8558d1bc4554f5cb0b66e50377457967a8969263"
"reference": "29cffc38a38f2a8ed7e494c9cea2f890a40c2359"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/8558d1bc4554f5cb0b66e50377457967a8969263",
"reference": "8558d1bc4554f5cb0b66e50377457967a8969263",
"url": "https://api.github.com/repos/symfony/dom-crawler/zipball/29cffc38a38f2a8ed7e494c9cea2f890a40c2359",
"reference": "29cffc38a38f2a8ed7e494c9cea2f890a40c2359",
"shasum": ""
},
"require": {
@@ -2992,11 +2991,11 @@
],
"description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com",
"time": "2019-08-26T07:52:58+00:00"
"time": "2019-08-30T17:42:32+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
@@ -3059,7 +3058,7 @@
},
{
"name": "symfony/filesystem",
"version": "v3.4.31",
"version": "v3.4.32",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
@@ -3426,8 +3425,8 @@
"authors": [
{
"name": "Arne Blankerts",
"role": "Developer",
"email": "arne@blankerts.de"
"email": "arne@blankerts.de",
"role": "Developer"
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+4
View File
@@ -815,6 +815,10 @@ $CFG->admin = 'admin';
// Example:
// $CFG->behat_faildump_path = '/my/path/to/save/failure/dumps';
//
// You can make behat pause upon failure to help you diagnose and debug problems with your tests.
//
// $CFG->behat_pause_on_fail = true;
//
// You can specify db, selenium wd_host etc. for behat parallel run by setting following variable.
// Example:
// $CFG->behat_parallel_run = array (
+3
View File
@@ -103,6 +103,9 @@ class course_summary_exporter extends \core\external\exporter {
),
'enddate' => array(
'type' => PARAM_INT,
),
'visible' => array(
'type' => PARAM_BOOL,
)
);
}
+3 -5
View File
@@ -166,11 +166,9 @@ if ($editform->is_cancelled()) {
if (!empty($CFG->creatornewroleid) and !is_viewing($context, NULL, 'moodle/role:assign') and !is_enrolled($context, NULL, 'moodle/role:assign')) {
// Deal with course creators - enrol them internally with default role.
if (user_can_assign($context, $CFG->creatornewroleid)) {
enrol_try_internal_enrol($course->id, $USER->id, $CFG->creatornewroleid);
} else {
enrol_try_internal_enrol($course->id, $USER->id);
}
// Note: This does not respect capabilities, the creator will be assigned the default role.
// This is an expected behaviour. See MDL-66683 for further details.
enrol_try_internal_enrol($course->id, $USER->id, $CFG->creatornewroleid);
}
// The URL to take them to if they chose save and display.
+8 -1
View File
@@ -84,7 +84,14 @@ if ($deletesection) {
}
}
$editoroptions = array('context'=>$context ,'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>false, 'noclean'=>true);
$editoroptions = array(
'context' => $context,
'maxfiles' => EDITOR_UNLIMITED_FILES,
'maxbytes' => $CFG->maxbytes,
'trusttext' => false,
'noclean' => true,
'subdirs' => true
);
$courseformat = course_get_format($course);
$defaultsectionname = $courseformat->get_default_section_name($section);
+1 -1
View File
@@ -3586,7 +3586,7 @@ class core_course_external extends external_api {
}
/**
* Return structure for edit_module()
* Return structure for get_module()
*
* @since Moodle 3.3
* @return external_description
+1 -1
View File
@@ -4577,7 +4577,7 @@ function course_get_recent_courses(int $userid = null, int $limit = 0, int $offs
}
$basefields = array('id', 'idnumber', 'summary', 'summaryformat', 'startdate', 'enddate', 'category',
'shortname', 'fullname', 'timeaccess', 'component');
'shortname', 'fullname', 'timeaccess', 'component', 'visible');
$sort = trim($sort);
if (empty($sort)) {
+7 -1
View File
@@ -28,7 +28,8 @@
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"hasprogress": true,
"progress": 10
"progress": 10,
"visible": true
}
]
}
@@ -63,6 +64,11 @@
</a>
{{$menu}}{{/menu}}
</div>
{{^visible}}
<div class="hiddenmessage">
<span class="badge badge-info">{{#str}} hiddenfromstudents {{/str}}</span>
</div>
{{/visible}}
</div>
{{$progress}}{{/progress}}
</div>
+2 -5
View File
@@ -1123,11 +1123,8 @@ class behat_course extends behat_base {
protected function get_activity_element($element, $selectortype, $activityname) {
$activitynode = $this->get_activity_node($activityname);
// Transforming to Behat selector/locator.
list($selector, $locator) = $this->transform_selector($selectortype, $element);
$exception = new ElementNotFoundException($this->getSession(), '"' . $element . '" "' . $selectortype . '" in "' . $activityname . '" ');
return $this->find($selector, $locator, $exception, $activitynode);
$exception = new ElementNotFoundException($this->getSession(), "'{$element}' '{$selectortype}' in '${activityname}'");
return $this->find($selectortype, $element, $exception, $activitynode);
}
/**
@@ -85,7 +85,6 @@ Feature: Managers can create courses
| moodle/course:create | Allow |
| moodle/course:manageactivities | Allow |
| moodle/course:viewparticipants | Allow |
| moodle/role:assign | Allow |
And I log out
And I log in as "kevin"
And I am on site homepage
@@ -96,20 +95,4 @@ Feature: Managers can create courses
And I press "Save and display"
And I follow "Participants"
Then I should see "Kevin the"
And I should not see "Teacher"
And I log out
Given I log in as "admin"
And I define the allowed role assignments for the "Creator" role as:
| Teacher | Assignable |
And I log out
And I log in as "kevin"
And I am on site homepage
And I turn editing mode on
When I press "Add a new course"
And I set the following fields to these values:
| Course full name | My second course |
| Course short name | mysecondcourse |
And I press "Save and display"
And I follow "Participants"
Then I should see "Kevin the"
And I should see "Teacher"
+64
View File
@@ -993,6 +993,70 @@ class core_enrol_external extends external_api {
);
}
/**
* Returns description of submit_user_enrolment_form parameters.
*
* @return external_function_parameters.
*/
public static function submit_user_enrolment_form_parameters() {
return new external_function_parameters([
'formdata' => new external_value(PARAM_RAW, 'The data from the event form'),
]);
}
/**
* External function that handles the user enrolment form submission.
*
* @param string $formdata The user enrolment form data in s URI encoded param string
* @return array An array consisting of the processing result and error flag, if available
*/
public static function submit_user_enrolment_form($formdata) {
global $CFG, $DB, $PAGE;
// Parameter validation.
$params = self::validate_parameters(self::submit_user_enrolment_form_parameters(), ['formdata' => $formdata]);
$data = [];
parse_str($params['formdata'], $data);
$userenrolment = $DB->get_record('user_enrolments', ['id' => $data['ue']], '*', MUST_EXIST);
$instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST);
$plugin = enrol_get_plugin($instance->enrol);
$course = get_course($instance->courseid);
$context = context_course::instance($course->id);
self::validate_context($context);
require_once("$CFG->dirroot/enrol/editenrolment_form.php");
$customformdata = [
'ue' => $userenrolment,
'modal' => true,
'enrolinstancename' => $plugin->get_instance_name($instance)
];
$mform = new enrol_user_enrolment_form(null, $customformdata, 'post', '', null, true, $data);
if ($validateddata = $mform->get_data()) {
require_once($CFG->dirroot . '/enrol/locallib.php');
$manager = new course_enrolment_manager($PAGE, $course);
$result = $manager->edit_enrolment($userenrolment, $validateddata);
return ['result' => $result];
} else {
return ['result' => false, 'validationerror' => true];
}
}
/**
* Returns description of submit_user_enrolment_form() result value
*
* @return external_description
*/
public static function submit_user_enrolment_form_returns() {
return new external_single_structure([
'result' => new external_value(PARAM_BOOL, 'True if the user\'s enrolment was successfully updated'),
'validationerror' => new external_value(PARAM_BOOL, 'Indicates invalid form data', VALUE_DEFAULT, false),
]);
}
/**
* Returns description of unenrol_user_enrolment() parameters
*
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){var e=100;return{processResults:function(b,c){var d=[];return a.isArray(c)?(a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d):c},transport:function(f,g,h,i){var j,k=a(f).attr("courseid"),l=a(f).attr("userfields").split(",");"undefined"==typeof k&&(k="1");var m=a(f).attr("enrolid");"undefined"==typeof m&&(m=""),j=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:k,enrolid:m,search:g,searchanywhere:!0,page:0,perpage:e+1}}]),j[0].then(function(b){var f=[],g=0;return b.length<=e?(a.each(b,function(b,d){var e=d,g=[];a.each(l,function(a,b){"undefined"!=typeof d[b]&&""!==d[b]&&(e.hasidentity=!0,g.push(d[b]))}),e.identity=g.join(", "),f.push(c.render("enrol_manual/form-user-selector-suggestion",e))}),a.when.apply(a.when,f).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[g],g++}),h(b)})):d.get_string("toomanyuserstoshow","core",">"+e).then(function(a){h(a)})}).fail(i)}}});
define(["jquery","core/ajax","core/templates","core/str"],function(a,b,c,d){return{processResults:function(b,c){var d=[];return a.isArray(c)?(a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d):c},transport:function(e,f,g,h){var i,j=a(e).attr("courseid"),k=a(e).attr("userfields").split(",");"undefined"==typeof j&&(j="1");var l=a(e).attr("enrolid");"undefined"==typeof l&&(l="");var m=a(e).attr("perpage");"undefined"==typeof m&&(m=100),i=b.call([{methodname:"core_enrol_get_potential_users",args:{courseid:j,enrolid:l,search:f,searchanywhere:!0,page:0,perpage:m+1}}]),i[0].then(function(b){var e=[],f=0;return b.length<=m?(a.each(b,function(b,d){var f=d,g=[];a.each(k,function(a,b){"undefined"!=typeof d[b]&&""!==d[b]&&(f.hasidentity=!0,g.push(d[b]))}),f.identity=g.join(", "),e.push(c.render("enrol_manual/form-user-selector-suggestion",f))}),a.when.apply(a.when,e).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[f],f++}),g(b)})):d.get_string("toomanyuserstoshow","core",">"+m).then(function(a){g(a)})}).fail(h)}}});
+1 -1
View File
@@ -1 +1 @@
define(["core/templates","jquery","core/str","core/config","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g,h){var i={COHORTSELECT:"#id_cohortlist",TRIGGERBUTTONS:".enrolusersbutton.enrol_manual_plugin [type='submit']",UNWANTEDHIDDENFIELDS:":input[value='_qf__force_multiselect_submission']"},j=function(a){this.contextid=a.contextid,this.initModal()};return j.prototype.courseid=0,j.prototype.modal=null,j.prototype.initModal=function(){var a=b(i.TRIGGERBUTTONS);b.when(c.get_strings([{key:"enroluserscohorts",component:"enrol_manual"},{key:"enrolusers",component:"enrol_manual"}]),f.create({type:f.types.SAVE_CANCEL,large:!0},a)).then(function(a,c){this.modal=c,c.setTitle(a[1]),c.setSaveButtonText(a[1]),c.getRoot().on(g.save,this.submitForm.bind(this)),c.getRoot().on("submit","form",this.submitFormAjax.bind(this)),c.getRoot().on(g.hidden,function(){c.setBody("")}),c.getRoot().on(g.shown,function(){var d=this.getBody();d.then(function(d){var e=b(d).find(i.COHORTSELECT).length?0:1;c.setSaveButtonText(a[e])}).fail(e.exception),c.setBody(d)}.bind(this))}.bind(this)).fail(e.exception)},j.prototype.submitForm=function(a){a.preventDefault(),this.modal.getRoot().find("form").submit()},j.prototype.submitFormAjax=function(a){a.preventDefault();var c=this.modal.getRoot().find("form"),f=c.find(i.UNWANTEDHIDDENFIELDS);f.each(function(){b(this).remove()});var g=c.serialize();this.modal.hide();var h={type:"GET",processData:!1,contentType:"application/json"},j=d.wwwroot+"/enrol/manual/ajax.php?"+g;b.ajax(j,h).then(function(a){a.error?e.addNotification({message:a.error,type:"error"}):("undefined"!=typeof window.M.core_formchangechecker&&window.M.core_formchangechecker.reset_form_dirty_state(),window.location.reload())}).fail(e.exception)},j.prototype.getBody=function(){return h.loadFragment("enrol_manual","enrol_users_form",this.contextid,{}).fail(e.exception)},j.prototype.getFooter=function(){return a.render("enrol_manual/enrol_modal_footer",{})},{init:function(a){new j(a)}}});
define(["core/templates","jquery","core/str","core/config","core/notification","core/modal_factory","core/modal_events","core/fragment","core/pending"],function(a,b,c,d,e,f,g,h,i){var j={COHORTSELECT:"#id_cohortlist",TRIGGERBUTTONS:".enrolusersbutton.enrol_manual_plugin [type='submit']",UNWANTEDHIDDENFIELDS:":input[value='_qf__force_multiselect_submission']"},k=function(a){this.contextid=a.contextid,this.initModal()};return k.prototype.courseid=0,k.prototype.modal=null,k.prototype.initModal=function(){var a=b(j.TRIGGERBUTTONS);b.when(c.get_strings([{key:"enroluserscohorts",component:"enrol_manual"},{key:"enrolusers",component:"enrol_manual"}]),f.create({type:f.types.SAVE_CANCEL,large:!0},a)).then(function(a,c){this.modal=c,c.setTitle(a[1]),c.setSaveButtonText(a[1]),c.getRoot().on(g.save,this.submitForm.bind(this)),c.getRoot().on("submit","form",this.submitFormAjax.bind(this)),c.getRoot().on(g.hidden,function(){c.setBody("")}),c.getRoot().on(g.shown,function(){var d=new i("enrol_manual/quickenrolment:initModal:shown"),f=this.getBody();f.then(function(d){var e=b(d).find(j.COHORTSELECT).length?0:1;c.setSaveButtonText(a[e])}).then(d.resolve)["catch"](e.exception),c.setBody(f)}.bind(this))}.bind(this)).fail(e.exception)},k.prototype.submitForm=function(a){a.preventDefault(),this.modal.getRoot().find("form").submit()},k.prototype.submitFormAjax=function(a){a.preventDefault();var c=this.modal.getRoot().find("form"),f=c.find(j.UNWANTEDHIDDENFIELDS);f.each(function(){b(this).remove()});var g=c.serialize();this.modal.hide();var h={type:"GET",processData:!1,contentType:"application/json"},i=d.wwwroot+"/enrol/manual/ajax.php?"+g;b.ajax(i,h).then(function(a){a.error?e.addNotification({message:a.error,type:"error"}):("undefined"!=typeof window.M.core_formchangechecker&&window.M.core_formchangechecker.reset_form_dirty_state(),window.location.reload())}).fail(e.exception)},k.prototype.getBody=function(){return h.loadFragment("enrol_manual","enrol_users_form",this.contextid,{}).fail(e.exception)},k.prototype.getFooter=function(){return a.render("enrol_manual/enrol_modal_footer",{})},{init:function(a){new k(a)}}});
@@ -25,9 +25,6 @@
define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax, Templates, Str) {
/** @var {Number} Maximum number of users to show. */
var MAXUSERS = 100;
return /** @alias module:enrol_manual/form-potential-user-selector */ {
processResults: function(selector, results) {
@@ -57,6 +54,10 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
if (typeof enrolid === "undefined") {
enrolid = '';
}
var perpage = $(selector).attr('perpage');
if (typeof perpage === "undefined") {
perpage = 100;
}
promise = Ajax.call([{
methodname: 'core_enrol_get_potential_users',
@@ -66,7 +67,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
search: query,
searchanywhere: true,
page: 0,
perpage: MAXUSERS + 1
perpage: perpage + 1
}
}]);
@@ -74,7 +75,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
var promises = [],
i = 0;
if (results.length <= MAXUSERS) {
if (results.length <= perpage) {
// Render the label.
$.each(results, function(index, user) {
var ctx = user,
@@ -101,7 +102,7 @@ define(['jquery', 'core/ajax', 'core/templates', 'core/str'], function($, Ajax,
});
} else {
return Str.get_string('toomanyuserstoshow', 'core', '>' + MAXUSERS).then(function(toomanyuserstoshow) {
return Str.get_string('toomanyuserstoshow', 'core', '>' + perpage).then(function(toomanyuserstoshow) {
success(toomanyuserstoshow);
return;
});
+5 -2
View File
@@ -28,8 +28,9 @@ define(['core/templates',
'core/modal_factory',
'core/modal_events',
'core/fragment',
'core/pending',
],
function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment) {
function(Template, $, Str, Config, Notification, ModalFactory, ModalEvents, Fragment, Pending) {
/** @type {Object} The list of selectors for the quick enrolment modal. */
var SELECTORS = {
@@ -91,6 +92,7 @@ define(['core/templates',
});
modal.getRoot().on(ModalEvents.shown, function() {
var pendingPromise = new Pending('enrol_manual/quickenrolment:initModal:shown');
var bodyPromise = this.getBody();
bodyPromise.then(function(html) {
var stringIndex = $(html).find(SELECTORS.COHORTSELECT).length ? 0 : 1;
@@ -98,7 +100,8 @@ define(['core/templates',
return;
})
.fail(Notification.exception);
.then(pendingPromise.resolve)
.catch(Notification.exception);
modal.setBody(bodyPromise);
}.bind(this));
@@ -99,6 +99,7 @@ class enrol_manual_enrol_users_form extends moodleform {
'multiple' => true,
'courseid' => $course->id,
'enrolid' => $instance->id,
'perpage' => $CFG->maxusersperpage,
'userfields' => implode(',', get_extra_user_fields($context))
);
$mform->addElement('autocomplete', 'userlist', get_string('selectusers', 'enrol_manual'), array(), $options);
@@ -154,6 +154,16 @@ Feature: Teacher can search and enrol users one by one into the course
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
Then I should see "Too many users (>100) to show"
@javascript
Scenario: Changing the Maximum users per page setting affects the enrolment pop-up.
Given the following config values are set as admin:
| maxusersperpage | 5 |
And I navigate to course participants
And I press "Enrol users"
When I set the field "Select users" to "student00"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Select users" "form_row"
Then I should see "Too many users (>5) to show"
@javascript
Scenario: Change the Show user identity setting affects the enrolment pop-up.
Given I log out
+148
View File
@@ -855,6 +855,154 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
$this->assertEquals(ENROL_USER_SUSPENDED, $ue->status);
}
/**
* dataProvider for test_submit_user_enrolment_form().
*/
public function submit_user_enrolment_form_provider() {
$now = new DateTime();
$nextmonth = clone($now);
$nextmonth->add(new DateInterval('P1M'));
return [
'Invalid data' => [
'customdata' => [
'status' => ENROL_USER_ACTIVE,
'timestart' => [
'day' => $now->format('j'),
'month' => $now->format('n'),
'year' => $now->format('Y'),
'hour' => $now->format('G'),
'minute' => 0,
'enabled' => 1,
],
'timeend' => [
'day' => $now->format('j'),
'month' => $now->format('n'),
'year' => $now->format('Y'),
'hour' => $now->format('G'),
'minute' => 0,
'enabled' => 1,
],
],
'expectedresult' => false,
'validationerror' => true
],
'Valid data' => [
'customdata' => [
'status' => ENROL_USER_ACTIVE,
'timestart' => [
'day' => $now->format('j'),
'month' => $now->format('n'),
'year' => $now->format('Y'),
'hour' => $now->format('G'),
'minute' => 0,
'enabled' => 1,
],
'timeend' => [
'day' => $nextmonth->format('j'),
'month' => $nextmonth->format('n'),
'year' => $nextmonth->format('Y'),
'hour' => $nextmonth->format('G'),
'minute' => 0,
'enabled' => 1,
],
],
'expectedresult' => true,
'validationerror' => false
],
'Suspend user' => [
'customdata' => [
'status' => ENROL_USER_SUSPENDED,
],
'expectedresult' => true,
'validationerror' => false
],
];
}
/**
* @param array $customdata The data we are providing to the webservice.
* @param bool $expectedresult The result we are expecting to receive from the webservice.
* @param bool $validationerror The validationerror we are expecting to receive from the webservice.
* @dataProvider submit_user_enrolment_form_provider
*/
public function test_submit_user_enrolment_form($customdata, $expectedresult, $validationerror) {
global $CFG, $DB;
$this->resetAfterTest(true);
$datagen = $this->getDataGenerator();
/** @var enrol_manual_plugin $manualplugin */
$manualplugin = enrol_get_plugin('manual');
$studentroleid = $DB->get_field('role', 'id', ['shortname' => 'student'], MUST_EXIST);
$teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher'], MUST_EXIST);
$course = $datagen->create_course();
$user = $datagen->create_user();
$teacher = $datagen->create_user();
$instanceid = null;
$instances = enrol_get_instances($course->id, true);
foreach ($instances as $inst) {
if ($inst->enrol == 'manual') {
$instanceid = (int)$inst->id;
break;
}
}
if (empty($instanceid)) {
$instanceid = $manualplugin->add_default_instance($course);
if (empty($instanceid)) {
$instanceid = $manualplugin->add_instance($course);
}
}
$this->assertNotNull($instanceid);
$instance = $DB->get_record('enrol', ['id' => $instanceid], '*', MUST_EXIST);
$manualplugin->enrol_user($instance, $user->id, $studentroleid, 0, 0, ENROL_USER_ACTIVE);
$manualplugin->enrol_user($instance, $teacher->id, $teacherroleid, 0, 0, ENROL_USER_ACTIVE);
$ueid = (int) $DB->get_field(
'user_enrolments',
'id',
['enrolid' => $instance->id, 'userid' => $user->id],
MUST_EXIST
);
// Login as teacher.
$teacher->ignoresesskey = true;
$this->setUser($teacher);
$formdata = [
'ue' => $ueid,
'ifilter' => 0,
'status' => null,
'timestart' => null,
'timeend' => null,
];
$formdata = array_merge($formdata, $customdata);
require_once("$CFG->dirroot/enrol/editenrolment_form.php");
$formdata = enrol_user_enrolment_form::mock_generate_submit_keys($formdata);
$querystring = http_build_query($formdata, '', '&');
$result = external_api::clean_returnvalue(
core_enrol_external::submit_user_enrolment_form_returns(),
core_enrol_external::submit_user_enrolment_form($querystring)
);
$this->assertEquals(
['result' => $expectedresult, 'validationerror' => $validationerror],
$result,
'', 0.0, 10, true);
if (!empty($result['result'])) {
$ue = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST);
$this->assertEquals($formdata['status'], $ue->status);
}
}
/**
* Test for core_enrol_external::unenrol_user_enrolment().
*/
+3 -3
View File
@@ -949,9 +949,9 @@ class core_files_renderer extends plugin_renderer_base {
<div class="file-picker fp-dlg">
<p class="fp-dlg-text"></p>
<div class="fp-dlg-buttons">
<button class="fp-dlg-butoverwrite btn">'.get_string('overwrite', 'repository').'</button>
<button class="fp-dlg-butrename btn"></button>
<button class="fp-dlg-butcancel btn btn-cancel">'.get_string('cancel').'</button>
<button class="fp-dlg-butoverwrite btn mb-1">'.get_string('overwrite', 'repository').'</button>
<button class="fp-dlg-butrename btn mb-1"></button>
<button class="fp-dlg-butcancel btn btn-cancel mb-1">'.get_string('cancel').'</button>
</div>
</div>';
return $rv;
+1 -1
View File
@@ -85,7 +85,7 @@ class external extends external_api {
} catch (Exception $e) {
$warnings[] = array(
'item' => 'context',
'itemid' => $context['instanceid'],
'itemid' => $contextinfo['instanceid'],
'warningcode' => $e->getCode(),
'message' => $e->getMessage(),
);
+6 -4
View File
@@ -104,14 +104,14 @@ class filter_emoticon extends moodle_text_filter {
}
// Detect all zones that we should not handle (including the nested tags).
$processing = preg_split('/(<\/?(?:span|script)[^>]*>)/is', $text, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$processing = preg_split('/(<\/?(?:span|script|pre)[^>]*>)/is', $text, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
// Initialize the results.
$resulthtml = "";
$exclude = 0;
// Define the patterns that mark the start of the forbidden zones.
$excludepattern = array('/^<script/is', '/^<span[^>]+class="nolink[^"]*"/is');
$excludepattern = array('/^<script/is', '/^<span[^>]+class="nolink[^"]*"/is', '/^<pre/is');
// Loop through the fragments.
foreach ($processing as $fragment) {
@@ -126,13 +126,15 @@ class filter_emoticon extends moodle_text_filter {
}
if ($exclude > 0) {
// If we are ignoring the fragment, then we must check if we may have reached the end of the zone.
if (strpos($fragment, '</span') !== false || strpos($fragment, '</script') !== false) {
if (strpos($fragment, '</span') !== false || strpos($fragment, '</script') !== false
|| strpos($fragment, '</pre') !== false) {
$exclude -= 1;
// This is needed because of a double increment at the first element.
if ($exclude == 1) {
$exclude -= 1;
}
} else if (strpos($fragment, '<span') !== false || strpos($fragment, '<script') !== false) {
} else if (strpos($fragment, '<span') !== false || strpos($fragment, '<script') !== false
|| strpos($fragment, '<pre') !== false) {
// If we find a nested tag we increase the exclusion level.
$exclude = $exclude + 1;
}
+15
View File
@@ -95,6 +95,21 @@ class filter_emoticon_testcase extends advanced_testcase {
'format' => FORMAT_HTML,
'expected' => '<span class="nolink"><span>(n)</span>(n)</span>' . $this->get_converted_content_for_emoticon('(n)'),
],
'Basic pre should not be processed' => [
'input' => '<pre>(n)</pre>',
'format' => FORMAT_HTML,
'expected' => '<pre>(n)</pre>',
],
'Nested pre should not be processed' => [
'input' => '<pre><pre>(n)</pre>(n)</pre>',
'format' => FORMAT_HTML,
'expected' => '<pre><pre>(n)</pre>(n)</pre>',
],
'Nested pre should not be processed but following emoticon' => [
'input' => '<pre><pre>(n)</pre>(n)</pre>(n)',
'format' => FORMAT_HTML,
'expected' => '<pre><pre>(n)</pre>(n)</pre>' . $this->get_converted_content_for_emoticon('(n)'),
],
];
}
+12
View File
@@ -189,5 +189,17 @@ MathJax.Hub.Config({
// Automatically generated Moodle v3.6.0 release upgrade line.
// Put any upgrade step following this.
if ($oldversion < 2018120301) {
// Update CDN url.
$originalurl = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js';
$newurl = 'https://cdn.jsdelivr.net/npm/mathjax@2.7.8/MathJax.js';
$currenturl = get_config('filter_mathjaxloader', 'httpsurl');
if ($currenturl == $originalurl) {
set_config('httpsurl', $newurl, 'filter_mathjaxloader');
}
upgrade_plugin_savepoint(true, 2018120301, 'filter', 'mathjaxloader');
}
return true;
}
+6 -1
View File
@@ -1,7 +1,7 @@
Description of MathJAX library integration in Moodle
====================================================
* Default MathJax version: 2.7.2
* Default MathJax version: 2.7.8
* License: Apache 2.0
* Source: https://www.mathjax.org/
@@ -18,3 +18,8 @@ Upgrading the default MathJax version
3. Check and eventually update the list of language mappings in filter.php.
Also see the unit test for the language mappings.
Changes
-------
* The MathJax 2.7.2 seems to have a possible security issue, the CDN default value have been
updated to point to the recommended 2.7.8 version. See MDL-68430 for details.
+1 -1
View File
@@ -33,7 +33,7 @@ if ($ADMIN->fulltree) {
$item = new admin_setting_configtext('filter_mathjaxloader/httpsurl',
new lang_string('httpsurl', 'filter_mathjaxloader'),
new lang_string('httpsurl_help', 'filter_mathjaxloader'),
'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js',
'https://cdn.jsdelivr.net/npm/mathjax@2.7.8/MathJax.js',
PARAM_RAW);
$settings->add($item);
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018120300;
$plugin->version = 2018120301;
$plugin->requires = 2018112800; // Requires this Moodle version.
$plugin->component= 'filter_mathjaxloader';
+8
View File
@@ -19,6 +19,14 @@
margin: auto;
}
/* This is needed to display videos in an adequate size and without too much space
withing the specific mod assign table views. */
.path-mod-assign .gradingtable .mediaplugin,
.path-mod-assign .submissionsummarytable .mediaplugin {
width: 400px;
height: auto;
}
/* Make media plugin behave properly in mod summaries and labels */
.mod-indent-outer .mediaplugin {
display: table-cell;
+9
View File
@@ -187,5 +187,14 @@ class core_filter_external_testcase extends externallib_advanced_testcase {
$this->assertEquals($firstfilter, $result['filters'][0]['filter']); // OK, the filter is enabled globally.
$this->assertEquals(TEXTFILTER_OFF, $result['filters'][0]['localstate']); // It is not available in this context.
$this->assertEquals(TEXTFILTER_ON, $result['filters'][0]['inheritedstate']); // In the parent context is available.
// Try user without permission, warning expected.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$result = external::get_available_in_context(array(array('contextlevel' => 'module', 'instanceid' => $forum->cmid)));
$result = external_api::clean_returnvalue(external::get_available_in_context_returns(), $result);
$this->assertNotEmpty($result['warnings']);
$this->assertEquals('context', $result['warnings'][0]['item']);
$this->assertEquals($forum->cmid, $result['warnings'][0]['itemid']);
}
}
+4 -2
View File
@@ -322,8 +322,10 @@ class grading_manager {
}
} else if ($this->get_context()->contextlevel == CONTEXT_MODULE) {
list($context, $course, $cm) = get_context_info_array($this->get_context()->id);
return self::available_areas('mod_'.$cm->modname);
$modulecontext = $this->get_context();
$coursecontext = $modulecontext->get_course_context();
$cm = get_fast_modinfo($coursecontext->instanceid)->get_cm($modulecontext->instanceid);
return self::available_areas("mod_{$cm->modname}");
} else {
throw new coding_exception('Unsupported gradable area context level');

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