Compare commits

..

260 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 23360fd95b Moodle release 3.2.4 2017-07-08 20:43:34 +02:00
AMOS bot 0ed1c5d259 Automatically generated installer lang files 2017-07-08 00:16:24 +08:00
Jake Dallimore 28f52bc329 weekly release 3.2.3+ 2017-07-07 12:10:16 +08:00
Jake Dallimore 8c18772edc Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-07-07 12:10:14 +08:00
AMOS bot dd819dbb88 Automatically generated installer lang files 2017-07-07 00:06:39 +08:00
Simey Lameze 4c48d88c46 MDL-59456 auth_cas: patch phpCAS auth bypass vulnerability 2017-07-06 09:33:27 +01:00
Jun Pataleta af16b393ea MDL-58651 logstore_database: Set dbhandlesoptions in test page 2017-07-05 23:04:51 +08:00
Dan Poltawski 2dc0dc6293 MDL-57021 passwords: only use unmask field with shared secrets
When a user is entering a password which isn't returned back to them
then its not correct to use the unmask element - this element was
designed for places where we are storing shared secrets.
2017-07-05 12:25:41 +02:00
Eloy Lafuente (stronk7) a3aa1600de Merge branch 'MDL-59398-32-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-07-05 11:52:42 +02:00
Eloy Lafuente (stronk7) fb629ce56a Merge branch 'MDL-59294-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-07-05 09:44:54 +02:00
Eloy Lafuente (stronk7) 33f31a12d4 Merge branch 'MDL-58286-32' of https://github.com/xow/moodle into MOODLE_32_STABLE 2017-07-05 09:40:55 +02:00
Helen Foster 92033f7e9d MDL-59398 lang: Merge English strings from the en_fix language pack 2017-07-05 09:34:14 +02:00
John Okely 8e28bc402b MDL-58286 enrol_ldap: Pass connection to ldap_paged_results_supported
Thanks to Bianco Veigel for the original patch.
2017-07-05 09:50:10 +08:00
Eloy Lafuente (stronk7) 1cee1602be Merge branch 'MDL-58651_32' of git://github.com/aolley/moodle into MOODLE_32_STABLE 2017-07-05 01:23:39 +02:00
Jake Dallimore bea116e2ff Merge branch 'MDL-59380-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-07-04 16:29:36 +08:00
Marina Glancy 106eb4921a MDL-59409 admin: set admin user in unittest 2017-07-04 11:05:24 +08:00
Ankit Agarwal bc1d916868 MDL-56565 forum: Add sitename as heading when there is nothing to display 2017-07-04 10:11:39 +08:00
Ankit Agarwal a053131595 MDL-56565 forum: Make sure userfullname is not disclosed 2017-07-04 10:11:39 +08:00
Jake Dallimore f3b9685ad0 MDL-56565 navigation: fix for cap checks in nav and context header
Fix to:
- Make sure we properly check both user and course contexts in
the load_for_user function in navigation lib and user the
user_can_view_profile function for same-course access checks.
- Use user_can_view_profile in the renderer's context_header to
properly decide whether a user can view another user's picture
and messaging options in the page header.
2017-07-04 10:11:39 +08:00
Jake Dallimore 93e09909ab MDL-56565 navigation: fix user details disclosure in nav tree
Fixes a bug in which a user's full name might be disclosed via the
nav tree. Nav generation now checks the current user's access to the
user before adding the node, else adds a dummy node.
2017-07-04 10:11:39 +08:00
Jake Dallimore f373c08314 MDL-56565 core: fix user details disclosure in page context header
Fixes a bug with context_header function in which user details were
displayed regardless of the current user's capabilities.
2017-07-04 10:11:39 +08:00
Marina Glancy dacac4d10b MDL-59409 admin: check access to every setting in category 2017-07-04 10:03:42 +08:00
Jake Dallimore 35d1b3da7a weekly release 3.2.3+ 2017-06-29 16:23:47 +08:00
Jake Dallimore a52742dea7 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-06-29 16:23:46 +08:00
Jun Pataleta ffd642a654 MDL-59294 block_login: Make display of ID provider buttons consistent 2017-06-29 09:36:56 +08:00
Mark Nelson dbbbf02dc0 MDL-56046 mod_quiz: do not close the sheet twice 2017-06-28 14:15:36 +08:00
Jun Pataleta e29ea1b2c9 MDL-59294 theme_bootstrapbase: Fix display of ID provider buttons 2017-06-28 13:39:02 +08:00
Jake Dallimore 74accbdd85 Merge branch 'wip-MDL-59308-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-06-28 13:10:16 +08:00
Adam Olley eea5900c13 MDL-58651 logstore_database: Add ability to not send database options
In the core dml:
PostgreSQL connections now use advanced options to reduce connection overhead.
These options are not compatible with some connection poolers. The
dbhandlesoptions parameter has been added to allow the database to configure
the required defaults.

This item adds a setting to the logstore_database plugin to let you set the
same flag for your destination database - without it you won't be able to ship
logs to a postgresql database with a pgbouncer frontend.
2017-06-28 13:20:36 +09:30
Marina Glancy 01005ff69a MDL-59308 calendar: pass module context when known
this will protect us from exceptions when context for removed instance can not be retrieved
2017-06-28 11:18:03 +08:00
Eloy Lafuente (stronk7) ee3ba0c3f8 Merge branch 'MDL-57809-32-progressbar' of https://github.com/roperto/moodle into MOODLE_32_STABLE 2017-06-27 20:17:55 +02:00
Eloy Lafuente (stronk7) 5bbc58a7fb Merge branch 'wip-MDL-59136-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-06-27 18:09:50 +02:00
David Monllao c6a447f1b7 Merge branch 'MDL-32151-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-06-27 17:47:47 +02:00
Eloy Lafuente (stronk7) 2584ce25c7 Merge branch 'MDL-59362_32' of git://github.com/markn86/moodle into MOODLE_32_STABLE 2017-06-27 17:22:11 +02:00
Danny Jung 2dd87cb37a MDL-59073 Workshop: Prevent submission without content or file 2017-06-27 17:06:02 +02:00
David Monllao 53456587f6 Merge branch 'MDL-59158-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-06-27 16:40:07 +02:00
David Monllao b9874d0c13 Merge branch 'MDL-57927-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-27 15:55:40 +02:00
Eloy Lafuente (stronk7) bf58adf836 Merge branch 'MDL-58844-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-06-27 11:42:22 +02:00
Eloy Lafuente (stronk7) afeb42ed9e Merge branch 'MDL-59296-32' of git://github.com/crazyserver/moodle into MOODLE_32_STABLE 2017-06-27 11:40:10 +02:00
Jake Dallimore 52cabc8f66 Merge branch 'MDL-59312-32' of https://github.com/xow/moodle into MOODLE_32_STABLE 2017-06-27 15:10:41 +08:00
Damyon Wiese 4197baf775 MDL-59380 fragments: Include js from templates
Mustache templates containing {{#js}} blocks are not returned via the
fragments API. This is because the requirements manager is assigned when the renderer is created
and not updated by the call to start collecting page requirements.
2017-06-27 13:35:40 +08:00
Jake Dallimore ba9f218e17 Merge branch 'MDL-56046_32-fix' of git://github.com/markn86/moodle into MOODLE_32_STABLE 2017-06-27 13:18:50 +08:00
Mark Nelson 32dc9a45d6 MDL-56046 dataformat: minor changes to PHPDocs and upgrade.txt 2017-06-27 11:26:35 +08:00
Andrew Nicols 8c696ccafc MDL-58844 testing: Move to GCE build infrastructure
Switch back to GCE build infrastructure for Travis Builds and move
databases to RAM Disk.

This also adds a software entropy generator (haveged) which is
recommended when using a RAMdisk for the database.
2017-06-27 09:39:20 +08:00
Eloy Lafuente (stronk7) 0bfbdaef20 Merge branch 'MDL-56046_32' of git://github.com/markn86/moodle into MOODLE_32_STABLE 2017-06-27 02:43:00 +02:00
Eloy Lafuente (stronk7) 55fc1104d5 Merge branch 'MDL-40818-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-06-27 01:50:48 +02:00
Eloy Lafuente (stronk7) 7032ff37b7 Merge branch 'MDL-59295-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-27 00:54:25 +02:00
Eloy Lafuente (stronk7) 1d0867ae48 Merge branch 'mdl58813-moodle32' of https://github.com/tlock/moodle into MOODLE_32_STABLE 2017-06-26 19:38:51 +02:00
Mark Nelson 4e50a38018 MDL-56046 core: enable multiple sheets for flexible table 2017-06-26 13:55:21 +08:00
Mark Nelson a54703d88f MDL-56046 dataformat: added related information to upgrade.txt 2017-06-26 13:55:21 +08:00
Mark Nelson 4ba0709401 MDL-56046 dataformat_*: convert core plugins 2017-06-26 13:28:02 +08:00
Mark Nelson f72bc10fe3 MDL-56046 core: convert download_as_dataformat to use new API 2017-06-26 13:28:02 +08:00
Mark Nelson b15859b879 MDL-56046 core_dataformat: added functions to support multiple sheets
Also removed write_header() and write_footer(). The reason for this
is because in core we want to know if the format being used supports
multiple sheets. To do this, and ensure we do not break third-party
dataformat plugins, we are using method_exist(). If write_header()
and write_footer() remain in the base class then this will always
be true.
2017-06-26 13:19:09 +08:00
Mark Nelson ed248331a4 MDL-59362 core: ensure we use 'new' when throwing exceptions 2017-06-26 13:10:43 +08:00
Marina Glancy 5b8ca7ac93 MDL-59136 roles: avoid double escaping in role names 2017-06-26 11:57:49 +08:00
Jake Dallimore 0efb93bbe9 Merge branch 'MDL-49484-moodle32' of github.com:jebarviabb/moodle into MOODLE_32_STABLE 2017-06-26 10:52:49 +08:00
Josh Ebarvia f3008f556c MDL-49484 mod_lesson: Fix lesson page headers when editing 2017-06-24 05:23:16 +09:30
AMOS bot aac5a4f103 Merge branch 'MOODLE_32_STABLE' into install_32_STABLE 2017-06-24 00:09:03 +08:00
Pau Ferrer Ocaña e5881ad801 MDL-59296 data: Fix latlong field search 2017-06-23 09:15:31 +02:00
Andrew Nicols c244743775 MDL-59312 js: Improve display of exception stacktrace 2017-06-23 10:50:11 +08:00
John Okely deb442a293 MDL-59312 notification: Normalise backtrace/stacktrace 2017-06-23 10:50:11 +08:00
Andrew Nicols 93a935049e MDL-59312 js: Add exception on AJAX error 2017-06-23 10:50:11 +08:00
Jun Pataleta f2fb8f5a7f MDL-32151 group: Use appropriate error langstring error key 2017-06-23 10:28:13 +08:00
Jun Pataleta 3a5ae742f1 MDL-32151 grade: Use appropriate error langstring error key 2017-06-23 10:28:13 +08:00
Jun Pataleta 017d8f1aec MDL-59158 theme_boost: Remove auto width and height for user picture 2017-06-23 10:13:00 +08:00
Jun Pataleta 95e1ac08fe MDL-40818 calendar: Require login to calendar pages
* Make sure that the course ID being passed points to an existing course
* Require user to login before granting access to calendar pages.
2017-06-23 09:21:05 +08:00
Daniel Thee Roperto ef43566698 MDL-57809 weblib: Added missing NO_OUTPUT_BUFFERING directive. 2017-06-23 09:42:37 +10:00
Daniel Thee Roperto d33f7642dd MDL-57809 weblib: Added opening disclaimer and file-level phpdocs. 2017-06-23 09:42:37 +10:00
Daniel Thee Roperto a9a72025b6 MDL-57809 weblib: Progress bar and output buffer - added debugging
This fix makes Moodle show a debbuging message if using progressbar without defining NO_OUTPUT_BUFFERING.
2017-06-23 09:42:37 +10:00
AMOS bot 222189cc75 Automatically generated installer lang files 2017-06-23 00:08:05 +08:00
Dan Poltawski 62c58d22be weekly release 3.2.3+ 2017-06-22 15:40:47 +01:00
Simey Lameze b962ac2439 MDL-59295 tool_lp: remove useless ng-label attribute 2017-06-22 15:49:46 +08:00
Tim Lock c2f08942d9 MDL-58813 webservice: create_courses() initialise all section records 2017-06-22 11:13:38 +09:30
Eloy Lafuente (stronk7) 9072b59c0e Merge branch 'MDL-59217-32' of git://github.com/ryanwyllie/moodle into MOODLE_32_STABLE 2017-06-20 20:40:45 +02:00
Eloy Lafuente (stronk7) f86bb360b5 Merge branch 'MDL-59269-32-languninstall' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-06-20 17:57:15 +02:00
Mathieu Petit-Clair 90e86c7568 MDL-58952 admin: use valid default for language selection dropdown. 2017-06-20 11:31:55 +01:00
Dan Poltawski f730eb2a81 Merge branch 'MDL-59005-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-20 09:52:46 +01:00
Dan Poltawski 485decb3a2 Merge branch 'MDL-58472-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-06-20 09:36:53 +01:00
Jun Pataleta b95a012124 Merge branch 'MDL-57770-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-20 16:28:31 +08:00
Jake Dallimore f7e3be1bbb Merge branch 'wip-MDL-58729-32' of git://github.com/abgreeve/moodle into MOODLE_32_STABLE 2017-06-20 15:19:13 +08:00
Simey Lameze 5a5efa8bd9 MDL-57927 tool_lp: make both buttons consistent 2017-06-20 08:50:32 +08:00
Dan Poltawski 079c73c98d Merge branch 'MDL-59048_32' of https://github.com/timhunt/moodle into MOODLE_32_STABLE 2017-06-19 15:43:19 +01:00
Dan Poltawski 3fb4b3a9ed Merge branch 'MDL-59173-32' of git://github.com/tobiasreischmann/moodle into MOODLE_32_STABLE 2017-06-19 12:27:45 +01:00
Dan Poltawski c7d6a0e356 Merge branch 'wip-MDL-51917-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-06-19 12:21:50 +01:00
Dan Poltawski 8b57dd0768 Merge branch 'MDL-46418-32-hiddenrepos' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-06-19 10:33:34 +01:00
Jun Pataleta 97d966df08 Merge branch 'MDL-44961-32' of git://github.com/ankitagarwal/moodle into MOODLE_32_STABLE 2017-06-19 16:25:18 +08:00
Jun Pataleta fe67ec46da Merge branch 'MDL-58310-32' of https://github.com/xow/moodle into MOODLE_32_STABLE 2017-06-19 13:26:46 +08:00
John Okely 285e7e5eb3 MDL-58310 ajax: suppress errors upon page unload 2017-06-19 11:45:45 +08:00
John Okely 53e3825619 MDL-58310 message: No longer need to supress errors from messaging 2017-06-19 11:45:45 +08:00
Vladimir Zhirov 90156e427c MDL-59005 resource: fixed zip extraction for filenames in CP-1251/CP-866 2017-06-19 08:51:19 +08:00
David Mudrák 5074849703 MDL-59269 lang: Fix ability to uninstall certain language packs
In the issue MDL-39319 (6ddf92c77), the ability to uninstall multiple
language packs at once was added. By a mistake, the PARAM_ALPHAEXT was
used as paramater type for the dash-separated list of language packs to
be uninstalled. Language packs with a number in the name (such as
en_us_k12) do not pass the ALPHAEXT cleaning.

This patch changes the parameter cleaning to PARAM_SAFEPATH which is
more appropriate for the given scenario as language code themselves must
be SAFEDIRs.
2017-06-16 14:15:31 +02:00
Tobias Reischmann c5a8568799 MDL-59173 tablelib.php: changed default of $params in set_sql to array()
Default of $params = null leads to a problem in query_db().
There this value is used in array_merge, which can not handle null
values. If null is passed for one of the params the outcome will be null
independent of the value of the second param!
2017-06-16 10:27:21 +02:00
Jake Dallimore ab7056032d weekly release 3.2.3+ 2017-06-16 13:29:36 +08:00
David Mudrák 0d063c69ac MDL-46418 repositories: Fix how enabled repositories are populated
Repository instances are stored in the 'repository' table. Repositories
in the table are either 'Enabled and visible' or 'Enabled but hidden'.
Hidden repositories still serve their files, but are not visible in the
filepicker UI. Disabling a repository instance removes its record from
the table.

In the original implementation of the plugin manager (see b9934a17), the
method plugintype_repository::get_enabled_repositories() correctly
returned all records from the repository table. Then as a part of the
bigger refactoring in MDL-41437, the commit bde002b8 replaced the
original method with the new get_enabled_plugins() one which started to
return visible repositories only.

As a consequence, the admin tree stopped populating setting page nodes
for hidden repository instances. So attempting to visit their setting
page threw a section error. Credit goes to Ike Quigley for debugging and
tracing this down.

This patch fixes the way how the list of enabled repositories is
populated by the plugin manager so that both visible and hidden
repositories are returned again. This does not affect the filepicker
itself as it is using its own methods for obtaining the list.
2017-06-15 21:22:48 +02:00
Simey Lameze ac6ab5b8d2 MDL-57770 tool_lp: style fixes for the competency rule dialog 2017-06-15 15:39:17 +08:00
Ankit Agarwal 74fbdebd0d MDL-59217 restore: Check for userride only for activity events 2017-06-15 06:02:38 +00:00
Mark Nelson e523626603 MDL-59140 core: apply limit only on courses to be shown in specific nav
There can be a different number of courses displayed in the
'Navigation' block and in the 'Flat' navigation. This patch
decides what courses we want to display on each, then
applies the 'navcourselimit' setting individually.
2017-06-15 13:36:35 +08:00
Ankit Agarwal c33e03ae95 MDL-44961 logs: Keep log dates constant during restore 2017-06-14 15:21:36 +05:30
Jake Dallimore b3f3c3c395 Merge branch 'MDL-59142-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-14 11:40:13 +08:00
Dan Poltawski 072c0b4196 Merge branch 'MDL-59171-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-06-13 14:40:47 +01:00
Dan Poltawski 638aa54cbb Merge branch 'MDL-59140_32' of git://github.com/markn86/moodle into MOODLE_32_STABLE 2017-06-13 13:23:39 +01:00
Mark Nelson 8d9e621f2c MDL-59140 core: upgrade 'navcourselimit' if set to old default value 2017-06-13 18:27:04 +08:00
Mark Nelson bb3956eb5c MDL-59140 core: limit the number of courses shown in the navigation
If the user is enrolled in more courses than the limit then a 'More...'
link is displayed which takes the user to the course/index.php page.
2017-06-13 18:27:04 +08:00
Mark Nelson a8fc3a33ab MDL-59140 core: changes to the 'navcourselimit' setting
Changed the default and description.
2017-06-13 18:23:52 +08:00
Eloy Lafuente (stronk7) 2c6f3befeb Merge branch 'wip-MDL-58523-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-06-13 11:21:48 +02:00
Jun Pataleta d11850101e Merge branch 'MDL-58991-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-14 16:56:36 +08:00
Dan Poltawski 531c1ec0be Merge branch 'MDL-41426_32-block-completionstatus-spaces' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-06-13 09:53:56 +01:00
Eloy Lafuente (stronk7) 8ae8ed4aca MDL-46322 database: alias sort fields to avoid ambiguous naming 2017-06-13 09:17:08 +01:00
Jake Dallimore 1faba07075 Merge branch 'MDL-58136-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-06-13 15:55:45 +08:00
Damyon Wiese 587b99609d MDL-58136 course: Remove lines from unit test
Remove unused vars and logic from the unit test for classifying a course.
2017-06-13 15:08:18 +08:00
Marina Glancy c9192ffccb MDL-51917 course completion: order activities in reports
Thanks to Nick Phillips for initial patch
2017-06-13 14:49:24 +08:00
Marina Glancy 4290182491 MDL-58523 mod_feedback: deleting response should reset completion 2017-06-13 14:36:35 +08:00
Jake Dallimore cb1c0ae4dc Merge branch 'MDL-51691-moodle32' of https://github.com/jebarviabb/moodle into MOODLE_32_STABLE 2017-06-13 10:35:37 +08:00
Damyon Wiese ffc7fda945 MDL-58136 navigation: Ensure we have all course fields
To properly classify courses we need the start/end dates etc.
2017-06-13 10:10:22 +08:00
Marcus Green a9ba142326 MDL-58248 theme_boost: label/span for sidepanel expand button
Add string "Side panel" to make the purpose of
trigram/hamburger icon at top left clearer, particularly
when using screen readers e.g. Jaws/NVDA.
Currently it reads out only "expand"
2017-06-13 09:51:07 +08:00
Simey Lameze 59527f3e7a MDL-59142 core_theme: cache post-processed css
Thanks Cameron Ball for the base patch
2017-06-13 09:39:56 +08:00
Damyon Wiese 8122557661 MDL-58472 videojs: Force manual initialise
If we let videojs auto-init the video/audio tags present in the page - we cannot guarantee that the
youtube library will be loaded by the time video.js is processing the tag.

Video.js uses the presence of a data-setup attibute to signal that it should auto-init this tag, so
we have to rename our config attribute to something else.
2017-06-13 09:13:07 +08:00
Eloy Lafuente (stronk7) ae84db35c7 Merge branch 'MDL-40015-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-06-13 01:23:52 +02:00
Eloy Lafuente (stronk7) ab8b6fae1a Merge branch 'mdl58161-moodle32' of https://github.com/tlock/moodle into MOODLE_32_STABLE 2017-06-13 01:22:09 +02:00
Josh Ebarvia b3ca553f3a MDL-51691 assignsubmission_feedback: Fix delete comments 2017-06-13 08:39:08 +09:30
Tim Lock 7e31bb6dc2 MDL-58161 user: tests: user_can_view_profile fails under certain cases 2017-06-13 08:09:14 +09:30
Eloy Lafuente (stronk7) 5e39900691 Merge branch 'MDL-59112-32' of git://github.com/jleyva/moodle into MOODLE_32_STABLE 2017-06-12 14:39:22 +02:00
Dan Poltawski a4f5cdddcf Merge branch 'mdl46322-moodle32' of https://github.com/AndresMelo/moodle into MOODLE_32_STABLE 2017-06-12 10:29:53 +01:00
Damyon Wiese 4d26fcd737 MDL-58136 cache: Add a course completion cache
The last change added 1 db read per course per page which is not OK. Add a cache to compensate.
2017-06-12 16:11:52 +08:00
Damyon Wiese 11127354db MDL-58136 boost: Limit courses in flatnav
Only show "in-progress" courses in the boost flat navigation (as per the myoverview block).
2017-06-12 16:09:56 +08:00
Adrian Greeve f751b97393 MDL-58729 database: Improve performance of CLI tool.
Imporve the speed with which mysql_collation converts to
a different collation.
2017-06-12 14:15:34 +08:00
Jake Dallimore 9265a5db56 Merge branch 'MDL-57103-32' of https://github.com/xow/moodle into MOODLE_32_STABLE 2017-06-12 13:59:57 +08:00
Jun Pataleta f5942f3e6f Merge branch 'MDL-59154-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-06-12 13:45:33 +08:00
John Okely 3ad8f33235 MDL-57103 lib: Force ajax renderer for all ajax fatal errors 2017-06-12 10:37:37 +08:00
Jun Pataleta abeb033dfb MDL-59171 mod_lti: Set mod_lti_view_lti's type to 'read' 2017-06-12 08:34:52 +08:00
Luca Bösch 98b955d665 MDL-41426 block: Whitespace lacking in completion status block 2017-06-08 19:10:21 +02:00
Dan Poltawski 7624f86fb2 weekly release 3.2.3+ 2017-06-08 12:16:21 +01:00
Dan Poltawski 7f4835a7da Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-06-08 12:16:20 +01:00
Juan Leyva ba76815aaf MDL-40015 core_course: Fix description of duplicate_course WS
It said that the duplication didn’t include user data, but that’s not
true since there is a parameter to include it.
2017-06-08 10:20:46 +01:00
Juan Leyva 70dcc1e39a MDL-59112 theme_clean: Always return expected moodle_url
The function was returned some times a moodle_url object and another
times just a string with a relative URL.
2017-06-08 09:40:47 +01:00
Andrew Nicols 25ffa9a67f MDL-59154 theme: Lock for all caching builds
The previous behaviour was to only lock when in theme designer mode.
As a result, when generating the theme for after a reset, each new
client was starting the generation afresh and no locking was taking
place at all.
2017-06-08 12:05:39 +08:00
Dan Poltawski 99864cdf74 Merge branch 'MDL-59101-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-06-07 16:26:21 +01:00
Jun Pataleta d356128f05 MDL-59101 calendar: Properly calculate expected until date 2017-06-07 23:12:52 +08:00
Dan Poltawski c33c78a33c Merge branch 'MDL-58658_32' of https://github.com/sk-unikent/moodle into MOODLE_32_STABLE 2017-06-06 10:01:44 +01:00
Dan Poltawski 3ec562a322 Merge branch 'MDL-59086_32' of git://github.com/markn86/moodle into MOODLE_32_STABLE 2017-06-06 08:44:52 +01:00
Simey Lameze 07e6a3c6c1 MDL-58991 report_stats: use same date handling on chart rendering
This commmit fixes applies the same date handling used on stats
table render to the charts render.
2017-06-06 13:56:04 +08:00
Jun Pataleta 5ec875b281 Merge branch 'MDL-58646-32' of git://github.com/danpoltawski/moodle into MOODLE_32_STABLE 2017-06-06 12:24:46 +08:00
Jake Dallimore a202546fd3 Merge branch 'MDL-58900-32' of git://github.com/lameze/moodle into MOODLE_32_STABLE 2017-06-06 11:40:12 +08:00
Eloy Lafuente (stronk7) 589b4c0360 Merge branch 'MDL-58826_32_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_32_STABLE 2017-06-06 01:45:17 +02:00
Dan Poltawski 5f6cf92f97 Merge branch 'MDL-59080_M32' of git://github.com/lazydaisy/moodle into MOODLE_32_STABLE 2017-06-05 12:49:48 +01:00
Mark Johnson 43391de3e2 MDL-58826 theme_boost: Prevent fatal errors in action menu behat steps 2017-06-05 09:04:06 +01:00
AMOS bot fbf621bd29 Automatically generated installer lang files 2017-06-04 00:07:23 +08:00
AMOS bot 5a10b55442 Automatically generated installer lang files 2017-06-04 00:07:23 +08:00
AMOS bot 554167b43a Automatically generated installer lang files 2017-06-03 00:07:58 +08:00
Dan Poltawski c90e9381d2 MDL-58646 lib: import latest sabberworm/PHP-CSS-Parser
This version includes a fix[1] contributed by Frédéric Massart investigating
our compilation time issues, which significantly improves the speed of
processing font awesome.

Thanks, Fred!

[1] https://github.com/sabberworm/PHP-CSS-Parser/pull/120
2017-06-02 11:03:51 +01:00
Mary Evans 8ac3e5ea59 MDL-59080 theme_boost: make drawer.scss variables default
--author="Urs Hunkler <urs.hunkler@unodo.de>"
2017-06-02 07:58:43 +01:00
Dan Poltawski 74554368a0 weekly release 3.2.3+ 2017-06-01 09:28:23 +01:00
Dan Poltawski 6f4d9a89d5 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-06-01 09:28:22 +01:00
Jake Dallimore 7fd70c34a0 Merge branch 'MDL-59094-32' of git://github.com/danpoltawski/moodle into MOODLE_32_STABLE 2017-06-01 15:29:15 +08:00
AMOS bot a31c6bc4b9 Automatically generated installer lang files 2017-06-01 00:12:41 +08:00
Dan Poltawski 6160631e28 Merge branch 'MDL-59093-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-05-31 11:09:27 +01:00
Dan Poltawski c82ad7c6e0 MDL-59094 npm: Update shrinkwrap file to npm 5 generated
Starting with npm version 5, npm install will generate a lockfile
(now named package-lock.json) or update the existing npm-shrinkwrap.json

To prevent changes being generated in the codebase when this happens, we
need to commit the version 5 generated shrinkwrap.

This is related to a general overhaul [1] of how npm manages things. But
for our purposes, we the lockfile should be BC to previous versions [2].

Going forward, we need to ensure we generate the lockfile on npm >=5 to
prevent differences from the previously un-versioned lockfile.

[1] http://blog.npmjs.org/post/161081169345/v500
[2] https://github.com/npm/npm/issues/16728#issuecomment-305104149
2017-05-31 10:13:45 +01:00
Jun Pataleta 087ab1e345 MDL-59093 calendar: Use a fixed start day for forever BYMONTH test 2017-05-31 15:02:15 +08:00
Simey Lameze f7c9dd2158 MDL-58900 mod_assign: fix incorrect overrides ordering 2017-05-31 10:51:01 +08:00
Jake Dallimore 984bcd770c Merge branch 'MDL-54887-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-05-31 08:40:43 +08:00
Eloy Lafuente (stronk7) e84d284e65 Merge branch 'MDL-49988_fix_wiki_preview_32_STABLE' of https://github.com/DMaterka/moodle into MOODLE_32_STABLE 2017-05-31 00:30:45 +02:00
Dan Poltawski 352b9b00d6 Merge branch 'MDL-58997_32-group-names-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-30 16:56:23 +01:00
Luca Bösch 2a7bb7a0f8 MDL-58997 calendar: Group names passing multilang filters. 2017-05-30 16:52:07 +02:00
Dan Poltawski 269e1f027e Merge branch 'MDL-49040-moodle32' of https://github.com/jebarviabb/moodle into MOODLE_32_STABLE 2017-05-30 11:42:35 +01:00
Jun Pataleta 48903d67ea Merge branch 'MDL-57313-32-clibootswatch' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-05-30 16:58:15 +08:00
Jun Pataleta 3bfdb64f43 MDL-54887 calendar: PR fixes
* Use the calendar_event::description property and format it using
format_text() on it in order to apply the appropriate filters.
* Then use html_to_text() on it to strip the tags and convert the
description to plain text while converting <br> and <p> tags to
line breaks.
2017-05-30 16:53:57 +08:00
Soon-Systems a42233487e MDL-54887 calendar: Format summary + description of an event for export 2017-05-30 16:53:57 +08:00
Mark Nelson 07da0155a7 MDL-59086 gradereport_grader: style 'Save changes' button 2017-05-30 13:44:15 +08:00
AMOS bot 1a7cf17ed8 Automatically generated installer lang files 2017-05-28 14:07:41 +08:00
David Mudrák 818bc4c9a7 MDL-57313 boost: Fix the CLI utility import-bootswatch.php 2017-05-26 09:48:28 +02:00
Dan Poltawski 8708ea0968 weekly release 3.2.3+ 2017-05-24 19:14:43 +01:00
Dan Poltawski cdffe52b28 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-05-24 19:14:41 +01:00
Tim Hunt 67970b8675 MDL-59048 user tours: avoid white-on-white text in Clean 2017-05-24 17:25:23 +01:00
AMOS bot d979b4614d Automatically generated installer lang files 2017-05-25 00:04:44 +08:00
Andrew Nicols 85eacc3a31 MDL-58577 stats: Correct groupby when getting report options 2017-05-23 19:46:55 +08:00
Andrew Nicols bfc16e66a5 Merge branch 'MDL-58577_32-statistics-report-header-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-23 19:45:56 +08:00
Luca Bösch 3a8f07f241 MDL-58577 stats: Use multilang with role in header 2017-05-23 11:14:09 +02:00
Jun Pataleta e621a47c48 Merge branch 'MDL-58895-32' of git://github.com/ankitagarwal/moodle into MOODLE_32_STABLE 2017-05-23 16:54:35 +08:00
Jake Dallimore 4bb9787760 Merge branch 'MDL-58921_32-calculated-question-name-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-23 16:27:06 +08:00
Jun Pataleta 2469a838f1 Merge branch 'MDL-58165-32' of https://github.com/abias/moodle into MOODLE_32_STABLE 2017-05-23 14:47:38 +08:00
Ankit Agarwal c28e5eaee2 MDL-58895 groups: Add bootstrap classes to buttons 2017-05-23 12:05:42 +05:30
Alexander Bias f85f0c80da MDL-58165 navigation: Add node key to private files navigation node 2017-05-23 07:24:11 +02:00
Josh Ebarvia 4643358a5c MDL-49040 gradereport_grader: Fix feedback truncation after & char 2017-05-23 13:04:23 +09:30
AMOS bot 2774649389 Automatically generated installer lang files 2017-05-23 00:05:47 +08:00
Dan Poltawski 18d41005e3 Merge branch 'MDL-58922_32-calculatedmulti-question-name-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-22 10:44:52 +01:00
Luca Bösch a281621189 MDL-58921 questions: Calculated question name passing multilang.
In edit calculated question the question name does pass format_string to process multilang tags.
2017-05-22 11:37:22 +02:00
Luca Bösch ab8fa2ff7a MDL-58922 questions: Calculatedmulti question name passing multilang.
In edit calculatedmulti question the question name does pass format_string to process multilang tags.
2017-05-22 11:32:52 +02:00
David Monllao fb0e1b10fe Merge branch 'MOODLE_32_STABLE-MDL-56973' of https://github.com/fwsl/moodle into MOODLE_32_STABLE 2017-05-22 15:14:19 +08:00
Jake Dallimore 78f7595fd9 Merge branch 'MDL-56617_32-course-cbm-grade-to-pass' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-22 14:33:32 +08:00
David Monllao 338097adce Merge branch 'MDL-58986_32' of git://github.com/markn86/moodle into MOODLE_32_STABLE 2017-05-22 12:22:37 +08:00
David Monllao f98e259ddb Merge branch 'MDL-57957_32' of https://github.com/bostelm/moodle into MOODLE_32_STABLE 2017-05-22 10:44:32 +08:00
Luca Bösch 0e106b8332 MDL-56617 mod_quiz: No grade to pass check if CBM used
When certainty-based marking is used, grades can 'exceed' the maximum grade
(because they are multiplied by factors). Therefore, in such cases, don't show
no warning.
2017-05-19 12:43:07 +02:00
Grzegorz Ziółek 25e3a8a14c MDL-56973 wiki: New page title readonly after changing course language 2017-05-19 11:10:41 +02:00
David Monllao 46280f7478 weekly release 3.2.3+ 2017-05-19 13:08:36 +08:00
David Monllao 80bf9ac40a Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-05-19 13:08:34 +08:00
Andres e2b4084bfd MDL-46322 mod_assign: Only list enrolled graders as potential markers 2017-05-18 22:22:45 -05:00
Mark Nelson 2a667a0820 MDL-58986 mod_quiz: add CSS classes to buttons on comment page 2017-05-18 16:50:06 +08:00
Andres Melo a4ad655bf1 MDL-46322 mod_assign: Only list enrolled graders as potential markers 2017-05-17 15:54:40 -05:00
AMOS bot 653e23bcc1 Automatically generated installer lang files 2017-05-18 00:07:20 +08:00
Mark Nelson 80d970cd0e MDL-58776 core_tag: removed whitespace from id attribute
This was preventing the JS from finding the element.
2017-05-17 12:13:40 +01:00
Simey Lameze f8962b4270 MDL-58884 core_competency: add exporter required course fields 2017-05-17 15:01:49 +08:00
Jake Dallimore e2f921ea2a Merge branch 'MDL-58947-m32' of https://github.com/sammarshallou/moodle into MOODLE_32_STABLE 2017-05-17 09:16:55 +08:00
Andrew Nicols 3586517ff8 Merge branch 'MDL-58795-moodle32' of https://github.com/jebarviabb/moodle into MOODLE_32_STABLE 2017-05-17 07:05:31 +08:00
Daniel Materka 4e8f93abba MDL-49988 wiki: fix broken page layout if html contains line breaks 2017-05-16 19:00:02 +01:00
Dan Poltawski 164d1e290e Merge branch 'MDL-58776-32' of git://github.com/ankitagarwal/moodle into MOODLE_32_STABLE 2017-05-16 17:49:07 +01:00
AMOS bot 373bd248b9 Automatically generated installer lang files 2017-05-17 00:09:11 +08:00
Henning Bostelmann c6bbd48e23 MDL-57957 mod_assign: show feedback file in absence of grade item 2017-05-16 12:00:46 +01:00
Iñaki Arenaza 4db85a5943 MDL-57558 ldap: fix ldap_get_entries_moodle()
While ldap_get_entries_moodle() PHPdocs state that it returns "array
ldap-entries with lower-cased attributes as indexes.", this is not true. It
uses ldap_get_attributes() internally, which returns both numerically indexed
attribute names, and dictionary-like entries indexed by attribute names.

Current code lowercases the dictionary-like entries, but then uses the
numerically indexed entries for the attribute names used as keys in the
returned array. The numerically indexed names might or might not be lowercased,
depending on the LDAP server and PHP version) version. E.g., OpenLDAP 2.x,
Novell eDirectory 8.x and MS Active Directory return mixed-cased attribute
names, and PHP 5.x and PHP 7.x don't lowercase them inside ldap_get_entries().

This is probably why all calls to ldap_get_entries_moodle() are followed by
calls to array_change_key_case(), even if that shouldn't be necessary.

So make sure we always return lower-cased attributs as indexes and add some
unit tests to avoid regressions in the future.
2017-05-16 10:47:22 +01:00
Jun Pataleta 726fce53e7 Merge branch 'MDL-58811-32-extra-slash' of https://github.com/dmitriim/moodle into MOODLE_32_STABLE 2017-05-16 17:43:14 +08:00
Josh Ebarvia 5607f04f15 MDL-58795 gradereport_grader: Prevent duplicates in grader report
Currently, the sorting being used for the grader report table
(asc/desc arrows) is just the grade_grades.finalgrade.
This adds grade_grades.userid in the sort to prevent duplicate
in records returned when using pages.
2017-05-16 16:56:44 +09:30
Jake Dallimore 5d37f70d68 Merge branch 'MDL-58723-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-05-16 15:17:57 +08:00
Jun Pataleta 163e56dfbb MDL-58723 calendar: Better testing of forever recurring events
* Change the start date of the parent event to the current date
  for tests that with events that recur forever.
* Limit query results to 100 for events that recur forever that can
  generate more than 100 event records.
2017-05-16 14:40:29 +08:00
Andrew Nicols 07f1e2b49c Merge branch 'MDL-58756_32-statslib-roles-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-16 13:53:23 +08:00
Luca Bösch 328159027c MDL-58756 stats: Use multilang with role. 2017-05-16 07:28:43 +02:00
Dmitrii Metelkin c6e47712f5 MDL-58811 backup: fix an extra slash on restore for the legacy files 2017-05-16 14:31:05 +10:00
David Monllao 4a1d28e6c6 Merge branch 'MDL-58884-32' of git://github.com/StudiUM/moodle into MOODLE_32_STABLE 2017-05-16 10:41:53 +08:00
Jake Dallimore cbbfaad531 Merge branch 'MDL-58770-32' of https://github.com/IMSGlobal/moodle into MOODLE_32_STABLE 2017-05-16 09:58:42 +08:00
sam marshall bb78b2fd22 MDL-58947 Search: Label URLs not correctly calculated 2017-05-15 17:56:41 +01:00
AMOS bot 021b544c7a Automatically generated installer lang files 2017-05-16 00:07:22 +08:00
Dan Poltawski 71e94edfd8 Merge branch 'MDL-58916-32' of https://github.com/xow/moodle into MOODLE_32_STABLE 2017-05-15 11:01:43 +01:00
Dan Poltawski 37b143aeaf Merge branch 'MDL-58841-32' of git://github.com/cameron1729/moodle into MOODLE_32_STABLE 2017-05-15 10:46:11 +01:00
Dan Poltawski d1e6ca40a0 Merge branch 'MDL-58852_32-choice-chart-options-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-15 10:23:05 +01:00
Andrew Nicols d926390fba Merge branch 'MDL-58893-32-missing-div' of https://github.com/dmitriim/moodle into MOODLE_32_STABLE 2017-05-15 15:15:34 +08:00
Andrew Nicols 1dcc39e9a1 Merge branch 'MDL-58920_32-calculated-question-edit-name-multilang' of https://github.com/lucaboesch/moodle into MOODLE_32_STABLE 2017-05-15 14:54:20 +08:00
Dmitrii Metelkin e48bab0b24 MDL-58893 portfolio: add missing closing div 2017-05-15 15:52:52 +10:00
David Monllao bc71da7f50 Merge branch 'MDL-58656-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-05-15 11:39:39 +08:00
AMOS bot 3739127caf Automatically generated installer lang files 2017-05-14 00:04:48 +08:00
Luca Bösch 4321953314 MDL-58920 questions: Calculated question name passing multilang.
In "Shared wild cards" table calculated question name do pass format_string to process multilang tags.
Thus, not breaking the layout any more.
2017-05-12 18:07:55 +02:00
AMOS bot d69fcc7bc1 Automatically generated installer lang files 2017-05-13 00:04:43 +08:00
Dan Poltawski 723ed522a5 weekly release 3.2.3+ 2017-05-12 10:02:00 +01:00
Dan Poltawski 0d011d9ad3 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-05-12 10:01:59 +01:00
John Okely 15e5a39266 MDL-58916 user_profile: Pass site context when determining menu options 2017-05-12 15:59:48 +08:00
AMOS bot 1a63aaddeb Automatically generated installer lang files 2017-05-12 00:04:33 +08:00
Issam Taboubi ec66fbbeec MDL-58884 competency: Inaccurate stats proficient competencies in course 2017-05-11 11:51:53 -04:00
Skylar Kelty 11580ef62a MDL-58658 caching: Add static acceleration unit test for empty arrays 2017-05-11 11:04:25 +01:00
Skylar Kelty 8afd92382e MDL-58658 caching: Fix static acceleration for empty arrays 2017-05-11 11:04:15 +01:00
AMOS bot cf4753e354 Automatically generated installer lang files 2017-05-11 00:04:44 +08:00
David Monllao ed8c3327fb Merge branch 'MDL-58833-32' of git://github.com/andrewnicols/moodle into MOODLE_32_STABLE 2017-05-10 14:07:59 +08:00
David Monllao 3bd5edccf8 Merge branch 'MDL-58843-32-exchandler' of git://github.com/mudrd8mz/moodle into MOODLE_32_STABLE 2017-05-10 14:06:06 +08:00
Dan Poltawski 01932fa6fa Merge branch 'MDL-58836-32' of git://github.com/damyon/moodle into MOODLE_32_STABLE 2017-05-10 06:57:12 +01:00
Andrew Nicols db8ff4bc78 Merge branch 'MDL-58780-32' of git://github.com/junpataleta/moodle into MOODLE_32_STABLE 2017-05-10 11:49:07 +08:00
Eloy Lafuente (stronk7) 2dced48edf Merge branch 'wip-MDL-58854-32' of git://github.com/marinaglancy/moodle into MOODLE_32_STABLE 2017-05-10 02:09:34 +02:00
AMOS bot 835bc90d7c Automatically generated installer lang files 2017-05-10 00:05:27 +08:00
Dan Poltawski 4d160525d3 weekly release 3.2.3+ 2017-05-09 12:41:47 +01:00
Dan Poltawski b3d4341009 Merge branch 'install_32_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_32_STABLE 2017-05-09 12:41:44 +01:00
Cameron Ball bfa2ed7f6c MDL-58841 mod_assign: Style "view all" link on grading summary 2017-05-09 15:05:58 +08:00
David Mudrák 00fe8e5e3f MDL-58843 core: Do not expect a particular class of the thrown exception
Since PHP 7, the custom exception handlers are also called to handle
thrown Errors which are not Exceptions.
2017-05-09 08:42:53 +02:00
Andrew Nicols 5aeb8b003c Merge branch 'MDL-58822-32' of git://github.com/ryanwyllie/moodle into MOODLE_32_STABLE 2017-05-09 14:16:57 +08:00
Ryan Wyllie d90b7b734c MDL-58822 backup: backup and restore user override events 2017-05-09 05:49:25 +00:00
Jun Pataleta 26aaa71667 MDL-58780 mod_assign: Remove AS keyword in table alias
* The AS keyword is not recognised by Oracle for table aliases.
This is okay with other databases, but optional, so better to
remove it.
2017-05-09 12:00:45 +08:00
Marina Glancy 2265e74a31 MDL-58854 theme_boost: override templates for columns 2017-05-09 10:36:38 +08:00
Damyon Wiese 04f82f5669 MDL-58836 auth: Improve backwards compatibility
Auth plugins with custom signup forms may not be using renderables / renderers - or
even if they are they may return a renderable that can only be rendered with the renderer from the auth
plugin.

This change checks if the signup form is a renderable - if so try the plugin renderer or fall back on the general renderer.
Otherwise call display() from the mform which is the previous way of rendering an mform.
2017-05-09 10:27:39 +08:00
Luca Bösch e4d2487dd2 MDL-58852 choice: Use multilang for choice options in charts 2017-05-08 23:29:40 +02:00
AMOS bot b603370a23 Automatically generated installer lang files 2017-05-09 00:06:57 +08:00
Andrew Nicols 6ed25aee09 MDL-58833 tool_templatelibrary: Skip if directory empty 2017-05-08 15:02:20 +08:00
Jun Pataleta 9fff50ae00 MDL-58810 calendar: Fix rrule_manager issues
* Set the correct repeat ID for the recurring event
* Unset UUID for 'child' events of recurring events
2017-05-08 09:48:46 +08:00
Jun Pataleta 787d1a8f53 MDL-58810 calendar: Add coverage for UUID in recurring events 2017-05-08 09:40:19 +08:00
Ankit Agarwal b84949f618 MDL-58776 tags: Add bootstrap classes to buttons 2017-05-02 12:26:20 +05:30
Stephen Vickers 22227b7701 MDL-58770 mod_lti: Strip HTML from parameters
Remove HTML tags from parameters which should be plain text.
2017-05-01 21:10:40 +01:00
Damyon Wiese 8a33f2a530 MDL-58656 competencies: Fix buggy scale caching
This affects the competency breakdown report in a course.
2017-04-20 13:24:56 +08:00
241 changed files with 4386 additions and 1812 deletions
+29 -1
View File
@@ -2,7 +2,7 @@
# process (which uses our internal CI system) this file is here for the benefit
# of community developers git clones - see MDL-51458.
sudo: false
sudo: required
# We currently disable Travis notifications entirely until https://github.com/travis-ci/travis-ci/issues/4976
# is fixed.
@@ -16,6 +16,12 @@ php:
- 7.1
- 5.6
addons:
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
services:
- redis-server
@@ -70,6 +76,28 @@ cache:
- $HOME/.npm
install:
- sudo apt-get -y install haveged
- sudo service haveged start
- >
if [ "$DB" = 'mysqli' ];
then
sudo mkdir /mnt/ramdisk
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
sudo stop mysql
sudo mv /var/lib/mysql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
sudo start mysql
fi
- >
if [ "$DB" = 'pgsql' ];
then
sudo mkdir /mnt/ramdisk
sudo mount -t tmpfs -o size=1024m tmpfs /mnt/ramdisk
sudo service postgresql stop
sudo mv /var/lib/postgresql /mnt/ramdisk
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
sudo service postgresql start 9.1
fi
- >
if [ "$TASK" = 'PHPUNIT' ];
then
+1 -1
View File
@@ -89,7 +89,7 @@ if ($PAGE->user_allowed_editing()) {
$savebutton = false;
$outputhtml = '';
foreach ($settingspage->children as $childpage) {
if ($childpage->is_hidden()) {
if ($childpage->is_hidden() || !$childpage->check_access()) {
continue;
}
if ($childpage instanceof admin_externalpage) {
+40 -4
View File
@@ -53,7 +53,7 @@ Options:
-h, --help Print out this help
Example:
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8_general_ci
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8mb4_unicode_ci
";
if (!empty($options['collation'])) {
@@ -145,9 +145,22 @@ if (!empty($options['collation'])) {
$skipped++;
} else {
$DB->change_database_structure("ALTER TABLE $table->name DEFAULT CHARACTER SET $charset DEFAULT COLLATE = $collation");
echo "CONVERTED\n";
$converted++;
try {
$DB->change_database_structure("ALTER TABLE $table->name CONVERT TO CHARACTER SET $charset COLLATE $collation");
echo "CONVERTED\n";
$converted++;
} catch (ddl_exception $e) {
$result = mysql_set_row_format($table->name, $charset, $collation, $engine);
if ($result) {
echo "CONVERTED\n";
$converted++;
} else {
// We don't know what the problem is. Stop the conversion.
cli_error("Error: Tried to convert $table->name, but there was a problem. Please check the details of this
table and try again.");
die();
}
}
}
$sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
@@ -290,3 +303,26 @@ function mysql_get_column_collations($tablename) {
$rs->close();
return $collations;
}
function mysql_set_row_format($tablename, $charset, $collation, $engine) {
global $DB;
$sql = "SELECT row_format
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema = DATABASE() AND table_name = ?";
$rs = $DB->get_record_sql($sql, array($tablename));
if ($rs) {
if ($rs->row_format == 'Compact' || $rs->row_format == 'Redundant') {
$rowformat = $DB->get_row_format_sql($engine, $collation);
// Try to convert to compressed format and then try updating the collation again.
$DB->change_database_structure("ALTER TABLE $tablename $rowformat");
$DB->change_database_structure("ALTER TABLE $tablename CONVERT TO CHARACTER SET $charset COLLATE $collation");
} else {
// Row format may not be the problem. Can not diagnose problem. Send fail reply.
return false;
}
} else {
return false;
}
return true;
}
+1 -1
View File
@@ -232,7 +232,7 @@ class site_registration_form extends moodleform {
}
$language = get_config('hub', 'site_language_' . $cleanhuburl);
if ($language === false) {
$language = current_language();
$language = explode('_', current_language())[0];
}
$geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
$contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
+2 -1
View File
@@ -179,7 +179,8 @@ preferences,moodle|/user/preferences.php|preferences',
'idnumber' => new lang_string('sort_idnumber', 'admin'),
);
$temp->add(new admin_setting_configselect('navsortmycoursessort', new lang_string('navsortmycoursessort', 'admin'), new lang_string('navsortmycoursessort_help', 'admin'), 'sortorder', $sortoptions));
$temp->add(new admin_setting_configtext('navcourselimit',new lang_string('navcourselimit','admin'),new lang_string('confignavcourselimit', 'admin'),20,PARAM_INT));
$temp->add(new admin_setting_configtext('navcourselimit', new lang_string('navcourselimit', 'admin'),
new lang_string('confignavcourselimit', 'admin'), 10, PARAM_INT));
$temp->add(new admin_setting_configcheckbox('usesitenameforsitepages', new lang_string('usesitenameforsitepages', 'admin'), new lang_string('configusesitenameforsitepages', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('linkadmincategories', new lang_string('linkadmincategories', 'admin'), new lang_string('linkadmincategories_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('linkcoursesections', new lang_string('linkcoursesections', 'admin'), new lang_string('linkcoursesections_help', 'admin'), 0));
@@ -31,7 +31,7 @@ $string['delete_confirmation'] = 'Are you absolutely sure you want to remove <st
$string['deletea'] = 'Delete {$a}';
$string['deletefiletypes'] = 'Delete a file type';
$string['description'] = 'Custom description';
$string['description_help'] = 'Simple file type description, e.g. &lsquo;Kindle ebook&rsquo;. If your site supports multiple languages and uses the multi-language filter, you can enter multi-language tags in this field to supply a description in different languages.';
$string['description_help'] = 'Simple file type description, e.g. \'Kindle ebook\'. If your site supports multiple languages and uses the multi-language filter, you can enter multi-language tags in this field to supply a description in different languages.';
$string['descriptiontype'] = 'Description type';
$string['descriptiontype_help'] = 'There are three possible ways to specify a description.
@@ -49,15 +49,15 @@ $string['error_defaulticon'] = 'Another file extension with the same MIME type i
$string['error_extension'] = 'The file type extension <strong>{$a}</strong> already exists or is invalid. File extensions must be unique and must not contain special characters.';
$string['error_notfound'] = 'The file type with extension {$a} cannot be found.';
$string['extension'] = 'Extension';
$string['extension_help'] = 'File name extension without the dot, e.g. &lsquo;mobi&rsquo;';
$string['extension_help'] = 'File name extension without the dot, e.g. \'mobi\'';
$string['groups'] = 'Type groups';
$string['groups_help'] = 'Optional list of file type groups that this type belongs to. These are generic categories such as &lsquo;document&rsquo; and &lsquo;image&rsquo;.';
$string['groups_help'] = 'Optional list of file type groups that this type belongs to. These are generic categories such as \'document\' and \'image\'.';
$string['icon'] = 'File icon';
$string['icon_help'] = 'Icon filename.
The list of icons is taken from the /pix/f directory inside your Moodle installation. You can add custom icons to this folder if required.';
$string['mimetype'] = 'MIME type';
$string['mimetype_help'] = 'MIME type associated with this file type, e.g. &lsquo;application/x-mobipocket-ebook&rsquo;';
$string['mimetype_help'] = 'MIME type associated with this file type, e.g. \'application/x-mobipocket-ebook\'';
$string['pluginname'] = 'File types';
$string['revert'] = 'Restore {$a} to Moodle defaults';
$string['revert_confirmation'] = 'Are you sure you want to restore <strong>.{$a}</strong> to Moodle defaults, discarding your changes?';
+6 -4
View File
@@ -40,7 +40,7 @@ if (empty($CFG->langotherroot)) {
$mode = optional_param('mode', 0, PARAM_INT); // action
$pack = optional_param_array('pack', array(), PARAM_SAFEDIR); // pack to install
$uninstalllang = optional_param_array('uninstalllang', array(), PARAM_LANG);// installed pack to uninstall
$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_ALPHAEXT); // uninstallation confirmation
$confirmtounistall = optional_param('confirmtouninstall', '', PARAM_SAFEPATH); // uninstallation confirmation
$purgecaches = optional_param('purgecaches', false, PARAM_BOOL); // explicit caches reset
if ($purgecaches) {
@@ -74,7 +74,7 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
// Actually deleting languages, languages to delete are passed as GET parameter as string
// ...need to populate them to array.
if (empty($uninstalllang)) {
$uninstalllang = explode('-', $confirmtounistall);
$uninstalllang = explode('/', $confirmtounistall);
}
if (in_array('en', $uninstalllang)) {
@@ -84,8 +84,10 @@ if ($mode == DELETION_OF_SELECTED_LANG and (!empty($uninstalllang) or !empty($co
} else if (empty($confirmtounistall) and confirm_sesskey()) { // User chose langs to be deleted, show confirmation.
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('uninstallconfirm', 'tool_langimport', implode(', ', $uninstalllang)),
'index.php?mode='.DELETION_OF_SELECTED_LANG.'&confirmtouninstall='.implode('-', $uninstalllang),
'index.php');
new moodle_url($PAGE->url, array(
'mode' => DELETION_OF_SELECTED_LANG,
'confirmtouninstall' => implode('/', $uninstalllang),
)), $PAGE->url);
echo $OUTPUT->footer();
die;
@@ -84,8 +84,7 @@ abstract class restore_tool_log_logstore_subplugin extends restore_subplugin {
}
}
// Roll dates.
$data->timecreated = $this->apply_date_offset($data->timecreated);
// There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
// Revert other to its original php way.
$data->other = unserialize(base64_decode($data->other));
@@ -88,6 +88,7 @@ class store implements \tool_log\log\writer, \core\log\sql_reader {
$dboptions['dbport'] = $this->get_config('dbport', '');
$dboptions['dbschema'] = $this->get_config('dbschema', '');
$dboptions['dbcollation'] = $this->get_config('dbcollation', '');
$dboptions['dbhandlesoptions'] = $this->get_config('dbhandlesoptions', false);
try {
$db->connect($this->get_config('dbhost'), $this->get_config('dbuser'), $this->get_config('dbpass'),
$this->get_config('dbname'), false, $dboptions);
@@ -31,6 +31,8 @@ $string['databasesettings_help'] = 'Connection details for the external log data
$string['databasepersist'] = 'Persistent database connections';
$string['databaseschema'] = 'Database schema';
$string['databasecollation'] = 'Database collation';
$string['databasehandlesoptions'] = 'Database handles options';
$string['databasehandlesoptions_help'] = 'Does the remote database handle its own options.';
$string['databasetable'] = 'Database table';
$string['databasetable_help'] = 'Name of the table where logs will be stored. This table should have a structure identical to the one used by logstore_standard (mdl_logstore_standard_log).';
$string['includeactions'] = 'Include actions of these types';
@@ -54,6 +54,8 @@ if ($hassiteconfig) {
'logstore_database'), '', ''));
$settings->add(new admin_setting_configtext('logstore_database/dbcollation', get_string('databasecollation',
'logstore_database'), '', ''));
$settings->add(new admin_setting_configcheckbox('logstore_database/dbhandlesoptions', get_string('databasehandlesoptions',
'logstore_database'), get_string('databasehandlesoptions_help', 'logstore_database'), '0'));
$settings->add(new admin_setting_configtext('logstore_database/buffersize', get_string('buffersize',
'logstore_database'), get_string('buffersize_help', 'logstore_database'), 50));
@@ -64,6 +64,7 @@ $dboptions['dbsocket'] = get_config('logstore_database', 'dbsocket');
$dboptions['dbport'] = get_config('logstore_database', 'dbport');
$dboptions['dbschema'] = get_config('logstore_database', 'dbschema');
$dboptions['dbcollation'] = get_config('logstore_database', 'dbcollation');
$dboptions['dbhandlesoptions'] = get_config('logstore_database', 'dbhandlesoptions');
try {
$db->connect(get_config('logstore_database', 'dbhost'), get_config('logstore_database', 'dbuser'),
@@ -83,6 +83,11 @@ class logstore_database_store_testcase extends advanced_testcase {
} else {
set_config('dbcollation', '', 'logstore_database');
}
if (!empty($CFG->dboptions['dbhandlesoptions'])) {
set_config('dbhandlesoptions', $CFG->dboptions['dbhandlesoptions'], 'logstore_database');
} else {
set_config('dbhandlesoptions', false, 'logstore_database');
}
// Enable logging plugin.
set_config('enabled_stores', 'logstore_database', 'tool_log');
+11
View File
@@ -0,0 +1,11 @@
This files describes API changes in the logstore_database code.
=== 3.2.4 ===
* PostgreSQL connections now use advanced options to reduce connection overhead. These options are not compatible
with some connection poolers. The dbhandlesoptions parameter has been added to allow the database to configure the
required defaults. The parameters that are required in the database are;
ALTER DATABASE moodle SET client_encoding = UTF8;
ALTER DATABASE moodle SET standard_conforming_strings = on;
ALTER DATABASE moodle SET search_path = 'moodle,public'; -- Optional, if you wish to use a custom schema.
You can set these options against the database or the moodle user who connects.
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2016120500; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2016120501; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2016112900; // Requires this Moodle version.
$plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
@@ -51,7 +51,7 @@
</div>
</div>
<div data-region="footer" class="pull-xs-right">
<input type="button" data-action="rate" value="{{#str}}rate, tool_lp{{/str}}" class="btn btn-primary">
<button data-action="rate" class="btn btn-primary">{{#str}}rate, tool_lp{{/str}}</button>
<button data-action="cancel" class="btn btn-secondary">{{#str}}cancel{{/str}}</button>
</div>
<div class="clearfix"></div>
@@ -60,7 +60,7 @@
<div data-region="rule-base" class="form">
<div data-region="rule-outcome" class="form-group">
<label>{{#str}}outcome, tool_lp{{/str}}</label>
<select name="outcome" class="custom-select" ng-label="{{#str}}outcome, tool_lp{{/str}}">
<select name="outcome" class="custom-select">
{{#outcomes}}
<option value="{{code}}" {{#selected}}selected{{/selected}}>{{name}}</option>
{{/outcomes}}
@@ -68,7 +68,7 @@
</div>
<div data-region="rule-type" class="form-group">
<label>{{#str}}when, tool_lp{{/str}}</label>
<select name="rule" class="custom-select" ng-label="{{#str}}when, tool_lp{{/str}}">
<select name="rule" class="custom-select">
<option value="-1">{{#str}}choosedots{{/str}}</option>
{{#rules}}
<option value="{{type}}" {{#selected}}selected{{/selected}}>{{name}}</option>
@@ -81,10 +81,11 @@
{{/config}}
</div>
<div data-region="footer" class="pull-xs-right">
<div data-region="footer" class="pull-xs-right m-t-1">
{{#config}}
<input type="button" class="btn btn-primary" data-action="save" value="{{#str}}savechanges{{/str}}"/>
{{/config}}
<input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
</div>
<div class="clearfix"></div>
</div>
@@ -70,6 +70,9 @@ class api {
// Look at all the templates dirs for subsystems.
$subsystems = core_component::get_core_subsystems();
foreach ($subsystems as $subsystem => $dir) {
if (empty($dir)) {
continue;
}
$dir .= '/templates';
if (is_dir($dir)) {
$dirs = mustache_template_finder::get_template_directories_for_component('core_' . $subsystem, $themename);
+12 -12
View File
@@ -3187,6 +3187,18 @@ class CAS_Client
false/*$no_response*/, true/*$bad_response*/, $text_response
);
$result = false;
} else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
// authentication failed, extract the error code and message and throw exception
$auth_fail_list = $tree_response
->getElementsByTagName("authenticationFailure");
throw new CAS_AuthenticationException(
$this, 'Ticket not validated', $validate_url,
false/*$no_response*/, false/*$bad_response*/,
$text_response,
$auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
);
$result = false;
} else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
// authentication succeded, extract the user name
$success_elements = $tree_response
@@ -3227,18 +3239,6 @@ class CAS_Client
$result = true;
}
}
} else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
// authentication succeded, extract the error code and message
$auth_fail_list = $tree_response
->getElementsByTagName("authenticationFailure");
throw new CAS_AuthenticationException(
$this, 'Ticket not validated', $validate_url,
false/*$no_response*/, false/*$bad_response*/,
$text_response,
$auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
);
$result = false;
} else {
throw new CAS_AuthenticationException(
$this, 'Ticket not validated', $validate_url,
+1
View File
@@ -2,3 +2,4 @@ Description of phpCAS 1.3.4 library import
* downloaded from http://downloads.jasig.org/cas-clients/php/current/
* MDL-59456 phpCAS library has been patched because of an authentication bypass security vulnerability.
+1 -1
View File
@@ -143,7 +143,7 @@ class login implements renderable, templatable {
$data->error = $this->error;
$data->forgotpasswordurl = $this->forgotpasswordurl->out(false);
$data->hasidentityproviders = !empty($this->identityproviders);
$data->hasinstructions = !empty($this->instructions);
$data->hasinstructions = !empty($this->instructions) || $this->cansignup;
$data->identityproviders = $identityproviders;
list($data->instructions, $data->instructionsformat) = external_format_text($this->instructions, FORMAT_MOODLE,
context_system::instance()->id);
+9 -9
View File
@@ -276,7 +276,7 @@ class auth_plugin_ldap extends auth_plugin_base {
}
$ldapval = NULL;
foreach ($values as $value) {
$entry = array_change_key_case($user_entry[0], CASE_LOWER);
$entry = $user_entry[0];
if (($value == 'dn') || ($value == 'distinguishedname')) {
$result[$key] = $user_dn;
continue;
@@ -634,7 +634,7 @@ class auth_plugin_ldap extends auth_plugin_base {
if ($sr) {
$info = ldap_get_entries_moodle($ldapconnection, $sr);
if (!empty ($info)) {
$info = array_change_key_case($info[0], CASE_LOWER);
$info = $info[0];
if (isset($info[$this->config->expireattr][0])) {
$expiretime = $this->ldap_expirationtime2unix($info[$this->config->expireattr][0], $ldapconnection, $user_dn);
if ($expiretime != 0) {
@@ -1201,7 +1201,7 @@ class auth_plugin_ldap extends auth_plugin_base {
return false;
}
$user_entry = array_change_key_case($user_entry[0], CASE_LOWER);
$user_entry = $user_entry[0];
foreach ($attrmap as $key => $ldapkeys) {
$profilefield = '';
@@ -1369,7 +1369,7 @@ class auth_plugin_ldap extends auth_plugin_base {
$sr = ldap_read($ldapconnection, $user_dn, '(objectClass=*)', $search_attribs);
if ($sr) {
$entry = ldap_get_entries_moodle($ldapconnection, $sr);
$info = array_change_key_case($entry[0], CASE_LOWER);
$info = $entry[0];
$newattrs = array();
if (!empty($info[$this->config->expireattr][0])) {
// Set expiration time only if passwordExpirationInterval is defined
@@ -2024,7 +2024,7 @@ class auth_plugin_ldap extends auth_plugin_base {
}
$entry = ldap_get_entries_moodle($ldapconn, $sr);
$info = array_change_key_case($entry[0], CASE_LOWER);
$info = $entry[0];
$useraccountcontrol = $info['useraccountcontrol'][0];
if ($useraccountcontrol & UF_DONT_EXPIRE_PASSWD) {
// Password doesn't expire.
@@ -2069,17 +2069,17 @@ class auth_plugin_ldap extends auth_plugin_base {
}
$entry = ldap_get_entries_moodle($ldapconn, $sr);
$info = array_change_key_case($entry[0], CASE_LOWER);
$info = $entry[0];
$domaindn = $info['defaultnamingcontext'][0];
$sr = ldap_read ($ldapconn, $domaindn, '(objectClass=*)',
array('maxPwdAge'));
$entry = ldap_get_entries_moodle($ldapconn, $sr);
$info = array_change_key_case($entry[0], CASE_LOWER);
$info = $entry[0];
$maxpwdage = $info['maxpwdage'][0];
if ($sr = ldap_read($ldapconn, $user_dn, '(objectClass=*)', array('msDS-ResultantPSO'))) {
if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
$info = array_change_key_case($entry[0], CASE_LOWER);
$info = $entry[0];
$userpso = $info['msds-resultantpso'][0];
// If a PSO exists, FGPP is being utilized.
@@ -2087,7 +2087,7 @@ class auth_plugin_ldap extends auth_plugin_base {
if (!empty($userpso)) {
$sr = ldap_read($ldapconn, $userpso, '(objectClass=*)', array('msDS-MaximumPasswordAge'));
if ($entry = ldap_get_entries_moodle($ldapconn, $sr)) {
$info = array_change_key_case($entry[0], CASE_LOWER);
$info = $entry[0];
// Default value of msds-maximumpasswordage is 42 and is always set.
$maxpwdage = $info['msds-maximumpasswordage'][0];
}
+11
View File
@@ -15,6 +15,17 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This script is used to configure and execute the backup proccess.
*
* @package core
* @subpackage backup
* @copyright Moodle
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('NO_OUTPUT_BUFFERING', true);
require_once('../config.php');
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
+26
View File
@@ -1,5 +1,31 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This script is used to configure and execute the import proccess.
*
* @package core
* @subpackage backup
* @copyright Moodle
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('NO_OUTPUT_BUFFERING', true);
// Require both the backup and restore libs
require_once('../config.php');
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+8
View File
@@ -869,6 +869,14 @@ class backup_calendarevents_structure_step extends backup_structure_step {
AND (eventtype = 'course' OR eventtype = 'group')";
$calendar_items_params = array('courseid'=>backup::VAR_COURSEID);
$event->set_source_sql($calendar_items_sql, $calendar_items_params);
} else if ($this->name == 'activity_calendar') {
$params = array('instance' => backup::VAR_ACTIVITYID, 'modulename' => backup::VAR_MODNAME);
// If we don't want to include the userinfo in the backup then setting the courseid
// will filter out all of the user override events (which have a course id of zero).
if (!$this->get_setting_value('userinfo')) {
$params['courseid'] = backup::VAR_COURSEID;
}
$event->set_source_table('event', $params);
} else {
$event->set_source_table('event', array('courseid' => backup::VAR_COURSEID, 'instance' => backup::VAR_ACTIVITYID, 'modulename' => backup::VAR_MODNAME));
}
+20 -4
View File
@@ -2632,6 +2632,17 @@ class restore_calendarevents_structure_step extends restore_structure_step {
$data = (object)$data;
$oldid = $data->id;
$restorefiles = true; // We'll restore the files
// User overrides for activities are identified by having a courseid of zero with
// both a modulename and instance value set.
$isuseroverride = !$data->courseid && $data->modulename && $data->instance;
// If we don't want to include user data and this record is a user override event
// for an activity then we should not create it. (Only activity events can be user override events - which must have this
// setting).
if ($isuseroverride && $this->task->setting_exists('userinfo') && !$this->task->get_setting_value('userinfo')) {
return;
}
// Find the userid and the groupid associated with the event.
$data->userid = $this->get_mappingid('user', $data->userid);
if ($data->userid === false) {
@@ -2667,7 +2678,9 @@ class restore_calendarevents_structure_step extends restore_structure_step {
'name' => $data->name,
'description' => $data->description,
'format' => $data->format,
'courseid' => $this->get_courseid(),
// User overrides in activities use a course id of zero. All other event types
// must use the mapped course id.
'courseid' => $data->courseid ? $this->get_courseid() : 0,
'groupid' => $data->groupid,
'userid' => $data->userid,
'repeatid' => $this->get_mappingid('event', $data->repeatid),
@@ -2689,10 +2702,11 @@ class restore_calendarevents_structure_step extends restore_structure_step {
WHERE " . $DB->sql_compare_text('name', 255) . " = " . $DB->sql_compare_text('?', 255) . "
AND courseid = ?
AND modulename = ?
AND instance = ?
AND timestart = ?
AND timeduration = ?
AND " . $DB->sql_compare_text('description', 255) . " = " . $DB->sql_compare_text('?', 255);
$arg = array ($params['name'], $params['courseid'], $params['modulename'], $params['timestart'], $params['timeduration'], $params['description']);
$arg = array ($params['name'], $params['courseid'], $params['modulename'], $params['instance'], $params['timestart'], $params['timeduration'], $params['description']);
$result = $DB->record_exists_sql($sql, $arg);
if (empty($result)) {
$newitemid = $DB->insert_record('event', $params);
@@ -3045,7 +3059,8 @@ class restore_course_logs_structure_step extends restore_structure_step {
$data = (object)($data);
$data->time = $this->apply_date_offset($data->time);
// There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
$data->userid = $this->get_mappingid('user', $data->userid);
$data->course = $this->get_courseid();
$data->cmid = 0;
@@ -3092,7 +3107,8 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure
$data = (object)($data);
$data->time = $this->apply_date_offset($data->time);
// There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
$data->userid = $this->get_mappingid('user', $data->userid);
$data->course = $this->get_courseid();
$data->cmid = $this->task->get_moduleid();
@@ -0,0 +1,99 @@
<?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/>.
/**
* Tests for backup_xml_transformer class.
*
* @package core_backup
* @subpackage moodle2
* @category backup
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
/**
* Tests for backup_xml_transformer.
*
* @package core_backup
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class backup_xml_transformer_testcase extends advanced_testcase {
/**
* Initial set up.
*/
public function setUp() {
parent::setUp();
$this->resetAfterTest(true);
}
/**
* Data provider for ::test_filephp_links_replace.
*
* @return array
*/
public function filephp_links_replace_data_provider() {
return array(
array('http://test.test/', 'http://test.test/'),
array('http://test.test/file.php/1', 'http://test.test/file.php/1'),
array('http://test.test/file.php/2/1.jpg', 'http://test.test/file.php/2/1.jpg'),
array('http://test.test/file.php/2', 'http://test.test/file.php/2'),
array('http://test.test/file.php/1/1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
array('http://test.test/file.php/1//1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
array('http://test.test/file.php?file=/1', '$@FILEPHP@$'),
array('http://test.test/file.php?file=/2/1.jpg', 'http://test.test/file.php?file=/2/1.jpg'),
array('http://test.test/file.php?file=/2', 'http://test.test/file.php?file=/2'),
array('http://test.test/file.php?file=/1/1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
array('http://test.test/file.php?file=/1//1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
array('http://test.test/file.php?file=%2f1', '$@FILEPHP@$'),
array('http://test.test/file.php?file=%2f2%2f1.jpg', 'http://test.test/file.php?file=%2f2%2f1.jpg'),
array('http://test.test/file.php?file=%2f2', 'http://test.test/file.php?file=%2f2'),
array('http://test.test/file.php?file=%2f1%2f1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
array('http://test.test/file.php?file=%2f1%2f%2f1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
array('http://test.test/file.php?file=%2F1', '$@FILEPHP@$'),
array('http://test.test/file.php?file=%2F2%2F1.jpg', 'http://test.test/file.php?file=%2F2%2F1.jpg'),
array('http://test.test/file.php?file=%2F2', 'http://test.test/file.php?file=%2F2'),
array('http://test.test/file.php?file=%2F1%2F1.jpg', '$@FILEPHP@$$@SLASH@$1.jpg'),
array('http://test.test/file.php?file=%2F1%2F%2F1.jpg', '$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'),
);
}
/**
* Test that backup_xml_transformer replaces file php links to $@FILEPHP@$.
*
* @dataProvider filephp_links_replace_data_provider
* @param string $content Testing content.
* @param string $expected Expected result.
*/
public function test_filephp_links_replace($content, $expected) {
global $CFG;
$CFG->wwwroot = 'http://test.test';
$transformer = new backup_xml_transformer(1);
$this->assertEquals($expected, $transformer->process($content));
}
}
+25 -1
View File
@@ -1,5 +1,29 @@
<?php
//This script is used to configure and execute the restore proccess.
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This script is used to configure and execute the restore proccess.
*
* @package core
* @subpackage backup
* @copyright Moodle
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('NO_OUTPUT_BUFFERING', true);
require_once('../config.php');
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
@@ -60,17 +60,26 @@ class restore_structure_parser_processor extends grouped_parser_processor {
} else if (strpos($cdata, '$@FILEPHP@$') === false) { // No $@FILEPHP@$, nothing to convert
return $cdata;
}
if ($CFG->slasharguments) {
$slash = '/';
$forcedownload = '?forcedownload=1';
} else {
$slash = '%2F';
$forcedownload = '&amp;forcedownload=1';
}
// We have to remove trailing slashes, otherwise file URLs will be restored with an extra slash.
$basefileurl = rtrim(moodle_url::make_legacyfile_url($this->courseid, null)->out(true), $slash);
// Decode file.php calls
$search = array ("$@FILEPHP@$");
$replace = array(moodle_url::make_legacyfile_url($this->courseid, null));
$replace = array($basefileurl);
$result = str_replace($search, $replace, $cdata);
// Now $@SLASH@$ and $@FORCEDOWNLOAD@$ MDL-18799
$search = array('$@SLASH@$', '$@FORCEDOWNLOAD@$');
if ($CFG->slasharguments) {
$replace = array('/', '?forcedownload=1');
} else {
$replace = array('%2F', '&amp;forcedownload=1');
}
$replace = array($slash, $forcedownload);
return str_replace($search, $replace, $result);
}
@@ -0,0 +1,132 @@
<?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/>.
/**
* Tests for restore_structure_parser_processor class.
*
* @package core_backup
* @category test
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/util/helper/restore_structure_parser_processor.class.php');
/**
* Tests for restore_structure_parser_processor class.
*
* @package core_backup
* @copyright 2017 Dmitrii Metelkin (dmitriim@catalyst-au.net)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class restore_structure_parser_processor_test extends advanced_testcase {
/**
* Initial set up.
*/
public function setUp() {
parent::setUp();
$this->resetAfterTest(true);
}
/**
* Data provider for ::test_process_cdata.
*
* @return array
*/
public function process_cdata_data_provider() {
return array(
array(null, null, true),
array("$@NULL@$", null, true),
array("$@NULL@$ ", "$@NULL@$ ", true),
array(1, 1, true),
array(" ", " ", true),
array("1", "1", true),
array("$@FILEPHP@$1.jpg", "$@FILEPHP@$1.jpg", true),
array(
"http://test.test/$@SLASH@$",
"http://test.test/$@SLASH@$",
true
),
array(
"<a href='$@FILEPHP@$1.jpg'>Image</a>",
"<a href='http://test.test/file.php/11.jpg'>Image</a>",
true
),
array(
"<a href='$@FILEPHP@$$@SLASH@$1.jpg'>Image</a>",
"<a href='http://test.test/file.php/1/1.jpg'>Image</a>",
true
),
array(
"<a href='$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'>Image</a>",
"<a href='http://test.test/file.php/1//1.jpg'>Image</a>",
true
),
array(
"<a href='$@FILEPHP@$1.jpg'>Image</a>",
"<a href='http://test.test/file.php?file=%2F11.jpg'>Image</a>",
false
),
array(
"<a href='$@FILEPHP@$$@SLASH@$1.jpg'>Image</a>",
"<a href='http://test.test/file.php?file=%2F1%2F1.jpg'>Image</a>",
false
),
array(
"<a href='$@FILEPHP@$$@SLASH@$$@SLASH@$1.jpg'>Image</a>",
"<a href='http://test.test/file.php?file=%2F1%2F%2F1.jpg'>Image</a>",
false
),
array(
"<a href='$@FILEPHP@$$@SLASH@$1.jpg$@FORCEDOWNLOAD@$'>Image</a>",
"<a href='http://test.test/file.php/1/1.jpg?forcedownload=1'>Image</a>",
true
),
array(
"<a href='$@FILEPHP@$$@SLASH@$1.jpg$@FORCEDOWNLOAD@$'>Image</a>",
"<a href='http://test.test/file.php?file=%2F1%2F1.jpg&amp;forcedownload=1'>Image</a>",
false
),
);
}
/**
* Test that restore_structure_parser_processor replaces $@FILEPHP@$ to correct file php links.
*
* @dataProvider process_cdata_data_provider
* @param string $content Testing content.
* @param string $expected Expected result.
* @param bool $slasharguments A value for $CFG->slasharguments setting.
*/
public function test_process_cdata($content, $expected, $slasharguments) {
global $CFG;
$CFG->slasharguments = $slasharguments;
$CFG->wwwroot = 'http://test.test';
$processor = new restore_structure_parser_processor(1, 1);
$this->assertEquals($expected, $processor->process_cdata($content));
}
}
+4 -4
View File
@@ -90,7 +90,7 @@ echo html_writer::start_tag('tbody');
if ($USER->id != $user->id) {
echo html_writer::start_tag('tr');
echo html_writer::start_tag('td', array('colspan' => '2'));
echo html_writer::tag('b', get_string('showinguser', 'completion'));
echo html_writer::tag('b', get_string('showinguser', 'completion') . ' ');
$url = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id));
echo html_writer::link($url, fullname($user));
echo html_writer::end_tag('td');
@@ -99,7 +99,7 @@ if ($USER->id != $user->id) {
echo html_writer::start_tag('tr');
echo html_writer::start_tag('td', array('colspan' => '2'));
echo html_writer::tag('b', get_string('status'));
echo html_writer::tag('b', get_string('status') . ' ');
// Is course complete?
$coursecomplete = $info->is_course_complete($user->id);
@@ -141,7 +141,7 @@ if (empty($completions)) {
} else {
echo html_writer::start_tag('tr');
echo html_writer::start_tag('td', array('colspan' => '2'));
echo html_writer::tag('b', get_string('required'));
echo html_writer::tag('b', get_string('required') . ' ');
// Get overall aggregation method.
$overall = $info->get_aggregation_method();
@@ -214,7 +214,7 @@ if (empty($completions)) {
echo core_text::strtolower(get_string('any', 'completion'));
}
echo html_writer::end_tag('i') .core_text::strtolower(get_string('required')).')';
echo ' ' . html_writer::end_tag('i') .core_text::strtolower(get_string('required')).')';
$agg_type = false;
}
}
+3 -1
View File
@@ -119,7 +119,9 @@ class block_login extends block_base {
$this->content->text .= '<h6>' . get_string('potentialidps', 'auth') . '</h6>';
$this->content->text .= '<div class="potentialidplist">';
foreach ($potentialidps as $idp) {
$this->content->text .= '<div class="potentialidp"><a href="' . $idp['url']->out() . '" title="' . s($idp['name']) . '">';
$this->content->text .= '<div class="potentialidp">';
$this->content->text .= '<a class="btn btn-default btn-block" ';
$this->content->text .= 'href="' . $idp['url']->out() . '" title="' . s($idp['name']) . '">';
$this->content->text .= $OUTPUT->render($idp['icon'], $idp['name']) . s($idp['name']) . '</a></div>';
}
$this->content->text .= '</div>';
+2 -2
View File
@@ -1018,7 +1018,7 @@ class cache implements cache_loader {
$result = $data;
}
}
if ($result) {
if ($result !== false) {
if ($this->perfdebug) {
cache_helper::record_cache_hit('** static acceleration **', $this->definition);
}
@@ -2197,4 +2197,4 @@ class cache_session extends cache {
*/
class cache_request extends cache {
// This comment appeases code pre-checker ;) !
}
}
+33
View File
@@ -2173,6 +2173,39 @@ class core_cache_testcase extends advanced_testcase {
$startstats[$requestid]['stores']['cachestore_static']['sets']);
}
public function test_static_cache() {
global $CFG;
$this->resetAfterTest(true);
$CFG->perfdebug = 15;
// Create cache store with static acceleration.
$instance = cache_config_testing::instance();
$applicationid = 'phpunit/applicationperf';
$instance->phpunit_add_definition($applicationid, array(
'mode' => cache_store::MODE_APPLICATION,
'component' => 'phpunit',
'area' => 'applicationperf',
'simplekeys' => true,
'staticacceleration' => true,
'staticaccelerationsize' => 3
));
$application = cache::make('phpunit', 'applicationperf');
// Check that stores register sets.
$this->assertTrue($application->set('setMe1', 1));
$this->assertTrue($application->set('setMe2', 0));
$this->assertTrue($application->set('setMe3', array()));
$this->assertTrue($application->get('setMe1') !== false);
$this->assertTrue($application->get('setMe2') !== false);
$this->assertTrue($application->get('setMe3') !== false);
// Check that the static acceleration worked, even on empty arrays and the number 0.
$endstats = cache_helper::get_stats();
$this->assertEquals(0, $endstats[$applicationid]['stores']['** static acceleration **']['misses']);
$this->assertEquals(3, $endstats[$applicationid]['stores']['** static acceleration **']['hits']);
}
public function test_performance_debug_off() {
global $CFG;
$this->resetAfterTest(true);
+10 -5
View File
@@ -244,13 +244,16 @@ class rrule_manager {
// Generate timestamps that obey the rrule.
$eventtimes = $this->generate_recurring_event_times($eventrec);
// Adjust the parent event's timestart, if necessary.
// Update the parent event. Make sure that its repeat ID is the same as its ID.
$calevent = new calendar_event($eventrec);
$updatedata = new stdClass();
$updatedata->repeatid = $event->id;
// Also, adjust the parent event's timestart, if necessary.
if (count($eventtimes) > 0 && !in_array($eventrec->timestart, $eventtimes)) {
$calevent = new calendar_event($eventrec);
$updatedata = (object)['timestart' => $eventtimes[0], 'repeatid' => $eventrec->id];
$calevent->update($updatedata, false);
$eventrec->timestart = $calevent->timestart;
$updatedata->timestart = reset($eventtimes);
}
$calevent->update($updatedata, false);
$eventrec->timestart = $calevent->timestart;
// Create the recurring calendar events.
$this->create_recurring_events($eventrec, $eventtimes);
@@ -720,6 +723,8 @@ class rrule_manager {
$cloneevent->repeatid = $event->id;
$cloneevent->timestart = $time;
unset($cloneevent->id);
// UUID should only be set on the first instance of the recurring events.
unset($cloneevent->uuid);
calendar_event::create($cloneevent, false);
}
+2 -1
View File
@@ -72,7 +72,8 @@ class event_form extends moodleform {
if (!empty($eventtypes->groups) && is_array($eventtypes->groups)) {
$groupoptions = array();
foreach ($eventtypes->groups as $group) {
$groupoptions[$group->id] = $group->name;
$groupoptions[$group->id] = format_string($group->name, true,
array('context' => context_course::instance($group->courseid)));
}
$mform->addElement('select', 'groupid', get_string('typegroup', 'calendar'), $groupoptions);
$mform->disabledIf('groupid', 'eventtype', 'noteq', 'group');
+3 -2
View File
@@ -77,7 +77,8 @@ if (!empty($day) && !empty($mon) && !empty($year)) {
}
if ($courseid != SITEID && !empty($courseid)) {
$course = $DB->get_record('course', array('id' => $courseid));
// Course ID must be valid and existing.
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$courses = array($course->id => $course);
$issite = false;
} else {
@@ -85,7 +86,7 @@ if ($courseid != SITEID && !empty($courseid)) {
$courses = calendar_get_default_courses();
$issite = true;
}
require_course_login($course);
require_login($course, false);
$url = new moodle_url('/calendar/export.php', array('time' => $time));
+13 -3
View File
@@ -193,10 +193,20 @@ foreach($events as $event) {
$hostaddress = str_replace('http://', '', $CFG->wwwroot);
$hostaddress = str_replace('https://', '', $hostaddress);
$ev = new iCalendar_event;
$me = new calendar_event($event); // To use moodle calendar event services.
$ev = new iCalendar_event; // To export in ical format.
$ev->add_property('uid', $event->id.'@'.$hostaddress);
$ev->add_property('summary', $event->name);
$ev->add_property('description', clean_param($event->description, PARAM_NOTAGS));
// Set iCal event summary from event name.
$ev->add_property('summary', format_string($event->name, true, ['context' => $me->context]));
// Format the description text.
$description = format_text($me->description, $me->format, ['context' => $me->context]);
// Then convert it to plain text, since it's the only format allowed for the event description property.
// We use html_to_text in order to convert <br> and <p> tags to new line characters for descriptions in HTML format.
$description = html_to_text($description, 0);
$ev->add_property('description', $description);
$ev->add_property('class', 'PUBLIC'); // PUBLIC / PRIVATE / CONFIDENTIAL
$ev->add_property('last-modified', Bennu::timestamp_to_datetime($event->timemodified));
$ev->add_property('dtstamp', Bennu::timestamp_to_datetime()); // now
+4 -2
View File
@@ -45,13 +45,15 @@ $PAGE->set_pagelayout('admin');
$PAGE->navbar->add(get_string('managesubscriptions', 'calendar'));
if ($courseid != SITEID && !empty($courseid)) {
$course = $DB->get_record('course', array('id' => $courseid));
// Course ID must be valid and existing.
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$courses = array($course->id => $course);
} else {
$course = get_site();
$courses = calendar_get_default_courses();
}
require_course_login($course);
require_login($course, false);
if (!calendar_user_can_add_event($course)) {
print_error('errorcannotimport', 'calendar');
}
+51
View File
@@ -171,4 +171,55 @@ class core_calendar_lib_testcase extends advanced_testcase {
$event = reset($events);
$this->assertEquals('assign', $event->modulename);
}
/**
* Helper function to create calendar events using the old code.
*
* @param array $properties A list of calendar event properties to set
* @return calendar_event|bool
*/
protected function create_event($properties = []) {
$record = new \stdClass();
$record->name = 'event name';
$record->eventtype = 'global';
$record->timestart = time();
$record->timeduration = 0;
$record->timesort = 0;
$record->type = 1;
$record->courseid = 0;
foreach ($properties as $name => $value) {
$record->$name = $value;
}
$event = new calendar_event($record);
return $event->create($record, false);
}
/**
* Test that when course module is deleted all events are also deleted.
*/
public function test_delete_module_delete_events() {
global $DB;
$this->resetAfterTest(true);
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
// Create the course we will be using.
$course = $this->getDataGenerator()->create_course();
$group = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
foreach (core_component::get_plugin_list('mod') as $modname => $unused) {
$module = $this->getDataGenerator()->create_module($modname, ['course' => $course->id]);
// Create bunch of events of different type (user override, group override, module event).
$this->create_event(['userid' => $user->id, 'modulename' => $modname, 'instance' => $module->id]);
$this->create_event(['groupid' => $group->id, 'modulename' => $modname, 'instance' => $module->id]);
$this->create_event(['modulename' => $modname, 'instance' => $module->id]);
$this->create_event(['modulename' => $modname, 'instance' => $module->id, 'courseid' => $course->id]);
// Delete module and make sure all events are deleted.
course_delete_module($module->cmid);
$this->assertEmpty($DB->get_record('event', ['modulename' => $modname, 'instance' => $module->id]));
}
}
}
+249 -115
View File
@@ -451,6 +451,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
*/
public function test_every_300_days_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date.
$this->change_event_startdate(date('Ymd\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$interval = new DateInterval('P300D');
@@ -463,14 +466,25 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', array('repeatid' => $this->event->id), 'timestart ASC');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', array('repeatid' => $this->event->id), 'timestart ASC', 0, 100);
$expecteddate = clone($startdatetime);
$first = true;
foreach ($records as $record) {
$this->assertLessThanOrEqual($until, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
// Go to next iteration.
$expecteddate->add($interval);
// Check UUID.
if ($first) {
// The first instance of the event contains the UUID.
$this->assertEquals('uuid', $record->uuid);
$first = false;
} else {
// Succeeding instances will not contain the UUID.
$this->assertEmpty($record->uuid);
}
}
}
@@ -542,8 +556,20 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$expecteddate->add($interval);
}
}
}
// Forever event. This should generate events over time() + 10 year period, every 50th Monday.
/**
* Test recurrence rules for weekly frequency for RRULE with BYDAY rule set, recurring forever.
*/
public function test_weekly_byday_forever() {
global $DB;
// Set the next Monday as the starting date of this event.
$startdate = new DateTime('next Monday');
// Change the start date of the parent event.
$startdate = $this->change_event_startdate($startdate->format('Ymd\T090000'));
// Forever event. This should generate events over time() + 10 year period, every 50 weeks.
$rrule = 'FREQ=WEEKLY;BYDAY=MO;INTERVAL=50';
$mang = new rrule_manager($rrule);
@@ -554,13 +580,14 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$untildate->add(new DateInterval('P10Y'));
$until = $untildate->getTimestamp();
$interval = new DateInterval('P50W');
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// First instance of this set of recurring events: Monday, 17-08-1998.
$interval = new DateInterval('P50W');
// First instance of this set of recurring events.
$expecteddate = clone($startdate);
$expecteddate->modify('1998-08-17');
$expecteddate->add($offsetinterval);
// Iterate over each record and increment the expected date accordingly.
foreach ($records as $record) {
$eventdateexpected = $expecteddate->format('Y-m-d H:i:s');
$eventdateactual = date('Y-m-d H:i:s', $record->timestart);
@@ -666,17 +693,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
public function test_monthly_events_with_bymonthday_forever() {
global $DB;
// Change the start date for forever events to 9am of the 2nd day of the current month and year.
$this->change_event_startdate(date('Ym02\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$startdate = new DateTime(date('Y-m-d', $this->event->timestart));
$offsetinterval = $startdatetime->diff($startdate, true);
$interval = new DateInterval('P12M');
// Forever event. This should generate events over 10 year period, on 2nd day of every 12th month.
// Forever event. This should generate events over a 10-year period, on 2nd day of the month, every 12 months.
$rrule = "FREQ=MONTHLY;INTERVAL=12;BYMONTHDAY=2";
$mang = new rrule_manager($rrule);
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$until = $untildate->getTimestamp();
$mang->parse_rrule();
$mang->create_events($this->event);
@@ -818,24 +849,33 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
public function test_monthly_events_with_byday_forever() {
global $DB;
// Change the start date for forever events to 9am of the 2nd day of the current month and year.
$this->change_event_startdate(date('Ym02\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$startdate = new DateTime(date('Y-m-d', $this->event->timestart));
$offsetinterval = $startdatetime->diff($startdate, true);
$interval = new DateInterval('P12M');
// Forever event. This should generate events over 10 year period, on 2nd day of every 12th month.
// Forever event. This should generate events over a 10 year period, on 1st Monday of the month every 12 months.
$rrule = "FREQ=MONTHLY;INTERVAL=12;BYDAY=1MO";
$mang = new rrule_manager($rrule);
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$until = $untildate->getTimestamp();
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
$expecteddate = new DateTime('first Monday of September 1998');
$expecteddate = new DateTime('first Monday of this month');
// Move to the next interval's first Monday if the calculated start date is after this month's first Monday.
if ($expecteddate->getTimestamp() < $startdatetime->getTimestamp()) {
$expecteddate->add($interval);
$expecteddate->modify('first Monday of this month');
}
foreach ($records as $record) {
$expecteddate->add($offsetinterval);
$this->assertLessThanOrEqual($until, $record->timestart);
@@ -880,7 +920,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
// Create a yearly event, until the time limit is hit.
$until = strtotime('+20 day +10 years', $this->event->timestart);
$until = date('Ymd\THis\Z', $until);
$rrule = "FREQ=YEARLY;BYMONTH=9;UNTIL=$until"; // Forever event.
$rrule = "FREQ=YEARLY;BYMONTH=9;UNTIL=$until";
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
@@ -907,18 +947,6 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$this->assertTrue($result);
}
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2"; // Forever event.
$mang = new rrule_manager($rrule);
$until = time() + (YEARSECS * $mang::TIME_UNLIMITED_YEARS);
$mang->parse_rrule();
$mang->create_events($this->event);
for ($i = 0, $time = $this->event->timestart; $time < $until; $i++, $yoffset = $i * 2,
$time = strtotime("+$yoffset years", $this->event->timestart)) {
$result = $DB->record_exists('event', array('repeatid' => $this->event->id,
'timestart' => ($time)));
$this->assertTrue($result);
}
$rrule = "FREQ=YEARLY;COUNT=3;BYMONTH=9;BYDAY=1MO"; // This should generate 3 events in total.
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
@@ -994,12 +1022,45 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
}
}
/**
* Test for rrule with FREQ=YEARLY and INTERVAL=2 with BYMONTH rule set, recurring forever.
*/
public function test_yearly_september_every_two_years_forever() {
global $DB;
// Change the start date for forever events to 9am on the 2nd day of September of the current year.
$this->change_event_startdate(date('Y0902\T090000'));
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2"; // Forever event.
$mang = new rrule_manager($rrule);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$untiltimestamp = $untildate->getTimestamp();
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
$interval = new DateInterval('P2Y');
$expecteddate = new DateTime(date('Y0902\T090000'));
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
// Go to the next expected date.
$expecteddate->add($interval);
}
}
/**
* Test for rrule with FREQ=YEARLY with BYMONTH and BYDAY rules set, recurring forever.
*/
public function test_yearly_bymonth_byday_forever() {
global $DB;
// Change the start date for forever events to the first day of September of the current year at 9am.
$this->change_event_startdate(date('Y0901\T090000'));
// Every 2 years on the first Monday of September.
$rrule = "FREQ=YEARLY;BYMONTH=9;INTERVAL=2;BYDAY=1MO";
$mang = new rrule_manager($rrule);
@@ -1018,9 +1079,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$offsetinterval = $startdatetime->diff($startdate, true);
$interval = new DateInterval('P2Y');
// First occurrence of this set of events is on the first Monday of September 1999.
// First occurrence of this set of events is on the first Monday of September.
$expecteddate = clone($startdatetime);
$expecteddate->modify('first Monday of September 1999');
$expecteddate->modify('first Monday of September');
$expecteddate->add($offsetinterval);
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
@@ -1040,6 +1101,9 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
public function test_yearly_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date.
$this->change_event_startdate(date('Ymd\T090000'));
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$interval = new DateInterval('P2Y');
@@ -1137,14 +1201,19 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every other day - forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Current date]T090000
* RRULE:FREQ=DAILY;INTERVAL=2
* ==> (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;October 2,4,6...20,22,24
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;Dec 1,3,...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;October 2,4,6...20,22,24
* (1997 9:00 AM EST)October 26,28,30;November 1,3,5,7...25,27,29;Dec 1,3,...
*/
public function test_every_other_day_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date in US/Eastern time.
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
$startdatetime = new DateTime(date('Y-m-d H:i:s', $this->event->timestart));
$interval = new DateInterval('P2D');
@@ -1153,7 +1222,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -1331,16 +1401,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every other week - forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Current date]T090000
* RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
* ==> (1997 9:00 AM EDT)September 2,16,30;October 14
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
* (1998 9:00 AM EST)January 6,20;February
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September 2,16,30;October 14
* (1997 9:00 AM EST)October 28;November 11,25;December 9,23
* (1998 9:00 AM EST)January 6,20;February
* ...
*/
public function test_every_other_week_forever() {
global $DB;
// Change the start date for forever events to 9am of the current date in US/Eastern time.
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
$interval = new DateInterval('P2W');
$rrule = 'FREQ=WEEKLY;INTERVAL=2;WKST=SU';
@@ -1348,7 +1423,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -1694,25 +1770,28 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Monthly on the third to the last day of the month, forever:
*
* DTSTART;TZID=US-Eastern:19970928T090000
* DTSTART;TZID=US-Eastern:[Current year]0928T090000
* RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
* ==> (1997 9:00 AM EDT)September 28
* (1997 9:00 AM EST)October 29;November 28;December 29
* (1998 9:00 AM EST)January 29;February 26
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September 28
* (1997 9:00 AM EST)October 29;November 28;December 29
* (1998 9:00 AM EST)January 29;February 26
* ...
*/
public function test_third_to_the_last_day_of_the_month_forever() {
global $DB;
// Change our event's date to 05-09-1997, based on the example from the RFC.
$this->change_event_startdate('19970928T090000', 'US/Eastern');
// Change our event's date to 28 September of the current year, based on the example from the RFC.
$this->change_event_startdate(date('Y0928\T090000'), 'US/Eastern');
$rrule = 'FREQ=MONTHLY;BYMONTHDAY=-3';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -1868,22 +1947,29 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Tuesday, every other month:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Next Tuesday]T090000
* RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
* ==> (1997 9:00 AM EDT)September 2,9,16,23,30
* (1997 9:00 AM EST)November 4,11,18,25
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)September 2,9,16,23,30
* (1997 9:00 AM EST)November 4,11,18,25
* (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
* ...
*/
public function test_every_tuesday_every_other_month_forever() {
global $DB;
// Change the start date for forever events to 9am of the Tuesday on or before of the current date in US/Eastern time.
$nexttuesday = new DateTime('next Tuesday');
$this->change_event_startdate($nexttuesday->format('Ymd\T090000'), 'US/Eastern');
$rrule = 'FREQ=MONTHLY;INTERVAL=2;BYDAY=TU';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2053,18 +2139,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every 20th Monday of the year, forever:
*
* DTSTART;TZID=US-Eastern:19970519T090000
* DTSTART;TZID=US-Eastern:[20th Monday of the current year]T090000
* RRULE:FREQ=YEARLY;BYDAY=20MO
* ==> (1997 9:00 AM EDT)May 19
* (1998 9:00 AM EDT)May 18
* (1999 9:00 AM EDT)May 17
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)May 19
* (1998 9:00 AM EDT)May 18
* (1999 9:00 AM EDT)May 17
* ...
*/
public function test_yearly_every_20th_monday_forever() {
global $DB;
// Change our event's date to 19-05-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970519T090000', 'US/Eastern');
// Change our event's date to the 20th Monday of the current year.
$twentiethmonday = new DateTime(date('Y-01-01'));
$twentiethmonday->modify('+20 Monday');
$startdatetime = $this->change_event_startdate($twentiethmonday->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
@@ -2100,18 +2190,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Monday of week number 20 (where the default start of the week is Monday), forever:
*
* DTSTART;TZID=US-Eastern:19970512T090000
* DTSTART;TZID=US-Eastern:[1st day of the 20th week this year]T090000
* RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO
* ==> (1997 9:00 AM EDT)May 12
* (1998 9:00 AM EDT)May 11
* (1999 9:00 AM EDT)May 17
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)May 12
* (1998 9:00 AM EDT)May 11
* (1999 9:00 AM EDT)May 17
* ...
*/
public function test_yearly_byweekno_forever() {
global $DB;
// Change our event's date to 12-05-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970512T090000', 'US/Eastern');
// Change our event's date to the start of the 20th week of the current year.
$twentiethweek = new DateTime(date('Y-01-01'));
$twentiethweek->setISODate($twentiethweek->format('Y'), 20);
$startdatetime = $this->change_event_startdate($twentiethweek->format('Ymd\T090000'), 'US/Eastern');
$startdate = clone($startdatetime);
$startdate->modify($startdate->format('Y-m-d'));
@@ -2146,18 +2240,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Thursday in March, forever:
*
* DTSTART;TZID=US-Eastern:19970313T090000
* DTSTART;TZID=US-Eastern:[First thursday of March of the current year]T090000
* RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
* ==> (1997 9:00 AM EST)March 13,20,27
* (1998 9:00 AM EST)March 5,12,19,26
* (1999 9:00 AM EST)March 4,11,18,25
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EST)March 13,20,27
* (1998 9:00 AM EST)March 5,12,19,26
* (1999 9:00 AM EST)March 4,11,18,25
* ...
*/
public function test_every_thursday_in_march_forever() {
global $DB;
// Change our event's date to 12-05-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970313T090000', 'US/Eastern');
// Change our event's date to the first Thursday of March of the current year at 9am US/Eastern time.
$firstthursdayofmarch = new DateTime('first Thursday of March');
$startdatetime = $this->change_event_startdate($firstthursdayofmarch->format('Ymd\T090000'), 'US/Eastern');
$interval = new DateInterval('P1Y');
@@ -2166,7 +2263,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2176,7 +2274,7 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offsetinterval = $startdatetime->diff($startdate, true);
$expecteddate->setTimezone(new DateTimeZone(get_user_timezone()));
$april1st = new DateTime('1997-04-01');
$april1st = new DateTime('April 1');
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
@@ -2201,18 +2299,21 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Thursday, but only during June, July, and August, forever:
*
* DTSTART;TZID=US-Eastern:19970605T090000
* DTSTART;TZID=US-Eastern:[First Thursday of June of the current year]T090000
* RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
* ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
* ...
*
* Sample results (e.g. in the year 1997):
* (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
* (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
* (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
* ...
*/
public function test_every_thursday_june_july_august_forever() {
global $DB;
// Change our event's date to 05-06-1997, based on the example from the RFC.
$startdatetime = $this->change_event_startdate('19970605T090000', 'US/Eastern');
// Change our event's date to the first Thursday of June in the current year at 9am US/Eastern time.
$firstthursdayofjune = new DateTime('first Thursday of June');
$startdatetime = $this->change_event_startdate($firstthursdayofjune->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
@@ -2225,14 +2326,15 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
$untiltimestamp = $untildate->getTimestamp();
$expecteddate = new DateTime(date('Y-m-d H:i:s', $startdatetime->getTimestamp()));
$september1st = new DateTime('1997-09-01');
$september1st = new DateTime('September 1');
foreach ($records as $record) {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
$this->assertEquals($expecteddate->format('Y-m-d H:i:s'), date('Y-m-d H:i:s', $record->timestart));
@@ -2254,22 +2356,28 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every Friday the 13th, forever:
*
* DTSTART;TZID=US-Eastern:19970902T090000
* EXDATE;TZID=US-Eastern:19970902T090000
* DTSTART;TZID=US-Eastern:[Current date]T090000
* RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
* ==> (1998 9:00 AM EST)February 13;March 13;November 13
* (1999 9:00 AM EDT)August 13
* (2000 9:00 AM EDT)October 13
*
* Sample results (e.g. in the year 1997):
* (1998 9:00 AM EST)February 13;March 13;November 13
* (1999 9:00 AM EDT)August 13
* (2000 9:00 AM EDT)October 13
* ...
*/
public function test_friday_the_thirteenth_forever() {
global $DB;
// Change our event's date to the first Thursday of June in the current year at 9am US/Eastern time.
$this->change_event_startdate(date('Ymd\T090000'), 'US/Eastern');
$rrule = 'FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2285,17 +2393,22 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* The first Saturday that follows the first Sunday of the month, forever:
*
* DTSTART;TZID=US-Eastern:19970913T090000
* DTSTART;TZID=US-Eastern:[The Saturday after the month's first Sunday]T090000
* RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
* ==> (1997 9:00 AM EDT)September 13;October 11
* (1997 9:00 AM EST)November 8;December 13
* (1998 9:00 AM EST)January 10;February 7;March 7
* (1998 9:00 AM EDT)April 11;May 9;June 13...
*
* Sample results (e.g. from 13 September 1997):
* (1997 9:00 AM EDT)September 13;October 11
* (1997 9:00 AM EST)November 8;December 13
* (1998 9:00 AM EST)January 10;February 7;March 7
* (1998 9:00 AM EDT)April 11;May 9;June 13...
*/
public function test_first_saturday_following_first_sunday_forever() {
global $DB;
$startdatetime = $this->change_event_startdate('19970913T090000', 'US/Eastern');
// Change our event's date to the next Saturday after the first Sunday of the the current month at 9am US/Eastern time.
$firstsaturdayafterfirstsunday = new DateTime('first Sunday of this month');
$firstsaturdayafterfirstsunday->modify('next Saturday');
$startdatetime = $this->change_event_startdate($firstsaturdayafterfirstsunday->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offset = $startdatetime->diff($startdate, true);
@@ -2304,7 +2417,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 100 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 100);
$untildate = new DateTime();
$untildate->add(new DateInterval('P' . $mang::TIME_UNLIMITED_YEARS . 'Y'));
@@ -2330,17 +2444,29 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Every four years, the first Tuesday after a Monday in November, forever (U.S. Presidential Election day):
*
* DTSTART;TZID=US-Eastern:19961105T090000
* DTSTART;TZID=US-Eastern:[Most recent election date]T090000
* RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8
* ==> (1996 9:00 AM EST)November 5
* (2000 9:00 AM EST)November 7
* (2004 9:00 AM EST)November 2
* ...
*
* Sample results (e.g. from 05 November 1996):
* (1996 9:00 AM EST)November 5
* (2000 9:00 AM EST)November 7
* (2004 9:00 AM EST)November 2
* ...
*/
public function test_every_us_presidential_election_forever() {
global $DB;
$startdatetime = $this->change_event_startdate('19961105T090000', 'US/Eastern');
// Calculate the most recent election date, starting from 1996 (e.g. today's 2017 so the most recent election was in 2016).
$currentyear = (int) date('Y');
$electionyear = 1996;
while ($electionyear + 4 < $currentyear) {
$electionyear += 4;
}
$electiondate = new DateTime('first Monday of November ' . $electionyear);
$electiondate->modify('+1 Tuesday');
// Use the most recent election date as the starting date of our recurring events.
$startdatetime = $this->change_event_startdate($electiondate->format('Ymd\T090000'), 'US/Eastern');
$startdate = new DateTime($startdatetime->format('Y-m-d'));
$offset = $startdatetime->diff($startdate, true);
@@ -2407,23 +2533,27 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
* The 2nd to last weekday of the month:
*
* DTSTART;TZID=US-Eastern:19970929T090000
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2
* RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;COUNT=7
* ==> (1997 9:00 AM EDT)September 29
* (1997 9:00 AM EST)October 30;November 27;December 30
* (1998 9:00 AM EST)January 29;February 26;March 30
* ...
*
* (Original RFC example is set to recur forever. But we just want to verify that the results match the dates listed from
* the RFC example. So just limit the count to 7.)
*/
public function test_second_to_the_last_weekday_of_the_month_forever() {
public function test_second_to_the_last_weekday_of_the_month() {
global $DB;
$this->change_event_startdate('19970929T090000', 'US/Eastern');
$rrule = 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2';
$rrule = 'FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;COUNT=7';
$mang = new rrule_manager($rrule);
$mang->parse_rrule();
$mang->create_events($this->event);
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart');
// Get the first 7 samples. This should be enough to verify that we have generated the recurring events correctly.
$records = $DB->get_records('event', ['repeatid' => $this->event->id], 'timestart ASC', 'id, repeatid, timestart', 0, 7);
$expecteddates = [
(new DateTime('1997-09-29 09:00:00 EDT'))->getTimestamp(),
@@ -2444,10 +2574,8 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
$this->assertLessThanOrEqual($untiltimestamp, $record->timestart);
// Confirm that the first 7 records correspond to the expected dates listed above.
if ($i < 7) {
$this->assertEquals($expecteddates[$i], $record->timestart);
$i++;
}
$this->assertEquals($expecteddates[$i], $record->timestart);
$i++;
}
}
@@ -2747,13 +2875,19 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
/**
* Change the event's timestart (DTSTART) based on the test's needs.
*
* @param string $datestr The date string. In YYYYmmddThhiiss format. e.g. 19990902T090000.
* @param string $timezonestr A valid timezone string. e.g. 'US/Eastern'.
* @param string $datestr The date string. In 'Ymd\This' format. e.g. 19990902T090000.
* @param null|string $timezonestr A valid timezone string. e.g. 'US/Eastern'.
* If not provided, the default timezone will be used.
* @return bool|DateTime
*/
protected function change_event_startdate($datestr, $timezonestr) {
$timezone = new DateTimeZone($timezonestr);
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr, $timezone);
protected function change_event_startdate($datestr, $timezonestr = null) {
// Use default timezone if not provided.
if ($timezonestr === null) {
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr);
} else {
$timezone = new DateTimeZone($timezonestr);
$newdatetime = DateTime::createFromFormat('Ymd\THis', $datestr, $timezone);
}
// Update the start date of the parent event.
$calevent = calendar_event::load($this->event->id);
+3 -2
View File
@@ -85,7 +85,8 @@ $url->param('time', $time);
$PAGE->set_url($url);
if ($courseid != SITEID && !empty($courseid)) {
$course = $DB->get_record('course', array('id' => $courseid));
// Course ID must be valid and existing.
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$courses = array($course->id => $course);
$issite = false;
navigation_node::override_active_url(new moodle_url('/course/view.php', array('id' => $course->id)));
@@ -95,7 +96,7 @@ if ($courseid != SITEID && !empty($courseid)) {
$issite = true;
}
require_course_login($course);
require_login($course, false);
$calendar = new calendar_information(0, 0, 0, $time);
$calendar->prepare_for_view($course, $courses);
+3 -1
View File
@@ -243,7 +243,9 @@ class course_competency extends persistent {
public static function list_courses($competencyid) {
global $DB;
$results = $DB->get_records_sql('SELECT course.id, course.visible, course.shortname, course.idnumber, course.fullname
$results = $DB->get_records_sql('SELECT course.id, course.visible, course.shortname, course.idnumber,
course.fullname, course.summary, course.summaryformat, course.startdate,
course.enddate
FROM {course} course
JOIN {' . self::TABLE . '} coursecomp
ON coursecomp.courseid = course.id
@@ -243,6 +243,8 @@ class user_competency_course extends persistent {
$sql = 'SELECT COUNT(comp.id)
FROM {' . self::TABLE . '} usercoursecomp
JOIN {' . course_competency::TABLE . '} cc
ON usercoursecomp.competencyid = cc.competencyid AND cc.courseid = usercoursecomp.courseid
JOIN {' . competency::TABLE . '} comp
ON usercoursecomp.competencyid = comp.id
WHERE usercoursecomp.courseid = ? AND usercoursecomp.userid = ? AND usercoursecomp.proficiency = ?';
+23 -3
View File
@@ -74,7 +74,16 @@ class completion_completion extends data_object {
* @return data_object instance of data_object or false if none found.
*/
public static function fetch($params) {
return self::fetch_helper('course_completions', __CLASS__, $params);
$cache = cache::make('core', 'coursecompletion');
$key = $params['userid'] . '_' . $params['course'];
if ($hit = $cache->get($key)) {
return $hit['value'];
}
$tocache = self::fetch_helper('course_completions', __CLASS__, $params);
$cache->set($key, ['value' => $tocache]);
return $tocache;
}
/**
@@ -179,9 +188,10 @@ class completion_completion extends data_object {
$this->timeenrolled = 0;
}
$result = false;
// Save record
if ($this->id) {
return $this->update();
$result = $this->update();
} else {
// Make sure reaggregate field is not null
if (!$this->reaggregate) {
@@ -193,7 +203,17 @@ class completion_completion extends data_object {
$this->timestarted = 0;
}
return $this->insert();
$result = $this->insert();
}
if ($result) {
// Update the cached record.
$cache = cache::make('core', 'coursecompletion');
$data = $this->get_record_data();
$key = $data->userid . '_' . $data->course;
$cache->set($key, ['value' => $data]);
}
return $result;
}
}
+5
View File
@@ -724,6 +724,11 @@ class core_course_external extends external_api {
//Note: create_course() core function check shortname, idnumber, category
$course['id'] = create_course((object) $course)->id;
// Create sections that aren't created by core create_course().
if (!empty($course['numsections']) && $course['numsections'] > 0) {
course_create_sections_if_missing((object)$course, range(0, $course['numsections']));
}
$resultcourses[] = array('id' => $course['id'], 'shortname' => $course['shortname']);
}
+47 -1
View File
@@ -55,6 +55,10 @@ define('FIRSTUSEDEXCELROW', 3);
define('MOD_CLASS_ACTIVITY', 0);
define('MOD_CLASS_RESOURCE', 1);
define('COURSE_TIMELINE_PAST', 'past');
define('COURSE_TIMELINE_INPROGRESS', 'inprogress');
define('COURSE_TIMELINE_FUTURE', 'future');
function make_log_url($module, $url) {
switch ($module) {
case 'course':
@@ -1153,8 +1157,10 @@ function course_delete_module($cmid, $async = false) {
// Delete events from calendar.
if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename))) {
$coursecontext = context_course::instance($cm->course);
foreach($events as $event) {
$calendarevent = calendar_event::load($event->id);
$event->context = $coursecontext;
$calendarevent = calendar_event::load($event);
$calendarevent->delete();
}
}
@@ -3920,6 +3926,46 @@ function course_check_updates($course, $tocheck, $filter = array()) {
return array($instances, $warnings);
}
/**
* This function classifies a course as past, in progress or future.
*
* This function may incur a DB hit to calculate course completion.
* @param stdClass $course Course record
* @param stdClass $user User record (optional - defaults to $USER).
* @param completion_info $completioninfo Completion record for the user (optional - will be fetched if required).
* @return string (one of COURSE_TIMELINE_FUTURE, COURSE_TIMELINE_INPROGRESS or COURSE_TIMELINE_PAST)
*/
function course_classify_for_timeline($course, $user = null, $completioninfo = null) {
global $USER;
if ($user == null) {
$user = $USER;
}
$today = time();
// End date past.
if (!empty($course->enddate) && $course->enddate < $today) {
return COURSE_TIMELINE_PAST;
}
if ($completioninfo == null) {
$completioninfo = new completion_info($course);
}
// Course was completed.
if ($completioninfo->is_enabled() && $completioninfo->is_course_complete($user->id)) {
return COURSE_TIMELINE_PAST;
}
// Start date not reached.
if (!empty($course->startdate) && $course->startdate > $today) {
return COURSE_TIMELINE_FUTURE;
}
// Everything else is in progress.
return COURSE_TIMELINE_INPROGRESS;
}
/**
* Check module updates since a given time.
* This function checks for updates in the module config, file areas, completion, grades, comments and ratings.
+5 -3
View File
@@ -20,16 +20,18 @@
// //
///////////////////////////////////////////////////////////////////////////
/*
/**
* This page display the publication backup form
*
* @package course
* @subpackage publish
* @author Jerome Mouneyrac <jerome@mouneyrac.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
*
* This page display the publication backup form
*/
define('NO_OUTPUT_BUFFERING', true);
require_once('../../config.php');
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
+2 -1
View File
@@ -101,7 +101,8 @@ if ($switchrole > 0 && has_capability('moodle/role:switchroles', $context)) {
foreach ($roles as $key => $role) {
$url = new moodle_url('/course/switchrole.php', array('id' => $id, 'switchrole' => $key, 'returnurl' => $returnurl));
echo $OUTPUT->container($OUTPUT->single_button($url, $role), 'm-x-3 m-b-1');
// Button encodes special characters, apply htmlspecialchars_decode() to avoid double escaping.
echo $OUTPUT->container($OUTPUT->single_button($url, htmlspecialchars_decode($role)), 'm-x-3 m-b-1');
}
$url = new moodle_url($returnurl);
+48
View File
@@ -3689,4 +3689,52 @@ class core_course_courselib_testcase extends advanced_testcase {
}
$this->assertEquals(2, $count);
}
public function test_classify_course_for_timeline() {
global $DB, $CFG;
require_once($CFG->dirroot.'/completion/criteria/completion_criteria_self.php');
set_config('enablecompletion', COMPLETION_ENABLED);
$this->resetAfterTest(true);
$this->setAdminUser();
// Create courses for testing.
$generator = $this->getDataGenerator();
$future = time() + 3600;
$past = time() - 3600;
$futurecourse = $generator->create_course(['startdate' => $future]);
$pastcourse = $generator->create_course(['startdate' => $past - 60, 'enddate' => $past]);
$completedcourse = $generator->create_course(['enablecompletion' => COMPLETION_ENABLED]);
$inprogresscourse = $generator->create_course();
// Set completion rules.
$criteriadata = new stdClass();
$criteriadata->id = $completedcourse->id;
// Self completion.
$criteriadata->criteria_self = COMPLETION_CRITERIA_TYPE_SELF;
$class = 'completion_criteria_self';
$criterion = new $class();
$criterion->update_config($criteriadata);
$user = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
$this->getDataGenerator()->enrol_user($user->id, $futurecourse->id, $studentrole->id);
$this->getDataGenerator()->enrol_user($user->id, $pastcourse->id, $studentrole->id);
$this->getDataGenerator()->enrol_user($user->id, $completedcourse->id, $studentrole->id);
$this->getDataGenerator()->enrol_user($user->id, $inprogresscourse->id, $studentrole->id);
$this->setUser($user);
core_completion_external::mark_course_self_completed($completedcourse->id);
$ccompletion = new completion_completion(array('course' => $completedcourse->id, 'userid' => $user->id));
$ccompletion->mark_complete();
// Aggregate the completions.
$this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($pastcourse));
$this->assertEquals(COURSE_TIMELINE_FUTURE, course_classify_for_timeline($futurecourse));
$this->assertEquals(COURSE_TIMELINE_PAST, course_classify_for_timeline($completedcourse));
$this->assertEquals(COURSE_TIMELINE_INPROGRESS, course_classify_for_timeline($inprogresscourse));
}
}
+34
View File
@@ -361,6 +361,40 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
core_course_external::update_categories($categories);
}
/**
* Test create_courses numsections
*/
public function test_create_course_numsections() {
global $DB;
$this->resetAfterTest(true);
// Set the required capabilities by the external function.
$contextid = context_system::instance()->id;
$roleid = $this->assignUserCapability('moodle/course:create', $contextid);
$this->assignUserCapability('moodle/course:visibility', $contextid, $roleid);
$numsections = 10;
$category = self::getDataGenerator()->create_category();
// Create base categories.
$course1['fullname'] = 'Test course 1';
$course1['shortname'] = 'Testcourse1';
$course1['categoryid'] = $category->id;
$course1['courseformatoptions'][] = array('name' => 'numsections', 'value' => $numsections);
$courses = array($course1);
$createdcourses = core_course_external::create_courses($courses);
foreach ($createdcourses as $createdcourse) {
$existingsections = $DB->get_records('course_sections', array('course' => $createdcourse['id']));
$modinfo = get_fast_modinfo($createdcourse['id']);
$sections = $modinfo->get_section_info_all();
$this->assertEquals(count($sections), $numsections + 1); // Includes generic section.
$this->assertEquals(count($existingsections), $numsections + 1); // Includes generic section.
}
}
/**
* Test create_courses
*/
+21 -10
View File
@@ -42,11 +42,9 @@ class writer extends \core\dataformat\base {
public $extension = ".html";
/**
* Write the start of the format
*
* @param array $columns
* Write the start of the output
*/
public function write_header($columns) {
public function start_output() {
echo "<!DOCTYPE html><html>";
echo \html_writer::tag('title', $this->filename);
echo "<style>
@@ -75,9 +73,16 @@ table {
margin: auto;
}
</style>
<body>
<table border=1 cellspacing=0 cellpadding=3>
";
<body>";
}
/**
* Write the start of the sheet we will be adding data to.
*
* @param array $columns
*/
public function start_sheet($columns) {
echo "<table border=1 cellspacing=0 cellpadding=3>";
echo \html_writer::start_tag('tr');
foreach ($columns as $k => $v) {
echo \html_writer::tag('th', $v);
@@ -100,12 +105,18 @@ table {
}
/**
* Write the end of the format
* Write the end of the sheet containing the data.
*
* @param array $columns
*/
public function write_footer($columns) {
echo "</table></body></html>";
public function close_sheet($columns) {
echo "</table>";
}
/**
* Write the end of the sheet containing the data.
*/
public function close_output() {
echo "</body></html>";
}
}
+33 -5
View File
@@ -41,12 +41,31 @@ class writer extends \core\dataformat\base {
/** @var $extension */
public $extension = ".json";
/** @var $sheetstarted */
public $sheetstarted = false;
/** @var $sheetdatadded */
public $sheetdatadded = false;
/**
* Write the start of the format
* Write the start of the file.
*/
public function start_output() {
echo "[";
}
/**
* Write the start of the sheet we will be adding data to.
*
* @param array $columns
*/
public function write_header($columns) {
public function start_sheet($columns) {
if ($this->sheetstarted) {
echo ",";
} else {
$this->sheetstarted = true;
}
$this->sheetdatadded = false;
echo "[";
}
@@ -57,19 +76,28 @@ class writer extends \core\dataformat\base {
* @param int $rownum
*/
public function write_record($record, $rownum) {
if ($rownum) {
if ($this->sheetdatadded) {
echo ",";
}
echo json_encode($record);
$this->sheetdatadded = true;
}
/**
* Write the end of the format
* Write the end of the sheet containing the data.
*
* @param array $columns
*/
public function write_footer($columns) {
public function close_sheet($columns) {
echo "]";
}
/**
* Write the end of the file.
*/
public function close_output() {
echo "]";
}
}
+8
View File
@@ -1,6 +1,14 @@
This files describes API changes in /dataformat/ download system,
information provided here is intended especially for developers.
=== 3.2.4 ===
* In order to allow multiple sheets in an exported file the functions write_header() and write_footer() have
been removed from core dataformat plugins and have been replaced.
- write_header() has been replaced with the two functions start_output() and start_sheet().
- write_footer() has been replaced with the two functions close_output() and close_sheet().
For backwards compatibility write_header() and write_footer() will continue to work.
=== 3.1 ===
* Added new plugin system with low memory support for csv, ods, xls and json
+1 -1
View File
@@ -38,7 +38,7 @@ class enrol_guest_enrol_form extends moodleform {
$heading = $plugin->get_instance_name($instance);
$mform->addElement('header', 'guestheader', $heading);
$mform->addElement('passwordunmask', 'guestpassword', get_string('password', 'enrol_guest'));
$mform->addElement('password', 'guestpassword', get_string('password', 'enrol_guest'));
$this->add_action_buttons(false, get_string('submit'));
+2 -2
View File
@@ -328,7 +328,7 @@ class enrol_ldap_plugin extends enrol_plugin {
return;
}
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'), $this->ldapconnection);
// we may need a lot of memory here
core_php_time_limit::raise();
@@ -761,7 +761,7 @@ class enrol_ldap_plugin extends enrol_plugin {
// Get all contexts and look for first matching user
$ldap_contexts = explode(';', $ldap_contexts);
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'));
$ldap_pagedresults = ldap_paged_results_supported($this->get_config('ldap_version'), $this->ldapconnection);
foreach ($ldap_contexts as $context) {
$context = trim($context);
if (empty($context)) {
+1 -1
View File
@@ -78,7 +78,7 @@ class enrol_self_enrol_form extends moodleform {
if ($instance->password) {
// Change the id of self enrolment key input as there can be multiple self enrolment methods.
$mform->addElement('passwordunmask', 'enrolpassword', get_string('password', 'enrol_self'),
$mform->addElement('password', 'enrolpassword', get_string('password', 'enrol_self'),
array('id' => 'enrolpassword_'.$instance->id));
$context = context_course::instance($this->instance->courseid);
$keyholders = get_users_by_capability($context, 'enrol/self:holdkey', user_picture::fields('u'));
+1 -1
View File
@@ -32,7 +32,7 @@ $action = optional_param('action', '', PARAM_ALPHA);
/// Make sure they can even access this course
if ($courseid) {
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
+1 -1
View File
@@ -38,7 +38,7 @@ $PAGE->set_pagelayout('admin');
/// Make sure they can even access this course
if ($courseid) {
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
+1 -1
View File
@@ -71,7 +71,7 @@ if ($id) {
$heading = get_string('addscale', 'grades');
/// adding new scale from course
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
$scale_rec = new stdClass();
$scale_rec->standard = 0;
+1 -1
View File
@@ -34,7 +34,7 @@ $PAGE->set_url('/grade/edit/scale/index.php', array('id' => $courseid));
/// Make sure they can even access this course
if ($courseid) {
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
+1 -1
View File
@@ -33,7 +33,7 @@ $PAGE->set_url('/grade/edit/settings/index.php', array('id'=>$courseid));
$PAGE->set_pagelayout('admin');
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
+1 -1
View File
@@ -33,7 +33,7 @@ $PAGE->set_url('/grade/edit/tree/action.php', array('id'=>$courseid, 'action'=>$
/// Make sure they can even access this course
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
+1 -1
View File
@@ -39,7 +39,7 @@ if ($section !== 'calculation') {
$PAGE->set_url($url);
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -40,7 +40,7 @@ navigation_node::override_active_url(new moodle_url('/grade/edit/tree/index.php'
array('id'=>$courseid)));
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -45,7 +45,7 @@ if ($userid !== 0) {
$PAGE->set_url($url);
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
$PAGE->set_pagelayout('incourse');
+1 -1
View File
@@ -38,7 +38,7 @@ $PAGE->set_pagelayout('admin');
/// Make sure they can even access this course
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -41,7 +41,7 @@ navigation_node::override_active_url(new moodle_url('/grade/edit/tree/index.php'
array('id'=>$courseid)));
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -40,7 +40,7 @@ navigation_node::override_active_url(new moodle_url('/grade/edit/tree/index.php'
array('id'=>$courseid)));
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -31,7 +31,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/keymanager.php', array('id' => $id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -28,7 +28,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_user_key_login('grade/export', $id); // we want different keys for each course
+1 -1
View File
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/ods/export.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/ods/index.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -29,7 +29,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_user_key_login('grade/export', $id); // we want different keys for each course
+1 -1
View File
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/txt/export.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/txt/index.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -28,7 +28,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_user_key_login('grade/export', $id); // we want different keys for each course
+1 -1
View File
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/xls/export.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/xls/index.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -29,7 +29,7 @@ $decimalpoints = optional_param('decimalpoints', $CFG->grade_export_decimal
$onlyactive = optional_param('export_onlyactive', 0, PARAM_BOOL);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_user_key_login('grade/export', $id); // we want different keys for each course
+1 -1
View File
@@ -23,7 +23,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/xml/export.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -24,7 +24,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/export/xml/index.php', array('id'=>$id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -39,7 +39,7 @@ if ($verbosescales !== 1) {
$PAGE->set_url($url);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -35,7 +35,7 @@ if ($verbosescales !== 1) {
$PAGE->set_url($url);
if (!$course = $DB->get_record('course', array('id' => $id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -31,7 +31,7 @@ $id = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/import/keymanager.php', array('id' => $id));
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -20,7 +20,7 @@ require_once '../../../config.php';
$id = required_param('id', PARAM_INT); // course id
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_user_key_login('grade/import', $id); // we want different keys for each course
+1 -1
View File
@@ -30,7 +30,7 @@ if ($feedback !== 0) {
$PAGE->set_url($url);
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -25,7 +25,7 @@ $PAGE->set_url(new moodle_url('/grade/import/xml/index.php', array('id'=>$id)));
$PAGE->set_pagelayout('admin');
if (!$course = $DB->get_record('course', array('id'=>$id))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -37,7 +37,7 @@ $newvalue = optional_param('newvalue', false, PARAM_TEXT);
/// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
$context = context_course::instance($course->id);
require_login($course);
+3 -2
View File
@@ -56,7 +56,7 @@ $PAGE->requires->yui_module('moodle-gradereport_grader-gradereporttable', 'Y.M.g
// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
@@ -188,7 +188,8 @@ if ($USER->gradeediting[$course->id] && ($report->get_pref('showquickfeedback')
echo '<input type="hidden" value="grader" name="report"/>';
echo '<input type="hidden" value="'.$page.'" name="page"/>';
echo $reporthtml;
echo '<div class="submit"><input type="submit" id="gradersubmit" value="'.s(get_string('savechanges')).'" /></div>';
echo '<div class="submit"><input type="submit" id="gradersubmit" class="btn btn-primary"
value="'.s(get_string('savechanges')).'" /></div>';
echo '</div></form>';
} else {
echo $reporthtml;
+5 -5
View File
@@ -448,22 +448,22 @@ class grade_report_grader extends grade_report {
$this->groupwheresql_params, $enrolledparams, $relatedctxparams);
$sortjoin = "LEFT JOIN {grade_grades} g ON g.userid = u.id AND g.itemid = $this->sortitemid";
$sort = "g.finalgrade $this->sortorder";
$sort = "g.finalgrade $this->sortorder, u.idnumber, u.lastname, u.firstname, u.email";
} else {
$sortjoin = '';
switch($this->sortitemid) {
case 'lastname':
$sort = "u.lastname $this->sortorder, u.firstname $this->sortorder";
$sort = "u.lastname $this->sortorder, u.firstname $this->sortorder, u.idnumber, u.email";
break;
case 'firstname':
$sort = "u.firstname $this->sortorder, u.lastname $this->sortorder";
$sort = "u.firstname $this->sortorder, u.lastname $this->sortorder, u.idnumber, u.email";
break;
case 'email':
$sort = "u.email $this->sortorder";
$sort = "u.email $this->sortorder, u.firstname, u.lastname, u.idnumber";
break;
case 'idnumber':
default:
$sort = "u.idnumber $this->sortorder";
$sort = "u.idnumber $this->sortorder, u.firstname, u.lastname, u.email";
break;
}
+1
View File
@@ -444,6 +444,7 @@ M.gradereport_grader.classes.ajax.prototype.submit = function(properties, values
}
// If feedback is editable and has changed add to the IO queue for it
if (values.editablefeedback && values.feedback !== values.oldfeedback) {
values.feedback = encodeURIComponent(values.feedback);
this.pendingsubmissions.push({transaction:this.report.Y.io.queue(M.cfg.wwwroot+'/grade/report/grader/ajax_callbacks.php', {
method : 'POST',
data : 'id='+this.courseid+'&userid='+properties.userid+'&itemid='+properties.itemid+'&action=update&newvalue='+values.feedback+'&type=feedback&sesskey='+M.cfg.sesskey,
+1 -1
View File
@@ -35,7 +35,7 @@ $PAGE->set_pagelayout('admin');
/// Make sure they can even access this course
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -44,7 +44,7 @@ $PAGE->set_url($url);
/// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
if (!$item = $DB->get_record('grade_items', array('id' => $itemid))) {
+1 -1
View File
@@ -30,7 +30,7 @@ $PAGE->set_url('/grade/report/index.php', array('id'=>$courseid));
/// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$context = context_course::instance($course->id);
+1 -1
View File
@@ -31,7 +31,7 @@ $courseid = required_param('id', PARAM_INT); // course id
$PAGE->set_url('/grade/report/outcomes/index.php', array('id'=>$courseid));
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -33,7 +33,7 @@ $userid = optional_param('userid', $USER->id, PARAM_INT);
$PAGE->set_url(new moodle_url('/grade/report/overview/index.php', array('id' => $courseid, 'userid' => $userid)));
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login(null, false);
$PAGE->set_course($course);
+3 -1
View File
@@ -22,6 +22,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('NO_OUTPUT_BUFFERING', true);
require_once('../../../config.php');
require_once($CFG->dirroot.'/lib/gradelib.php');
require_once($CFG->dirroot.'/grade/lib.php');
@@ -59,7 +61,7 @@ $PAGE->set_url(new moodle_url('/grade/report/singleview/index.php', $pageparams)
$PAGE->set_pagelayout('incourse');
if (!$course = $DB->get_record('course', $courseparams)) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
+1 -1
View File
@@ -41,7 +41,7 @@ if ($userview == 0) {
/// basic access checks
if (!$course = $DB->get_record('course', array('id' => $courseid))) {
print_error('nocourseid');
print_error('invalidcourseid');
}
require_login($course);
$PAGE->set_pagelayout('report');
+4 -3
View File
@@ -152,10 +152,10 @@ echo $OUTPUT->header();
</select></div></td>
<td id="buttonscell">
<p class="arrow_button">
<input name="add" id="add" type="submit"
<input class="btn btn-secondary" name="add" id="add" type="submit"
value="<?php echo $OUTPUT->larrow().'&nbsp;'.get_string('add'); ?>"
title="<?php print_string('add'); ?>" /><br>
<input name="remove" id="remove" type="submit"
<input class="btn btn-secondary" name="remove" id="remove" type="submit"
value="<?php echo get_string('remove').'&nbsp;'.$OUTPUT->rarrow(); ?>"
title="<?php print_string('remove'); ?>" />
</p>
@@ -173,7 +173,8 @@ echo $OUTPUT->header();
</td>
</tr>
<tr><td colspan="3" id="backcell">
<input type="submit" name="cancel" value="<?php print_string('backtogroupings', 'group'); ?>" />
<input class="btn btn-secondary" type="submit" name="cancel"
value="<?php print_string('backtogroupings', 'group'); ?>" />
</td></tr>
</table>
</div>

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