Compare commits

..

285 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 8e4341402a Moodle release 3.3.1 2017-07-08 20:43:39 +02:00
AMOS bot 0a5af1649f Automatically generated installer lang files 2017-07-08 00:16:05 +08:00
Jake Dallimore b194f1a2e3 weekly release 3.3+ 2017-07-07 12:10:20 +08:00
Jake Dallimore 14ecaeea08 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2017-07-07 12:10:18 +08:00
AMOS bot c28de2e556 Automatically generated installer lang files 2017-07-07 00:06:27 +08:00
Simey Lameze 706571e94f MDL-59456 auth_cas: patch phpCAS auth bypass vulnerability 2017-07-06 09:35:43 +01:00
Jun Pataleta 0801d7dc95 MDL-58651 logstore_database: Set dbhandlesoptions in test page 2017-07-05 23:04:37 +08:00
Dan Poltawski 77da99fe77 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:30 +02:00
Eloy Lafuente (stronk7) c88b34c0fa Merge branch 'MDL-59398-33-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2017-07-05 11:52:27 +02:00
Eloy Lafuente (stronk7) 23dbc35541 Merge branch 'MDL-59294-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-07-05 09:43:44 +02:00
Eloy Lafuente (stronk7) e9609517d2 Merge branch 'MDL-58286-33' of https://github.com/xow/moodle into MOODLE_33_STABLE 2017-07-05 09:40:39 +02:00
Eloy Lafuente (stronk7) efc9c7572b Merge branch 'wip-MDL-59412-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-07-05 09:35:13 +02:00
Helen Foster 05263df3b0 MDL-59398 lang: Merge English strings from the en_fix language pack 2017-07-05 09:31:39 +02:00
Marina Glancy dc30c8fa2f MDL-59412 course: do not display completion icon for unavailable mod 2017-07-05 09:58:35 +08:00
John Okely 8b3ee7d311 MDL-58286 enrol_ldap: Pass connection to ldap_paged_results_supported
Thanks to Bianco Veigel for the original patch.
2017-07-05 09:49:48 +08:00
Jun Pataleta 5823f7e1bd MDL-59294 block_login: Make display of ID provider buttons consistent 2017-07-05 09:08:11 +08:00
Jun Pataleta 4dfa466691 MDL-59294 theme_bootstrapbase: Fix display of ID provider buttons 2017-07-05 09:08:11 +08:00
Eloy Lafuente (stronk7) 226ca38be3 Merge branch 'MDL-58651_33' of git://github.com/aolley/moodle into MOODLE_33_STABLE 2017-07-05 01:23:22 +02:00
Eloy Lafuente (stronk7) 145e6deee7 Merge branch 'wip-MDL-59336-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-07-04 19:59:17 +02:00
Jake Dallimore d53a5789a8 Merge branch 'MDL-59380-33' of git://github.com/damyon/moodle into MOODLE_33_STABLE 2017-07-04 16:29:11 +08:00
Marina Glancy 640534676c MDL-59409 admin: set admin user in unittest 2017-07-04 11:05:11 +08:00
Ankit Agarwal 49371ca433 MDL-56565 forum: Add sitename as heading when there is nothing to display 2017-07-04 10:11:37 +08:00
Ankit Agarwal 5697a42fc2 MDL-56565 forum: Make sure userfullname is not disclosed 2017-07-04 10:11:37 +08:00
Jake Dallimore 0ba4ffe353 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:37 +08:00
Jake Dallimore 31bae37249 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:37 +08:00
Jake Dallimore 2423a989fc 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:37 +08:00
Mark Nelson 67103939ac MDL-59304 core_calendar: check if course is hidden in bailout callback 2017-07-04 10:11:37 +08:00
Marina Glancy 4f91eb0ba1 MDL-59409 admin: check access to every setting in category 2017-07-04 10:03:16 +08:00
Jake Dallimore 07cb3212c5 Merge branch 'MDL-59008-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-07-03 15:56:18 +08:00
Simey Lameze 550e03463b MDL-59008 repository: add reload parent window support to callback 2017-07-03 13:45:41 +08:00
Simey Lameze 4f2c5e18c0 MDL-59008 repository_onedrive: add method to serve login on a popup 2017-07-03 13:45:41 +08:00
Simey Lameze 73aad88f63 MDL-59008 repository_googledocs: add method to serve login on a popup
This commit also add a new string logintoaccount to make the login
button more clear.
2017-07-03 13:45:40 +08:00
Simey Lameze 88d7acff69 MDL-59008 mod_resource: add option to serve external files embed 2017-07-03 13:45:40 +08:00
Jake Dallimore 59f5f4a9df weekly release 3.3+ 2017-06-29 16:23:52 +08:00
Jake Dallimore 14509286e4 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2017-06-29 16:23:51 +08:00
Mark Nelson 6b661ab0a2 MDL-56046 mod_quiz: do not close the sheet twice 2017-06-28 14:14:28 +08:00
Adam Olley 57cb067173 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:09 +09:30
Eloy Lafuente (stronk7) 65e5e9f454 Merge branch 'MDL-57809-33-progressbar' of https://github.com/roperto/moodle into MOODLE_33_STABLE 2017-06-27 20:17:34 +02:00
Eloy Lafuente (stronk7) 7984ae3581 Merge branch 'wip-MDL-59136-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-06-27 18:09:43 +02:00
David Monllao f786e59224 Merge branch 'MDL-32151-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-06-27 17:47:00 +02:00
Eloy Lafuente (stronk7) c46c38d355 Merge branch 'MDL-59362_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-27 17:22:02 +02:00
Danny Jung 67c112bf9c MDL-59073 Workshop: Prevent submission without content or file 2017-06-27 17:05:35 +02:00
David Monllao 61812e3dd8 Merge branch 'wip-MDL-59308-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-06-27 16:42:33 +02:00
David Monllao eaeed5b281 Merge branch 'MDL-59158-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-06-27 16:39:56 +02:00
David Monllao d259cafd3c Merge branch 'MDL-57927-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-27 15:55:33 +02:00
Eloy Lafuente (stronk7) e632f4ece5 Merge branch 'MDL-58844-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2017-06-27 11:42:14 +02:00
Eloy Lafuente (stronk7) aff28d6243 Merge branch 'MDL-59296-33' of git://github.com/crazyserver/moodle into MOODLE_33_STABLE 2017-06-27 11:40:03 +02:00
Jake Dallimore 653ec0d0b0 Merge branch 'MDL-59312-33' of https://github.com/xow/moodle into MOODLE_33_STABLE 2017-06-27 15:08:23 +08:00
Jake Dallimore 62a71e4a17 Merge branch 'MDL-59275-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-27 13:59:14 +08:00
Damyon Wiese 35657809ed 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:37 +08:00
Jake Dallimore c61c5009a8 Merge branch 'MDL-56046_33-fix' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-27 13:17:25 +08:00
Simey Lameze fe9e229248 MDL-59275 auth: prevent user login failed coding error 2017-06-27 13:07:13 +08:00
Mark Nelson db500a32a1 MDL-56046 dataformat: minor changes to PHPDocs and upgrade.txt 2017-06-27 11:25:22 +08:00
Andrew Nicols 75ead1e8cf 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:36:52 +08:00
Eloy Lafuente (stronk7) c7c9f4a46e Merge branch 'MDL-56046_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-27 02:42:48 +02:00
Eloy Lafuente (stronk7) 8e9c8f6583 Merge branch 'MDL-40818-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-06-27 01:50:39 +02:00
Eloy Lafuente (stronk7) 037bf82652 Merge branch 'MDL-59295-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-27 00:53:44 +02:00
Eloy Lafuente (stronk7) 5341d76031 MDL-58813 phpunit: pick test from 32_STABLE to fix expected behavior 2017-06-26 19:45:05 +02:00
Eloy Lafuente (stronk7) e71b162d09 Merge branch 'MDL-59297_myoverview_error_33' of git://github.com/davosmith/moodle into MOODLE_33_STABLE 2017-06-26 13:04:57 +02:00
Mark Nelson 58099bd24d MDL-56046 core: enable multiple sheets for flexible table 2017-06-26 13:56:38 +08:00
Mark Nelson c7da8264d0 MDL-56046 dataformat: added related information to upgrade.txt 2017-06-26 13:56:38 +08:00
Mark Nelson ca47e80375 MDL-56046 dataformat_*: convert core plugins 2017-06-26 13:30:56 +08:00
Mark Nelson 40e7ac2c70 MDL-56046 core: convert download_as_dataformat to use new API 2017-06-26 13:30:56 +08:00
Mark Nelson d7a2d1a2c8 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:28:44 +08:00
Mark Nelson d971e7dffe MDL-59362 core: ensure we use 'new' when throwing exceptions 2017-06-26 13:10:31 +08:00
Marina Glancy 56855a2842 MDL-59136 roles: avoid double escaping in role names 2017-06-26 11:57:37 +08:00
Marina Glancy 7563339608 MDL-59336 themes: change FA mapping for i/new 2017-06-26 11:37:04 +08:00
Jake Dallimore 89d85f5a4b Merge branch 'MDL-49484-moodle33' of github.com:jebarviabb/moodle into MOODLE_33_STABLE 2017-06-26 10:52:15 +08:00
Josh Ebarvia 74823e4e45 MDL-49484 mod_lesson: Fix lesson page headers when editing 2017-06-24 05:23:52 +09:30
AMOS bot 7a0e1cd70c Automatically generated installer lang files 2017-06-24 00:08:53 +08:00
AMOS bot 4534c7b531 Merge branch 'MOODLE_33_STABLE' into install_33_STABLE 2017-06-24 00:08:53 +08:00
Pau Ferrer Ocaña 16f2fe5514 MDL-59296 data: Fix latlong field search 2017-06-23 09:15:35 +02:00
Andrew Nicols eee0d699c3 MDL-59312 js: Improve display of exception stacktrace 2017-06-23 10:50:05 +08:00
John Okely 0d74c11cf7 MDL-59312 notification: Normalise backtrace/stacktrace 2017-06-23 10:50:05 +08:00
Andrew Nicols 6aebb4375f MDL-59312 js: Add exception on AJAX error 2017-06-23 10:50:04 +08:00
Jun Pataleta 32f2e90522 MDL-32151 group: Use appropriate error langstring error key 2017-06-23 10:28:25 +08:00
Jun Pataleta 8e62bc79c7 MDL-32151 grade: Use appropriate error langstring error key 2017-06-23 10:28:25 +08:00
Jun Pataleta c36c507277 MDL-59158 theme_boost: Remove auto width and height for user picture 2017-06-23 10:12:54 +08:00
Jun Pataleta 813f289b60 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:16 +08:00
Daniel Thee Roperto e318be3772 MDL-57809 weblib: Added missing NO_OUTPUT_BUFFERING directive. 2017-06-23 09:43:32 +10:00
Daniel Thee Roperto a67ff779d5 MDL-57809 weblib: Added opening disclaimer and file-level phpdocs. 2017-06-23 09:43:32 +10:00
Daniel Thee Roperto 222a87ae98 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:43:32 +10:00
AMOS bot 8d0dd90520 Automatically generated installer lang files 2017-06-23 00:07:50 +08:00
Dan Poltawski cccb1a6d21 weekly release 3.3+ 2017-06-22 15:40:49 +01:00
Marina Glancy 3d8a2c5cd9 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-22 16:01:33 +08:00
Simey Lameze ebe0cf3ed4 MDL-59295 tool_lp: remove useless ng-label attribute 2017-06-22 15:49:26 +08:00
Eloy Lafuente (stronk7) 9938165bb8 Merge branch 'MDL-59170-33' of https://github.com/xow/moodle into MOODLE_33_STABLE 2017-06-22 03:50:17 +02:00
John Okely 101271fd28 MDL-59170 fontawesome: Fix course total controls icon on grader report 2017-06-22 09:13:02 +08:00
Davo Smith 4ca3991e56 MDL-59297 block_myoverview: fix fatal error (missing require_once) 2017-06-21 08:01:53 +01:00
Eloy Lafuente (stronk7) f6736dedd1 Merge branch 'MDL-58985-33-bluebubbles' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2017-06-21 00:43:53 +02:00
Eloy Lafuente (stronk7) 5be425cf9e Merge branch 'wip-MDL-59263-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-06-20 18:04:08 +02:00
Eloy Lafuente (stronk7) 0f0b45fd59 Merge branch 'MDL-59269-33-languninstall' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2017-06-20 17:56:59 +02:00
Mathieu Petit-Clair f05e2e6690 MDL-58952 admin: use valid default for language selection dropdown. 2017-06-20 11:31:49 +01:00
Dan Poltawski b0b68a0bd4 Merge branch 'MDL-59005-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-20 09:52:12 +01:00
Dan Poltawski 7abe668bd6 Merge branch 'MDL-58472-33' of git://github.com/damyon/moodle into MOODLE_33_STABLE 2017-06-20 09:37:24 +01:00
Jun Pataleta b31f3097c2 Merge branch 'wip-MDL-58911-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-06-20 16:34:02 +08:00
Jun Pataleta 82b3050e72 Merge branch 'MDL-57770-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-20 16:28:20 +08:00
Marina Glancy 153f74956d MDL-58911 calendar: use the same callbacks in unittests and prod
Remove unittest-specific callbacks for checking access and displaying
the calendar events on the dashboard.

This will allow plugin developers unittest the full behavior
of how their plugins add events to the dashboard.

Reset all static caches between unittests.
2017-06-20 16:17:26 +08:00
Jake Dallimore 8b017ea78c Merge branch 'wip-MDL-58729-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2017-06-20 15:18:37 +08:00
Jun Pataleta cea093be87 Merge branch 'MDL-58766_33-clean-tree-item-indent' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-06-20 15:10:19 +08:00
Jun Pataleta 970c74b280 Merge branch 'MDL-59270-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-20 10:00:19 +08:00
Simey Lameze 04e5ef2a3e MDL-57927 tool_lp: make both buttons consistent 2017-06-20 08:50:14 +08:00
Simey Lameze b2a90870ce MDL-59270 block_myoverview: tab setting logic to main template on clean 2017-06-20 08:46:05 +08:00
Damyon Wiese ae60722b14 MDL-58808 fontawesome: nav and settings blocks 2017-06-20 08:22:59 +08:00
Dan Poltawski 26277438ed Merge branch 'MDL-59048_33' of https://github.com/timhunt/moodle into MOODLE_33_STABLE 2017-06-19 15:43:25 +01:00
Dan Poltawski 17eb11f801 Merge branch 'MDL-59173-33' of git://github.com/tobiasreischmann/moodle into MOODLE_33_STABLE 2017-06-19 12:27:44 +01:00
Dan Poltawski 3ae9ed890f Merge branch 'wip-MDL-51917-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-06-19 12:21:46 +01:00
Dan Poltawski 0ff0caefc0 Merge branch 'MDL-46418-33-hiddenrepos' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2017-06-19 10:33:35 +01:00
Jun Pataleta a5efab81c9 Merge branch 'MDL-44961-33' of git://github.com/ankitagarwal/moodle into MOODLE_33_STABLE 2017-06-19 16:25:03 +08:00
Jun Pataleta bc84e4e4ae Merge branch 'MDL-58310-33' of https://github.com/xow/moodle into MOODLE_33_STABLE 2017-06-19 13:26:13 +08:00
John Okely e70d1e66d6 MDL-58310 ajax: suppress errors upon page unload 2017-06-19 11:45:29 +08:00
John Okely e256446c75 MDL-58310 message: No longer need to supress errors from messaging 2017-06-19 11:45:29 +08:00
Jake Dallimore e4780bf151 Merge branch 'MDL-59230-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-19 09:13:22 +08:00
Vladimir Zhirov 4b8d403606 MDL-59005 resource: fixed zip extraction for filenames in CP-1251/CP-866 2017-06-19 08:50:59 +08:00
Luca Bösch 8a32c0fdb3 MDL-58766 css: clean theme block alignment 2017-06-16 16:12:28 +02:00
David Mudrák a27fa5b50e 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:05:31 +02:00
Simey Lameze 3cf5c5152e MDL-59230 block_myoverview: add missing core notification module 2017-06-16 16:40:02 +08:00
Tobias Reischmann c484b0574e 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:17 +02:00
Jake Dallimore dec00f6a53 weekly release 3.3+ 2017-06-16 13:29:39 +08:00
Jake Dallimore d51518e24d Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2017-06-16 13:29:38 +08:00
Jean-Roch Meurisse - University of Namur - Belgium 94925c38d0 MDL-59263 roles: Wrong order of parameters in calls to pix_icon function 2017-06-16 10:07:22 +08:00
David Mudrák 7abd8de776 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:20:03 +02:00
Jake Dallimore a358927e9e MDL-58248 theme: use pix icon for side panel menu icon instead of char
Replaces the trigram for heaven char with the fa-bars pix icon for
improved support with all screen readers.
2017-06-15 17:08:33 +08:00
Simey Lameze 49e5b8438c MDL-57770 tool_lp: style fixes for the competency rule dialog 2017-06-15 15:38:23 +08:00
Mark Nelson 2b026b44f7 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:14 +08:00
Ankit Agarwal 63bfa5afdb MDL-44961 logs: Keep log dates constant during restore 2017-06-14 15:21:54 +05:30
Jake Dallimore d08cd28dae Merge branch 'MDL-59142-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-14 11:36:19 +08:00
Dan Poltawski 5d7d2c0a45 Merge branch 'MDL-59171-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-06-13 14:40:45 +01:00
Dan Poltawski 9eb46e7d75 Merge branch 'MDL-59140_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-13 13:23:33 +01:00
Mark Nelson 481220cb4c MDL-59140 core: upgrade 'navcourselimit' if set to old default value 2017-06-13 18:22:58 +08:00
Mark Nelson d47b680074 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:21:58 +08:00
Mark Nelson 76b6407cb8 MDL-59140 core: changes to the 'navcourselimit' setting
Changed the default and description.
2017-06-13 18:21:18 +08:00
Eloy Lafuente (stronk7) ca1e040bbf Merge branch 'wip-MDL-58523-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2017-06-13 11:21:12 +02:00
Jun Pataleta 1312c844a1 Merge branch 'MDL-59012-33-linkurl' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2017-06-14 17:11:47 +08:00
Jun Pataleta a21c3208ea Merge branch 'MDL-58991-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-14 16:56:23 +08:00
Dan Poltawski a1692f6362 Merge branch 'MDL-41426_33-block-completionstatus-spaces' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-06-13 09:53:59 +01:00
Eloy Lafuente (stronk7) 9bcb6e1bec MDL-46322 database: alias sort fields to avoid ambiguous naming 2017-06-13 09:17:04 +01:00
Jake Dallimore 192a355707 Merge branch 'MDL-58136-33' of git://github.com/damyon/moodle into MOODLE_33_STABLE 2017-06-13 15:54:42 +08:00
Damyon Wiese 3709386ed5 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:07:50 +08:00
Marina Glancy c159483796 MDL-51917 course completion: order activities in reports
Thanks to Nick Phillips for initial patch
2017-06-13 14:49:35 +08:00
Marina Glancy 9bdff1611b MDL-58523 mod_feedback: deleting response should reset completion 2017-06-13 14:36:24 +08:00
Jake Dallimore ca18b0c33d Merge branch 'MDL-51691-moodle33' of https://github.com/jebarviabb/moodle into MOODLE_33_STABLE 2017-06-13 10:32:45 +08:00
Damyon Wiese 0fb6f059a9 MDL-58136 navigation: Ensure we have all course fields
To properly classify courses we need the start/end dates etc.
2017-06-13 10:09:44 +08:00
Marcus Green 7dc35ed9d2 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:50:01 +08:00
Simey Lameze 481a5ce58b MDL-59142 core_theme: cache post-processed css
Thanks Cameron Ball for the base patch
2017-06-13 09:36:44 +08:00
Damyon Wiese af153671de 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:12:25 +08:00
Eloy Lafuente (stronk7) 48b929667e Merge branch 'MDL-59032-33' of git://github.com/damyon/moodle into MOODLE_33_STABLE 2017-06-13 01:28:22 +02:00
Eloy Lafuente (stronk7) 6dc00c8423 Merge branch 'MDL-40015-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2017-06-13 01:23:43 +02:00
Eloy Lafuente (stronk7) 290ec233f5 Merge branch 'mdl58161-moodle33' of https://github.com/tlock/moodle into MOODLE_33_STABLE 2017-06-13 01:21:54 +02:00
Eloy Lafuente (stronk7) 56aa74ed3c Merge branch 'MDL-59056_33-admin-allowstealth-select-checkbox' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-06-13 01:19:26 +02:00
Josh Ebarvia fe3d722d69 MDL-51691 assignsubmission_feedback: Fix delete comments 2017-06-13 08:35:25 +09:30
Eloy Lafuente (stronk7) 792560a608 Merge branch 'MDL-58907_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-13 01:03:43 +02:00
Eloy Lafuente (stronk7) 7041dc6f8a Merge branch 'MDL-59132-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2017-06-13 00:45:09 +02:00
Tim Lock 57fb48743f MDL-58161 user: tests: user_can_view_profile fails under certain cases 2017-06-13 08:10:43 +09:30
Eloy Lafuente (stronk7) a9712dacbe Merge branch 'MDL-59112-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2017-06-12 14:39:14 +02:00
Dan Poltawski c0f4b8b3c1 Merge branch 'mdl46322-moodle33' of https://github.com/AndresMelo/moodle into MOODLE_33_STABLE 2017-06-12 10:29:18 +01:00
Damyon Wiese 9a9b9e53f0 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:08:57 +08:00
Damyon Wiese e1d15194bc 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:08:18 +08:00
David Mudrák 5b2f32ca92 MDL-58985 course: Fix display of availability information
The availability info text can be either a one line short text such as
"Hidden from students" but it can also be a long HTML formatted text
with the list of all restricted access conditions. For the latter, using
bootstrap labels was not appropriate.

This extends the template context data with some boolean flags that
allow to better distinguish the source and meaning of the availability
information and display it accordingly.

Credit goes to Marina Glancy for the solution idea.
2017-06-12 09:30:57 +02:00
Jun Pataleta a53a439c08 Merge branch 'MDL-59042-33-upgradefix' of github.com:snake/moodle into MOODLE_33_STABLE 2017-06-12 15:30:54 +08:00
Jake Dallimore 2c12e7f534 MDL-59042 upgrade: fix for non existent table in core upgrade.
Moved upgrade step to the assign mod where table is known to exist.
2017-06-12 15:26:03 +08:00
Adrian Greeve 7255306cc8 MDL-58729 database: Improve performance of CLI tool.
Imporve the speed with which mysql_collation converts to
a different collation.
2017-06-12 14:14:35 +08:00
Jake Dallimore b545e84294 Merge branch 'MDL-57103-33' of https://github.com/xow/moodle into MOODLE_33_STABLE 2017-06-12 14:00:25 +08:00
Jun Pataleta 72ebc73897 Merge branch 'MDL-59154-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2017-06-12 13:45:16 +08:00
Jun Pataleta 856e1c24c2 Merge branch 'MDL-59042-33' of git://github.com/snake/moodle into MOODLE_33_STABLE 2017-06-12 13:29:21 +08:00
Jake Dallimore 5b1dffd5b0 MDL-59042 upgrade: datafix assign group overrides with null priority
Find any events records for assign group overrides having null priority
and sets their priority to the sortorder value from the corresponding
assign_overrides table entry.
2017-06-12 13:19:28 +08:00
John Okely 6ebff58d8c MDL-57103 lib: Force ajax renderer for all ajax fatal errors 2017-06-12 10:36:59 +08:00
Mark Nelson 54bee25c65 MDL-58907 block_myoverview: change URL when tab is selected
We then check if this paramter exists in the URL and if it
does we display the specified tab.
2017-06-12 10:35:23 +08:00
Mark Nelson 355fefbe71 MDL-58907 block_myoverview: display last tab user was on 2017-06-12 10:35:23 +08:00
Mark Nelson 11a24a823b MDL-58907 block_myoverview: added setting to select default tab 2017-06-12 10:35:23 +08:00
Jun Pataleta 75797500ae MDL-59171 mod_lti: Set mod_lti_view_lti's type to 'read' 2017-06-12 08:35:03 +08:00
Jake Dallimore e2b8d30052 MDL-59042 assign: Group override edit no longer resets event priority
Fixed a bug in which $fromform->sortorder wasn't set before passing
$formdata to assign_update_events, resulting in the existing event
priority being incorrectly nulled and breaking the effective override.
2017-06-09 15:28:08 +08:00
Luca Bösch 571e862135 MDL-59056 admin: allowstealth yes/no checkbox instead of on/off 2017-06-08 21:09:54 +02:00
Luca Bösch 1e9ba1916b MDL-41426 block: Whitespace lacking in completion status block 2017-06-08 19:10:41 +02:00
AMOS bot ddd849e1d5 Automatically generated installer lang files 2017-06-09 00:18:26 +08:00
Dan Poltawski 760ed1dfde weekly release 3.3+ 2017-06-08 12:16:24 +01:00
Dan Poltawski 95a6fe8b05 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2017-06-08 12:16:23 +01:00
Juan Leyva 0fca28e197 MDL-59132 mod_feedback: Fix anonymous responses numbering
This was done correctly by the web scrip but not by the WS.
2017-06-08 11:16:52 +01:00
Juan Leyva cc5235bb77 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:39 +01:00
Juan Leyva 1099b7ce1d 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:39 +01:00
Andrew Nicols dc403b8386 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:27 +08:00
Dan Poltawski 23bec87007 Merge branch 'MDL-59101-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-06-07 16:26:19 +01:00
Jun Pataleta 924db1a0a6 MDL-59101 calendar: Properly calculate expected until date 2017-06-07 23:13:05 +08:00
Jake Dallimore f8326931a1 Merge branch 'MDL-59076_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-07 09:24:57 +08:00
Damyon Wiese 0a98628841 MDL-58908 auth_oauth2: Don't kill gravatar
If gravatar is enabled, don't update profile pictures.
2017-06-06 17:29:56 +08:00
Dan Poltawski d72a096797 Merge branch 'MDL-58658' of https://github.com/sk-unikent/moodle into MOODLE_33_STABLE 2017-06-06 10:02:32 +01:00
Damyon Wiese a6379acaf3 MDL-59032 scorm: Don't show action events to teachers 2017-06-06 15:57:39 +08:00
Dan Poltawski e002d8c2db Merge branch 'MDL-59086_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-06-06 08:44:49 +01:00
Simey Lameze 2b7268d645 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:15 +08:00
Mark Nelson 6e34867b93 MDL-59076 format_weeks: if 'enddate' does not exist in backup then use 0 2017-06-06 12:42:36 +08:00
Jun Pataleta 9a6e95557f Merge branch 'MDL-58646-33' of git://github.com/danpoltawski/moodle into MOODLE_33_STABLE 2017-06-06 12:24:29 +08:00
Jake Dallimore 88daff0ff3 Merge branch 'MDL-58900-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2017-06-06 11:39:43 +08:00
Eloy Lafuente (stronk7) 3309800768 Merge branch 'MDL-58826_33_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_33_STABLE 2017-06-06 01:44:56 +02:00
Eloy Lafuente (stronk7) adbba36a63 Merge branch 'MDL-59096-m33' of https://github.com/sammarshallou/moodle into MOODLE_33_STABLE 2017-06-06 01:41:41 +02:00
Dan Poltawski 37ff4578be Merge branch 'MDL-59080_M33' of git://github.com/lazydaisy/moodle into MOODLE_33_STABLE 2017-06-05 12:49:46 +01:00
Mark Johnson cbc3742d71 MDL-58826 theme_boost: Prevent fatal errors in action menu behat steps 2017-06-05 09:05:34 +01:00
AMOS bot 56e407f8a0 Automatically generated installer lang files 2017-06-05 00:05:48 +08:00
AMOS bot 362e7721f5 Automatically generated installer lang files 2017-06-04 00:07:14 +08:00
AMOS bot 53fd95f715 Automatically generated installer lang files 2017-06-04 00:07:14 +08:00
Dan Poltawski 078aaae0cf Merge branch 'MDL-59091_gherkinlint_fix_33' of https://github.com/mrmark/moodle into MOODLE_33_STABLE 2017-06-03 08:54:44 +01:00
Mark Nielsen 4f66cd826f MDL-59091 behat: Fix gherkinlint errors
Just whitespace problems.
2017-06-02 09:36:31 -07:00
Mark Nielsen 028f587670 MDL-59091 behat: Properly propagate gherkinlint exit code 2017-06-02 09:36:18 -07:00
AMOS bot 0b2e862c7a Automatically generated installer lang files 2017-06-03 00:07:42 +08:00
sam marshall 8db0bcc018 MDL-59096 Tasks: Web running local plugin scheduled tasks fails 2017-06-02 17:07:01 +01:00
Dan Poltawski bb6a2082f8 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:04:23 +01:00
Mary Evans dfac161651 MDL-59080 theme_boost: make drawer.scss variables default
--author="Urs Hunkler <urs.hunkler@unodo.de>"
2017-06-02 07:57:57 +01:00
Dan Poltawski f41c1f82bc weekly release 3.3+ 2017-06-01 09:28:28 +01:00
Dan Poltawski 443f993467 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2017-06-01 09:28:27 +01:00
Jake Dallimore 0e72aac68a Merge branch 'MDL-59094-33' of git://github.com/danpoltawski/moodle into MOODLE_33_STABLE 2017-06-01 15:28:34 +08:00
AMOS bot 4cd564dd65 Automatically generated installer lang files 2017-06-01 00:12:20 +08:00
Dan Poltawski c6c462903e Merge branch 'MDL-59093-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-05-31 11:10:38 +01:00
Dan Poltawski be4a2e7773 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:11:40 +01:00
Jun Pataleta 283140134b MDL-59093 calendar: Use a fixed start day for forever BYMONTH test 2017-05-31 15:02:04 +08:00
Simey Lameze c779c4fa0b MDL-58900 mod_assign: fix incorrect overrides ordering 2017-05-31 10:51:21 +08:00
Jake Dallimore 4577aa88fd Merge branch 'MDL-54887-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-05-31 08:39:08 +08:00
Eloy Lafuente (stronk7) 3add309d96 Merge branch 'MDL-49988_fix_wiki_preview_33_STABLE' of https://github.com/DMaterka/moodle into MOODLE_33_STABLE 2017-05-31 00:30:19 +02:00
Dan Poltawski 1c2a935975 Merge branch 'MDL-58997_33-group-names-multilang' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-05-30 16:57:34 +01:00
Luca Bösch 574aa817c1 MDL-58997 calendar: Group names passing multilang filters. 2017-05-30 16:51:38 +02:00
Eloy Lafuente (stronk7) 98a7bb9cd5 Merge branch 'MDL-58994-33' of git://github.com/cameron1729/moodle into MOODLE_33_STABLE 2017-05-30 12:50:51 +02:00
Dan Poltawski f35ff40f4a Merge branch 'MDL-49040-moodle33' of https://github.com/jebarviabb/moodle into MOODLE_33_STABLE 2017-05-30 11:42:34 +01:00
Jun Pataleta 2529f11ce3 Merge branch 'MDL-57313-33-clibootswatch' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2017-05-30 16:57:51 +08:00
Jun Pataleta 26f4cf3ad8 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:54:05 +08:00
Soon-Systems 23ec9e80b4 MDL-54887 calendar: Format summary + description of an event for export 2017-05-30 16:54:05 +08:00
Dan Poltawski 8710174991 Merge branch 'MDL-59014-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-05-30 08:33:37 +01:00
Mark Nelson e399833263 MDL-59086 gradereport_grader: style 'Save changes' button 2017-05-30 13:44:04 +08:00
AMOS bot 59411b45f6 Automatically generated installer lang files 2017-05-28 14:07:00 +08:00
David Mudrák 767622050e MDL-57313 boost: Fix the CLI utility import-bootswatch.php 2017-05-26 09:52:13 +02:00
Dan Poltawski 6696cff321 weekly release 3.3+ 2017-05-24 19:14:46 +01:00
Tim Hunt f59741cc6c MDL-59048 user tours: avoid white-on-white text in Clean 2017-05-24 17:28:02 +01:00
Andrew Nicols 524724c642 Merge branch 'MDL-59011-33' of git://github.com/ankitagarwal/moodle into MOODLE_33_STABLE 2017-05-24 14:18:58 +08:00
Ankit Agarwal ca31084da2 MDL-59011 restore: Check for userride only for activity events 2017-05-24 09:59:28 +05:30
Andrew Nicols 52ecbf8f4c MDL-58577 stats: Correct groupby when getting report options 2017-05-23 19:45:28 +08:00
Andrew Nicols d9c2abaa65 Merge branch 'MDL-58577_33-statistics-report-header-multilang' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-05-23 19:45:24 +08:00
David Mudrák 30613bca8d MDL-59012 auth_oauth2: Do not escape URL in plain text emails 2017-05-23 13:38:28 +02:00
Jun Pataleta cb3bad1d50 MDL-59014 calendar: Unescape event URL for the mini calendar 2017-05-23 17:21:18 +08:00
Luca Bösch e4eab531bf MDL-58577 stats: Use multilang with role in header 2017-05-23 11:12:22 +02:00
Jun Pataleta 068d573375 Merge branch 'MDL-58895-33' of git://github.com/ankitagarwal/moodle into MOODLE_33_STABLE 2017-05-23 16:53:45 +08:00
Jake Dallimore df78e4c8ab Merge branch 'MDL-58921_33-calculated-question-name-multilang' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-05-23 16:26:25 +08:00
Jun Pataleta 5fbe152a58 Merge branch 'MDL-58165-33' of https://github.com/abias/moodle into MOODLE_33_STABLE 2017-05-23 14:47:11 +08:00
Ankit Agarwal 7fe005f6d1 MDL-58895 groups: Add bootstrap classes to buttons 2017-05-23 12:05:56 +05:30
Alexander Bias 2a615a6031 MDL-58165 navigation: Add node key to private files navigation node 2017-05-23 07:22:23 +02:00
Josh Ebarvia cb065a2d2f MDL-49040 gradereport_grader: Fix feedback truncation after & char 2017-05-23 13:03:44 +09:30
Dan Poltawski e0adce5360 Merge branch 'MDL-58922_33-calculatedmulti-question-name-multilang' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-05-22 10:45:52 +01:00
Luca Bösch 613db5afcb 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:36:54 +02:00
Luca Bösch b38538fbdf 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:18 +02:00
David Monllao f96167c02e Merge branch 'MOODLE_33_STABLE_MDL-56973' of https://github.com/fwsl/moodle into MOODLE_33_STABLE 2017-05-22 15:14:09 +08:00
Jake Dallimore c708549705 Merge branch 'MDL-56617_33-course-cbm-grade-to-pass' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-05-22 14:32:17 +08:00
Jun Pataleta d14281e215 Merge branch 'MDL-58933_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2017-05-22 14:12:57 +08:00
Mark Nelson 19f6ca9457 MDL-58986 mod_quiz: add CSS classes to buttons on comment page 2017-05-22 12:23:04 +08:00
Dan Poltawski 7b4eb6082f MDL-58966 completion: improve dashboard string 2017-05-22 10:48:00 +08:00
Henning Bostelmann 8b8fbc6b84 MDL-57957 mod_assign: show feedback file in absence of grade item 2017-05-22 10:44:18 +08:00
Eloy Lafuente (stronk7) 906b385784 MDL-58933 upgrade: add 3.3.0 separation line to all upgrade scripts 2017-05-19 19:23:55 +02:00
Luca Bösch e13e5a42bc 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:34:21 +02:00
Grzegorz Ziółek 1fcfc991b9 MDL-56973 wiki: New page title readonly after changing course language 2017-05-19 11:11:55 +02:00
Cameron Ball a4eaa35e23 MDL-58994 core_calendar: Coalesce event sort field
There are situations where we need to sort events on a field called
"timesort", but sometimes it is not set. So we can fall back to
"timestart" in this case.
2017-05-19 15:11:32 +08:00
David Monllao df6749b03b weekly release 3.3+ 2017-05-19 13:08:39 +08:00
Andres 6fc4a6c17a MDL-46322 mod_assign: Only list enrolled graders as potential markers 2017-05-18 22:32:59 -05:00
Andres Melo f13c34e4a9 MDL-46322 mod_assign: Only list enrolled graders as potential markers 2017-05-17 16:48:43 -05:00
Mark Nelson 0899f6b9f9 MDL-58776 core_tag: removed whitespace from id attribute
This was preventing the JS from finding the element.
2017-05-17 12:13:54 +01:00
Simey Lameze b68abdc7c2 MDL-58884 core_competency: add exporter required course fields 2017-05-17 15:01:05 +08:00
Jake Dallimore 7e68b9a0af Merge branch 'MDL-58947-m33' of https://github.com/sammarshallou/moodle into MOODLE_33_STABLE 2017-05-17 09:16:01 +08:00
Andrew Nicols 63752139c4 Merge branch 'MDL-58795-moodle33' of https://github.com/jebarviabb/moodle into MOODLE_33_STABLE 2017-05-17 07:00:49 +08:00
Daniel Materka 67803cb430 MDL-49988 wiki: fix broken page layout if html contains line breaks 2017-05-16 19:10:26 +01:00
Ankit Agarwal 54b24b8a24 MDL-58776 tags: Add bootstrap classes to buttons 2017-05-16 17:51:11 +01:00
Iñaki Arenaza 3e97f327cf 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:48:49 +01:00
Jun Pataleta e91ffe1531 Merge branch 'MDL-58811-33-extra-slash' of https://github.com/dmitriim/moodle into MOODLE_33_STABLE 2017-05-16 17:42:55 +08:00
Josh Ebarvia c4d5303ce0 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 18:49:45 +09:30
Jake Dallimore 0712ef7f54 Merge branch 'MDL-58723-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2017-05-16 15:16:34 +08:00
Jun Pataleta ddf6c958f8 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:39 +08:00
Andrew Nicols fbf216799c Merge branch 'MDL-58756_33-statslib-roles-multilang' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2017-05-16 13:52:45 +08:00
Luca Bösch f8b0ee68bf MDL-58756 stats: Use multilang with role . 2017-05-16 07:27:00 +02:00
Dmitrii Metelkin 069683984a MDL-58811 backup: fix an extra slash on restore for the legacy files 2017-05-16 14:34:10 +10:00
Issam Taboubi 7a7dd2ff1f MDL-58884 competency: Inaccurate stats proficient competencies in course 2017-05-16 10:42:39 +08:00
Stephen Vickers 8a0ed98b81 MDL-58770 mod_lti: Strip HTML from parameters
Remove HTML tags from parameters which should be plain text.
2017-05-16 09:58:09 +08:00
sam marshall ce904a961d MDL-58947 Search: Label URLs not correctly calculated 2017-05-15 17:57:58 +01:00
Ankit Agarwal 5ff898804f MDL-58929 converters: Make link title consistent 2017-05-15 12:07:43 +01:00
Dan Poltawski 3bb50a471c Merge branch 'MDL-58936_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2017-05-15 11:45:19 +01:00
Cameron Ball 660182a172 MDL-58496 mod_chat: Update timesort when updating timestart
Previously when a repeating chat was updating the calendar
it would only update the timestart column. It needs to also
update the timesort column to display correctly on the new
overview.
2017-05-15 11:14:50 +01:00
John Okely e8f0664d53 MDL-58916 user_profile: Pass site context when determining menu options 2017-05-15 11:01:34 +01:00
Cameron Ball cb495b995c MDL-58841 mod_assign: Style "view all" link on grading summary 2017-05-15 10:46:25 +01:00
Luca Bösch c37bbda3ef MDL-58852 choice: Use multilang for choice options in charts 2017-05-15 10:23:29 +01:00
Andrew Nicols 81432e74f4 Merge branch 'MDL-58893-33-missing-div' of https://github.com/dmitriim/moodle into MOODLE_33_STABLE 2017-05-15 15:13:04 +08:00
Luca Bösch d231bf1272 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-15 14:44:06 +08:00
Dmitrii Metelkin 1aee3e9394 MDL-58893 portfolio: add missing closing div 2017-05-15 15:56:34 +10:00
Mark Nelson 9362f598dd MDL-58936 core: ensure 'page->context' is not null
When using $page->context it calls magic_get_context() in lib/pagelib.php.
This method sets the context to context_system::instance() if it is currently
null and returns that as the context. However, when installing a new site
context_system::instance() also returns null.
2017-05-15 12:40:29 +08:00
6048 changed files with 96565 additions and 454114 deletions
+3 -8
View File
@@ -3,9 +3,10 @@
*/**/build/
node_modules/
vendor/
admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/amd/src/popper.js
auth/cas/CAS/
auth/fc/fcFPP.php
enrol/lti/ims-blti/
filter/algebra/AlgParser.pm
filter/tex/mimetex.*
@@ -13,7 +14,6 @@ lib/editor/atto/yui/src/rangy/js/*.*
lib/editor/tinymce/plugins/pdw/tinymce/
lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
lib/mlbackend/php/phpml/
lib/adodb/
lib/bennu/
lib/evalmath/
@@ -41,6 +41,7 @@ lib/html2text/
lib/markdown/
lib/recaptchalib.php
lib/xhprof/
lib/xmlize.php
lib/horde/
lib/requirejs/
lib/amd/src/loglevel.js
@@ -57,15 +58,9 @@ lib/maxmind/MaxMind/
lib/ltiprovider/
lib/amd/src/truncate.js
lib/fonts/
lib/amd/src/adapter.js
lib/validateurlsyntax.php
lib/amd/src/popper.js
lib/geopattern-php/
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/videojs/
media/player/videojs/amd/src/videojs-flash-lazy.js
media/player/videojs/videojs/video-js.swf
mod/assign/feedback/editpdf/fpdi/
repository/s3/S3.php
theme/boost/scss/bootstrap/
+2 -36
View File
@@ -1,7 +1,4 @@
{
'plugins': [
'promise',
],
'env': {
'browser': true,
'amd': true
@@ -16,7 +13,6 @@
// === Possible Errors ===
'comma-dangle': 'off',
'no-compare-neg-zero': 'error',
'no-cond-assign': 'error',
'no-console': 'error',
'no-constant-condition': 'error',
@@ -68,6 +64,7 @@
'no-fallthrough': 'error',
'no-floating-decimal': 'warn',
'no-global-assign': 'warn',
// Enabled by grunt for AMD modules: 'no-implicit-globals': 'error',
'no-implied-eval': 'error',
'no-invalid-this': 'error',
'no-iterator': 'error',
@@ -106,7 +103,6 @@
'block-spacing': 'warn',
'brace-style': ['warn', '1tbs'],
'camelcase': 'warn',
'capitalized-comments': ['warn', 'always', { 'ignoreConsecutiveComments': true }],
'comma-spacing': ['warn', { 'before': false, 'after': true }],
'comma-style': ['warn', 'last'],
'computed-property-spacing': 'error',
@@ -174,41 +170,11 @@
'unicode-bom': 'error',
'wrap-regex': 'off',
// === Promises ===
'promise/always-return': 'warn',
'promise/no-return-wrap': 'warn',
'promise/param-names': 'warn',
'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail']}],
'promise/no-native': 'warn',
'promise/no-promise-in-callback': 'warn',
'promise/no-callback-in-promise': 'warn',
'promise/avoid-new': 'warn',
// === Deprecations ===
"no-restricted-properties": ['warn', {
'object': 'M',
'property': 'str',
'message': 'Use AMD module "core/str" or M.util.get_string()'
}],
},
overrides: [
{
files: ["**/yui/src/**/*.js"],
// Disable some rules which we can't safely define for YUI rollups.
rules: {
'no-undef': 'off',
'no-unused-vars': 'off',
'no-unused-expressions': 'off'
}
},
{
files: ["**/amd/src/*.js", "Gruntfile.js"],
// Check AMD with some slightly stricter rules.
rules: {
'no-unused-vars': 'error',
'no-implicit-globals': 'error'
}
}
]
}
}
-1
View File
@@ -1,5 +1,4 @@
**/yui/build/** -diff
**/amd/build/** -diff
lib/dml/oci_native_moodle_package.sql text eol=lf
theme/bootstrapbase/style/editor.css -diff
theme/bootstrapbase/style/moodle.css -diff
+2 -10
View File
@@ -9,18 +9,10 @@
#
# See gitignore(5) man page for more details
#
# Swap files (vim)
[._]*.s[a-v][a-z]
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Temporary files including undo
*~
#
/config.php
/lib/editor/tinymce/extra/tools/temp/
*~
*.swp
/tags
/TAGS
/cscope.*
-2
View File
@@ -1,2 +0,0 @@
**/amd/**
/*.js
-1
View File
@@ -1 +0,0 @@
v8.16.1
+3 -9
View File
@@ -2,12 +2,12 @@
theme/bootstrapbase/style/
theme/clean/style/custom.css
theme/more/style/custom.css
theme/boost/style/moodle.css
node_modules/
vendor/
admin/tool/policy/amd/src/jquery-eu-cookie-law-popup.js
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/amd/src/popper.js
auth/cas/CAS/
auth/fc/fcFPP.php
enrol/lti/ims-blti/
filter/algebra/AlgParser.pm
filter/tex/mimetex.*
@@ -15,7 +15,6 @@ lib/editor/atto/yui/src/rangy/js/*.*
lib/editor/tinymce/plugins/pdw/tinymce/
lib/editor/tinymce/plugins/spellchecker/rpc.php
lib/editor/tinymce/tiny_mce/
lib/mlbackend/php/phpml/
lib/adodb/
lib/bennu/
lib/evalmath/
@@ -43,6 +42,7 @@ lib/html2text/
lib/markdown/
lib/recaptchalib.php
lib/xhprof/
lib/xmlize.php
lib/horde/
lib/requirejs/
lib/amd/src/loglevel.js
@@ -59,15 +59,9 @@ lib/maxmind/MaxMind/
lib/ltiprovider/
lib/amd/src/truncate.js
lib/fonts/
lib/amd/src/adapter.js
lib/validateurlsyntax.php
lib/amd/src/popper.js
lib/geopattern-php/
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/videojs/
media/player/videojs/amd/src/videojs-flash-lazy.js
media/player/videojs/videojs/video-js.swf
mod/assign/feedback/editpdf/fpdi/
repository/s3/S3.php
theme/boost/scss/bootstrap/
+10 -11
View File
@@ -1,22 +1,18 @@
{
"plugins": [
"stylelint-csstree-validator"
],
"rules": {
"csstree/validator": true,
"at-rule-empty-line-before": [ "always",
{"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
{"except": [ "blockless-group"], ignore: ["after-comment", "all-nested"]}
],
"at-rule-name-case": "lower",
"at-rule-name-space-after": "always-single-line",
"at-rule-no-unknown": null, # Enabled for non-scss in grunt.
"at-rule-semicolon-newline-after": "always",
"at-rule-semicolon-space-before": "never",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always",
"block-closing-brace-newline-before": "always-multi-line",
"block-closing-brace-space-before": "always-single-line",
"block-no-empty": true,
"block-opening-brace-newline-after": "always",
"block-no-single-line": true,
"block-opening-brace-newline-after": "always-multi-line",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"color-hex-case": ["lower", { "severity": "warning" }],
@@ -25,6 +21,7 @@
"declaration-bang-space-after": "never",
"declaration-bang-space-before": "always",
"declaration-block-no-duplicate-properties": true,
"declaration-block-no-ignored-properties": true,
"declaration-block-no-shorthand-property-overrides": true,
"declaration-block-semicolon-newline-after": "always-multi-line",
"declaration-block-semicolon-space-after": "always-single-line",
@@ -35,7 +32,6 @@
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"declaration-no-important": true,
"font-family-no-duplicate-names": true,
"function-calc-no-unspaced-operator": true,
"function-comma-newline-after": "always-multi-line",
"function-comma-space-after": "always-single-line",
@@ -45,7 +41,7 @@
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
"function-url-scheme-blacklist": ["data"],
"function-url-data-uris": never,
"function-whitespace-after": "always",
"indentation": 4,
"keyframe-declaration-no-important": true,
@@ -54,12 +50,14 @@
"max-line-length": [132, { "severity": "warning" }],
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-no-missing-punctuation": true,
"media-feature-parentheses-space-inside": "never",
"media-feature-range-operator-space-after": "always",
"media-feature-range-operator-space-before": "always",
"media-query-list-comma-newline-after": "always-multi-line",
"media-query-list-comma-space-after": "always-single-line",
"media-query-list-comma-space-before": "never",
"no-browser-hacks": null, # Enabled for non-scss in grunt.
"no-empty-source": true,
"no-eol-whitespace": true,
"no-extra-semicolons": [true, { "severity": "warning" }],
@@ -80,10 +78,11 @@
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-no-unknown": true,
"selector-root-no-composition": true,
"selector-type-case": "lower",
"selector-type-no-unknown": true,
"string-no-newline": true,
"time-min-milliseconds": 100,
"time-no-imperceptible": true,
"unit-blacklist": ["pt"],
"unit-case": "lower",
"unit-no-unknown": true,
+28 -26
View File
@@ -11,29 +11,26 @@ notifications:
language: php
dist: trusty
php:
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
- 7.2
- 7.0
- 7.1
- 5.6
addons:
postgresql: "9.6"
postgresql: "9.3"
packages:
- mysql-server-5.6
- mysql-client-core-5.6
- mysql-client-5.6
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
# services:
# - redis-server
services:
- redis-server
env:
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
# start first so that the total run time is not too high.
#
# We only run MySQL on PHP 7.2, so run that first.
# We only run MySQL on PHP 7.1, so run that first.
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
# Postgres is significantly is pretty reasonable in its run-time.
@@ -56,16 +53,23 @@ matrix:
fast_finish: true
include:
# Run grunt/npm install on lowest supported npm version
- php: 7.1
env: DB=none TASK=GRUNT NVM_VERSION='4'
# Run grunt/npm install on highest version ('node' is an alias for the latest node.js version.)
- php: 7.2
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
- php: 7.1
env: DB=none TASK=GRUNT NVM_VERSION='node'
exclude:
# MySQL - it's just too slow.
# Exclude it on all versions except for 7.2
# Exclude it on all versions except for 7.1
- env: DB=mysqli TASK=PHPUNIT
php: 7.0
php: 5.6
# Moodle 2.7 is not compatible with PHP 7 for the upgrade test.
- env: DB=pgsql TASK=UPGRADE
php: 7.1
cache:
directories:
@@ -73,6 +77,8 @@ cache:
- $HOME/.npm
install:
- sudo apt-get -y install haveged
- sudo service haveged start
- >
if [ "$DB" = 'mysqli' ];
then
@@ -91,7 +97,7 @@ install:
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.6
sudo service postgresql start 9.3
fi
- >
if [ "$TASK" = 'PHPUNIT' ];
@@ -102,9 +108,8 @@ install:
fi
# Enable Redis.
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
# echo 'extension="redis.so"' > /tmp/redis.ini
# phpenv config-add /tmp/redis.ini
echo 'extension="redis.so"' > /tmp/redis.ini
phpenv config-add /tmp/redis.ini
# Install composer dependencies.
# We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
@@ -175,11 +180,10 @@ before_script:
mkdir -p "$HOME"/roots/phpunit
# The phpunit dataroot and prefix..
# Redis tests are currently failing on php 7.2 due to https://bugs.php.net/bug.php?id=75628
# -e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
sed -i \
-e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
-e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
-e "/require_once/i \\define('TEST_SESSION_REDIS_HOST', '127.0.0.1');" \
config.php ;
# Initialise PHPUnit for Moodle.
@@ -209,7 +213,7 @@ before_script:
# We need the official upstream for comparison
git remote add upstream https://github.com/moodle/moodle.git;
git fetch upstream MOODLE_35_STABLE;
git fetch upstream MOODLE_33_STABLE;
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
export GIT_COMMIT="$TRAVIS_COMMIT";
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
@@ -229,9 +233,9 @@ before_script:
# We need the official upstream.
git remote add upstream https://github.com/moodle/moodle.git;
# Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
git fetch upstream MOODLE_30_STABLE;
git checkout MOODLE_30_STABLE;
# Checkout 27 STABLE branch.
git fetch upstream MOODLE_27_STABLE;
git checkout MOODLE_27_STABLE;
# Perform the upgrade
php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
@@ -250,7 +254,7 @@ script:
- >
if [ "$TASK" = 'PHPUNIT' ];
then
vendor/bin/phpunit --fail-on-risky --disallow-test-output --verbose;
vendor/bin/phpunit;
fi
- >
@@ -265,9 +269,7 @@ script:
grunt ;
# Add all files to the git index and then run diff --cached to see all changes.
# This ensures that we get the status of all files, including new files.
# We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
git add . ;
git reset -- npm-shrinkwrap.json ;
git diff --cached --exit-code ;
fi
+23 -17
View File
@@ -24,7 +24,6 @@
* Grunt configuration
*/
/* eslint-env node */
module.exports = function(grunt) {
var path = require('path'),
tasks = {},
@@ -113,9 +112,26 @@ module.exports = function(grunt) {
// Even though warnings dont stop the build we don't display warnings by default because
// at this moment we've got too many core warnings.
options: {quiet: !grunt.option('show-lint-warnings')},
amd: {src: amdSrc},
amd: {
src: amdSrc,
// Check AMD with some slightly stricter rules.
rules: {
'no-unused-vars': 'error',
'no-implicit-globals': 'error'
}
},
// Check YUI module source files.
yui: {src: ['**/yui/src/**/*.js', '!*/**/yui/src/*/meta/*.js']}
yui: {
src: ['**/yui/src/**/*.js', '!*/**/yui/src/*/meta/*.js'],
options: {
// Disable some rules which we can't safely define for YUI rollups.
rules: {
'no-undef': 'off',
'no-unused-vars': 'off',
'no-unused-expressions': 'off'
}
}
}
},
uglify: {
amd: {
@@ -138,16 +154,6 @@ module.exports = function(grunt) {
}
}
},
sass: {
dist: {
files: {
"theme/boost/style/moodle.css": "theme/boost/scss/preset/default.scss"
}
},
options: {
includePaths: ["theme/boost/scss/"]
}
},
watch: {
options: {
nospawn: true // We need not to spawn so config can be changed dynamically.
@@ -188,6 +194,7 @@ module.exports = function(grunt) {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
"no-browser-hacks": [true, {"severity": "warning"}]
}
}
},
@@ -204,6 +211,7 @@ module.exports = function(grunt) {
rules: {
// These rules have to be disabled in .stylelintrc for scss compat.
"at-rule-no-unknown": true,
"no-browser-hacks": [true, {"severity": "warning"}]
}
}
}
@@ -225,8 +233,7 @@ module.exports = function(grunt) {
'# Generated by "grunt ignorefiles"',
'theme/bootstrapbase/style/',
'theme/clean/style/custom.css',
'theme/more/style/custom.css',
'theme/boost/style/moodle.css'
'theme/more/style/custom.css'
].concat(thirdPartyPaths);
grunt.file.write('.stylelintignore', stylelintIgnores.join('\n'));
};
@@ -374,7 +381,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-stylelint');
@@ -387,7 +393,7 @@ module.exports = function(grunt) {
grunt.registerTask('js', ['amd', 'yui']);
// Register CSS taks.
grunt.registerTask('css', ['stylelint:scss', 'sass', 'stylelint:less', 'less:bootstrapbase', 'stylelint:css']);
grunt.registerTask('css', ['stylelint:scss', 'stylelint:less', 'less:bootstrapbase', 'stylelint:css']);
// Register the startup task.
grunt.registerTask('startup', 'Run the correct tasks for the current directory', tasks.startup);
-6
View File
@@ -165,12 +165,6 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
// If custom field then pick name from database.
$fieldshortname = str_replace('profile_field_', '', $fieldname);
$fieldname = $customfieldname[$fieldshortname]->name;
if (core_text::strlen($fieldshortname) > 67) {
// If custom profile field name is longer than 67 characters we will not be able to store the setting
// such as 'field_updateremote_profile_field_NOTSOSHORTSHORTNAME' in the database because the character
// limit for the setting name is 100.
continue;
}
} elseif ($fieldname == 'url') {
$fieldname = get_string('webpage');
} else {
+9 -13
View File
@@ -54,16 +54,14 @@ $statusmsg = '';
$errormsg = '';
if ($data = data_submitted() and confirm_sesskey()) {
$count = admin_write_settings($data);
if (admin_write_settings($data)) {
$statusmsg = get_string('changessaved');
}
if (empty($adminroot->errors)) {
// No errors. Did we change any setting? If so, then indicate success.
if ($count) {
$statusmsg = get_string('changessaved');
} else {
switch ($return) {
case 'site': redirect("$CFG->wwwroot/");
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
}
switch ($return) {
case 'site': redirect("$CFG->wwwroot/");
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
}
} else {
$errormsg = get_string('errorwithsettings', 'admin');
@@ -75,7 +73,7 @@ if ($data = data_submitted() and confirm_sesskey()) {
if ($PAGE->user_allowed_editing() && $adminediting != -1) {
$USER->editing = $adminediting;
}
$buttons = null;
if ($PAGE->user_allowed_editing()) {
$url = clone($PAGE->url);
if ($PAGE->user_is_editing()) {
@@ -129,9 +127,7 @@ if ($savebutton) {
$visiblepathtosection = array_reverse($settingspage->visiblepath);
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
$PAGE->set_heading($SITE->fullname);
if ($buttons) {
$PAGE->set_button($buttons);
}
$PAGE->set_button($buttons);
echo $OUTPUT->header();
-41
View File
@@ -1,41 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for core_admin.
*
* @package core_admin
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_admin\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for core_admin implementing null_provider.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}
-119
View File
@@ -1,119 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Build and store theme CSS.
*
* @package core
* @subpackage cli
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once("$CFG->libdir/clilib.php");
require_once("$CFG->libdir/csslib.php");
require_once("$CFG->libdir/outputlib.php");
$longparams = [
'themes' => null,
'direction' => null,
'help' => false,
'verbose' => false
];
$shortmappings = [
't' => 'themes',
'd' => 'direction',
'h' => 'help',
'v' => 'verbose'
];
// Get CLI params.
list($options, $unrecognized) = cli_get_params($longparams, $shortmappings);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help']) {
echo
"Compile the CSS for one or more installed themes.
Existing CSS caches will replaced.
By default all themes will be recompiled unless otherwise specified.
Options:
-t, --themes A comma separated list of themes to be compiled
-d, --direction Only compile a single direction (either ltr or rtl)
-v, --verbose Print info comments to stdout
-h, --help Print out this help
Example:
\$ sudo -u www-data /usr/bin/php admin/cli/build_theme_css.php --themes=boost --direction=ltr
";
die;
}
if (empty($options['verbose'])) {
$trace = new null_progress_trace();
} else {
$trace = new text_progress_trace();
}
cli_heading('Build theme css');
// Determine which themes we need to build.
$themenames = [];
if (is_null($options['themes'])) {
$trace->output('No themes specified. Finding all installed themes.');
$themenames = array_keys(core_component::get_plugin_list('theme'));
} else {
if (is_string($options['themes'])) {
$themenames = explode(',', $options['themes']);
} else {
cli_error('--themes must be a comma separated list of theme names');
}
}
$trace->output('Checking that each theme is correctly installed...');
$themeconfigs = [];
foreach ($themenames as $themename) {
if (is_null(theme_get_config_file_path($themename))) {
cli_error("Unable to find theme config for {$themename}");
}
// Load the config for the theme.
$themeconfigs[] = theme_config::load($themename);
}
$directions = ['ltr', 'rtl'];
if (!is_null($options['direction'])) {
if (!in_array($options['direction'], $directions)) {
cli_error("--direction must be either ltr or rtl");
}
$directions = [$options['direction']];
}
$trace->output('Building CSS for themes: ' . implode(', ', $themenames));
theme_build_css_for_themes($themeconfigs, $directions);
exit(0);
-1
View File
@@ -73,7 +73,6 @@ foreach ($rs as $user) {
echo "Redeleting user $user->id: $user->username ($user->email)\n";
delete_user($user);
}
$rs->close();
cli_heading('Deleting all leftovers');
+10 -11
View File
@@ -146,9 +146,14 @@ define('PHPUNIT_TEST', false);
define('IGNORE_COMPONENT_CACHE', true);
// Check that PHP is of a sufficient version as soon as possible.
require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
moodle_require_minimum_php_version();
// Check that PHP is of a sufficient version
if (version_compare(phpversion(), "5.6.5") < 0) {
$phpversion = phpversion();
// do NOT localise - lang strings would not work here and we CAN NOT move it after installib
fwrite(STDERR, "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).\n");
fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
exit(1);
}
// set up configuration
global $CFG;
@@ -219,6 +224,7 @@ $databases = array('mysqli' => moodle_database::get_driver_instance('mysqli', 'n
'pgsql' => moodle_database::get_driver_instance('pgsql', 'native'),
'oci' => moodle_database::get_driver_instance('oci', 'native'),
'sqlsrv' => moodle_database::get_driver_instance('sqlsrv', 'native'), // MS SQL*Server PHP driver
'mssql' => moodle_database::get_driver_instance('mssql', 'native'), // FreeTDS driver
);
foreach ($databases as $type=>$database) {
if ($database->driver_installed() !== true) {
@@ -442,7 +448,6 @@ if ($interactive) {
}
}
$CFG->tempdir = $CFG->dataroot.'/temp';
$CFG->backuptempdir = $CFG->tempdir.'/backup';
$CFG->cachedir = $CFG->dataroot.'/cache';
$CFG->localcachedir = $CFG->dataroot.'/localcache';
@@ -710,7 +715,7 @@ if ($interactive) {
cli_separator();
cli_heading(get_string('cliadminemail', 'install'));
$prompt = get_string('clitypevaluedefault', 'admin', $options['adminemail']);
$options['adminemail'] = cli_input($prompt, $options['adminemail']);
$options['adminemail'] = cli_input($prompt);
}
// Validate that the address provided was an e-mail address.
@@ -803,12 +808,6 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
if (!$options['skip-database']) {
install_cli_database($options, $interactive);
// This needs to happen at the end to ensure it occurs after all caches
// have been purged for the last time.
// This will build a cached version of the current theme for the user
// to immediately start browsing the site.
require_once($CFG->libdir.'/upgradelib.php');
upgrade_themes();
} else {
echo get_string('cliskipdatabase', 'install')."\n";
}
+14 -16
View File
@@ -62,9 +62,14 @@ Example:
\$sudo -u www-data /usr/bin/php admin/cli/install_database.php --lang=cs --adminpass=soMePass123 --agree-license
";
// Check that PHP is of a sufficient version as soon as possible.
require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
moodle_require_minimum_php_version();
// Check that PHP is of a sufficient version
if (version_compare(phpversion(), "5.6.5") < 0) {
$phpversion = phpversion();
// do NOT localise - lang strings would not work here and we CAN NOT move it after installib
fwrite(STDERR, "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).\n");
fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
exit(1);
}
// Nothing to do if config.php does not exist
$configfile = __DIR__.'/../../config.php';
@@ -82,6 +87,11 @@ require_once($CFG->libdir.'/installlib.php');
require_once($CFG->libdir.'/adminlib.php');
require_once($CFG->libdir.'/componentlib.class.php');
// make sure no tables are installed yet
if ($DB->get_tables() ) {
cli_error(get_string('clitablesexist', 'install'));
}
$CFG->early_install_lang = true;
get_string_manager(true);
@@ -104,17 +114,12 @@ list($options, $unrecognized) = cli_get_params(
)
);
// We show help text even if tables are installed.
if ($options['help']) {
echo $help;
die;
}
// Make sure no tables are installed yet.
if ($DB->get_tables() ) {
cli_error(get_string('clitablesexist', 'install'));
}
if (!$options['agree-license']) {
cli_error('You have to agree to the license. --help prints out the help'); // TODO: localize
}
@@ -178,12 +183,5 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
install_cli_database($options, true);
// This needs to happen at the end to ensure it occurs after all caches
// have been purged for the last time.
// This will build a cached version of the current theme for the user
// to immediately start browsing the site.
require_once($CFG->libdir.'/upgradelib.php');
upgrade_themes();
echo get_string('cliinstallfinished', 'install')."\n";
exit(0); // 0 means success
-55
View File
@@ -1,55 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* CLI script to kill all user sessions without asking for confirmation.
*
* @package core
* @subpackage cli
* @copyright 2017 Alexander Bias <alexander.bias@uni-ulm.de>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once($CFG->libdir.'/clilib.php');
list($options, $unrecognized) = cli_get_params(array('help' => false), array('h' => 'help'));
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized), 2);
}
if ($options['help']) {
$help =
"Kill all Moodle sessions
Options:
-h, --help Print out this help
Example:
\$sudo -u www-data /usr/bin/php admin/cli/kill_all_sessions.php
";
echo $help;
exit(0);
}
\core\session\manager::kill_all_sessions();
exit(0);
+1 -1
View File
@@ -203,7 +203,7 @@ if (!empty($options['collation'])) {
$DB->change_database_structure($sql);
} else {
echo "ERROR (unknown column type: $column->type)\n";
$errors++;
$error++;
continue;
}
echo "CONVERTED\n";
+1 -3
View File
@@ -15,8 +15,6 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* CLI script to purge caches without asking for confirmation.
*
* @package core
* @subpackage cli
* @copyright 2011 David Mudrak <david@moodle.com>
@@ -52,4 +50,4 @@ Example:
purge_all_caches();
exit(0);
exit(0);
+4 -11
View File
@@ -131,11 +131,10 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
cli_error(get_string('pluginschecktodo', 'admin'));
}
$a = new stdClass();
$a->oldversion = $oldversion;
$a->newversion = $newversion;
if ($interactive) {
$a = new stdClass();
$a->oldversion = $oldversion;
$a->newversion = $newversion;
echo cli_heading(get_string('databasechecking', '', $a)) . PHP_EOL;
}
@@ -188,11 +187,5 @@ upgrade_noncore(true);
admin_apply_default_settings(NULL, false);
admin_apply_default_settings(NULL, false);
// This needs to happen at the end to ensure it occurs after all caches
// have been purged for the last time.
// This will build a cached version of the current theme for the user
// to immediately start browsing the site.
upgrade_themes();
echo get_string('cliupgradefinished', 'admin', $a)."\n";
echo get_string('cliupgradefinished', 'admin')."\n";
exit(0); // 0 means success
-901
View File
@@ -1754,7 +1754,6 @@
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="5.6.5" level="required">
<RESTRICT function="restrict_php_version_72" message="unsupportedphpversion72" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -1920,7 +1919,6 @@
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="5.6.5" level="required">
<RESTRICT function="restrict_php_version_72" message="unsupportedphpversion72" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -2083,903 +2081,4 @@
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.4" requires="3.0">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.5.31" />
<VENDOR name="postgres" version="9.3" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="7.0.0" level="required">
<RESTRICT function="restrict_php_version_73" message="unsupportedphpversion73" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.5" requires="3.1">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.5.31" />
<VENDOR name="postgres" version="9.3" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="10.2" />
</DATABASE>
<PHP version="7.0.0" level="required">
<RESTRICT function="restrict_php_version_73" message="unsupportedphpversion73" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.6" requires="3.1">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.6" />
<VENDOR name="postgres" version="9.4" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.0.0" level="required">
<RESTRICT function="restrict_php_version_74" message="unsupportedphpversion74" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
<FEEDBACK>
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.7" requires="3.2">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.6" />
<VENDOR name="postgres" version="9.4" />
<VENDOR name="mssql" version="10.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.1.0" level="required">
<RESTRICT function="restrict_php_version_74" message="unsupportedphpversion74" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
<FEEDBACK>
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
<MOODLE version="3.8" requires="3.2">
<UNICODE level="required">
<FEEDBACK>
<ON_ERROR message="unicoderequired" />
</FEEDBACK>
</UNICODE>
<DATABASE level="required">
<VENDOR name="mariadb" version="5.5.31" />
<VENDOR name="mysql" version="5.6" />
<VENDOR name="postgres" version="9.4" />
<VENDOR name="mssql" version="11.0" />
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.1.0" level="required">
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
<ON_CHECK message="pcreunicodewarning" />
</FEEDBACK>
</PCREUNICODE>
<PHP_EXTENSIONS>
<PHP_EXTENSION name="iconv" level="required">
<FEEDBACK>
<ON_ERROR message="iconvrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="mbstring" level="optional">
<FEEDBACK>
<ON_CHECK message="mbstringrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="curl" level="required">
<FEEDBACK>
<ON_ERROR message="curlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="openssl" level="required">
<FEEDBACK>
<ON_ERROR message="opensslrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="tokenizer" level="optional">
<FEEDBACK>
<ON_CHECK message="tokenizerrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlrpc" level="optional">
<FEEDBACK>
<ON_CHECK message="xmlrpcrecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="soap" level="optional">
<FEEDBACK>
<ON_CHECK message="soaprecommended" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="ctype" level="required">
<FEEDBACK>
<ON_ERROR message="ctyperequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zip" level="required">
<FEEDBACK>
<ON_ERROR message="ziprequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="zlib" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="gd" level="required">
<FEEDBACK>
<ON_ERROR message="gdrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="simplexml" level="required">
<FEEDBACK>
<ON_ERROR message="simplexmlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="spl" level="required">
<FEEDBACK>
<ON_ERROR message="splrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="pcre" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="dom" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xml" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="xmlreader" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="intl" level="required">
<FEEDBACK>
<ON_ERROR message="intlrequired" />
</FEEDBACK>
</PHP_EXTENSION>
<PHP_EXTENSION name="json" level="required">
</PHP_EXTENSION>
<PHP_EXTENSION name="hash" level="required"/>
<PHP_EXTENSION name="fileinfo" level="required"/>
</PHP_EXTENSIONS>
<PHP_SETTINGS>
<PHP_SETTING name="memory_limit" value="96M" level="required">
<FEEDBACK>
<ON_ERROR message="settingmemorylimit" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="file_uploads" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="settingfileuploads" />
</FEEDBACK>
</PHP_SETTING>
<PHP_SETTING name="opcache.enable" value="1" level="optional">
<FEEDBACK>
<ON_CHECK message="opcacherecommended" />
</FEEDBACK>
</PHP_SETTING>
</PHP_SETTINGS>
<CUSTOM_CHECKS>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbstorageengine" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
<FEEDBACK>
<ON_ERROR message="quizattemptsupgradedmessage" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
<FEEDBACK>
<ON_CHECK message="slashargumentswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
<FEEDBACK>
<ON_CHECK message="unsupporteddbtablerowformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
<FEEDBACK>
<ON_CHECK message="unoconvwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
<FEEDBACK>
<ON_CHECK message="libcurlwarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfileformat" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddbfilepertable" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
<FEEDBACK>
<ON_ERROR message="unsupporteddblargeprefix" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
<FEEDBACK>
<ON_CHECK message="ishttpswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
<FEEDBACK>
<ON_CHECK message="incompleteunicodesupport" />
</FEEDBACK>
</CUSTOM_CHECK>
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="optional">
<FEEDBACK>
<ON_CHECK message="sixtyfourbitswarning" />
</FEEDBACK>
</CUSTOM_CHECK>
</CUSTOM_CHECKS>
</MOODLE>
</COMPATIBILITY_MATRIX>
+10 -21
View File
@@ -29,9 +29,14 @@ if (!file_exists('../config.php')) {
die();
}
// Check that PHP is of a sufficient version as soon as possible.
require_once(__DIR__.'/../lib/phpminimumversionlib.php');
moodle_require_minimum_php_version();
// Check that PHP is of a sufficient version as soon as possible
if (version_compare(phpversion(), '5.6.5') < 0) {
$phpversion = phpversion();
// do NOT localise - lang strings would not work here and we CAN NOT move it to later place
echo "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).<br />";
echo "Please upgrade your server software or install older Moodle version.";
die();
}
// make sure iconv is available and actually works
if (!function_exists('iconv')) {
@@ -699,7 +704,6 @@ if (!$cache and moodle_needs_upgrading()) {
if (during_initial_install()) {
set_config('rolesactive', 1); // after this, during_initial_install will return false.
set_config('adminsetuppending', 1);
set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
// we need this redirect to setup proper session
upgrade_finished("index.php?sessionstarted=1&amp;lang=$CFG->lang");
}
@@ -815,9 +819,6 @@ if (isset($SESSION->pluginuninstallreturn)) {
}
}
// If site registration needs updating, redirect.
\core\hub\registration::registration_reminder('/admin/index.php');
// Everything should now be set up, and the user is an admin
// Print default admin page with notifications.
@@ -861,23 +862,12 @@ if ($updateschecker->enabled()) {
$buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
//check if the site is registered on Moodle.org
$registered = \core\hub\registration::is_registered();
$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
// Check if there are any cache warnings.
$cachewarnings = cache_helper::warnings();
// Check if there are events 1 API handlers.
$eventshandlers = $DB->get_records_sql('SELECT DISTINCT component FROM {events_handlers}');
$themedesignermode = !empty($CFG->themedesignermode);
$mobileconfigured = !empty($CFG->enablemobilewebservice);
$invalidforgottenpasswordurl = !empty($CFG->forgottenpasswordurl) && empty(clean_param($CFG->forgottenpasswordurl, PARAM_URL));
// Check if a directory with development libraries exists.
if (empty($CFG->disabledevlibdirscheck) && (is_dir($CFG->dirroot.'/vendor') || is_dir($CFG->dirroot.'/node_modules'))) {
$devlibdir = true;
} else {
$devlibdir = false;
}
// Check if the site is being foced onto ssl.
$overridetossl = !empty($CFG->overridetossl);
admin_externalpage_setup('adminnotifications');
@@ -885,5 +875,4 @@ $output = $PAGE->get_renderer('core', 'admin');
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
$maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
$registered, $cachewarnings, $eventshandlers, $themedesignermode, $devlibdir,
$mobileconfigured, $overridetossl, $invalidforgottenpasswordurl);
$registered, $cachewarnings, $eventshandlers, $themedesignermode);
+4 -3
View File
@@ -29,10 +29,9 @@ require_once($CFG->libdir.'/adminlib.php');
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$returnurl = optional_param('returnurl', null, PARAM_LOCALURL);
admin_externalpage_setup('purgecaches');
// If we have got here as a confirmed aciton, do it.
if ($confirm && confirm_sesskey()) {
if ($confirm && isloggedin() && confirm_sesskey()) {
require_capability('moodle/site:config', context_system::instance());
// Valid request. Purge, and redirect the user back to where they came from.
purge_all_caches();
@@ -46,6 +45,8 @@ if ($confirm && confirm_sesskey()) {
}
// Otherwise, show a button to actually purge the caches.
admin_externalpage_setup('purgecaches');
$actionurl = new moodle_url('/admin/purgecaches.php', array('sesskey'=>sesskey(), 'confirm'=>1));
if ($returnurl) {
$actionurl->param('returnurl', $returnurl);
+32 -27
View File
@@ -20,7 +20,7 @@
// //
///////////////////////////////////////////////////////////////////////////
/**
/*
* @package moodle
* @subpackage registration
* @author Jerome Mouneyrac <jerome@mouneyrac.com>
@@ -36,6 +36,7 @@
require('../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
$newtoken = optional_param('newtoken', '', PARAM_ALPHANUM);
$url = optional_param('url', '', PARAM_URL);
@@ -43,19 +44,7 @@ $hubname = optional_param('hubname', '', PARAM_TEXT);
$token = optional_param('token', '', PARAM_TEXT);
$error = optional_param('error', '', PARAM_ALPHANUM);
admin_externalpage_setup('registrationmoodleorg');
if ($url !== HUB_MOODLEORGHUBURL) {
// Allow other plugins to confirm registration on hubs other than moodle.net . Plugins implementing this
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
$callbacks = get_plugins_with_function('hub_registration');
foreach ($callbacks as $plugintype => $plugins) {
foreach ($plugins as $plugin => $callback) {
$callback('confirm');
}
}
throw new moodle_exception('errorotherhubsnotsupported', 'hub');
}
admin_externalpage_setup('registrationhubs');
if (!empty($error) and $error == 'urlalreadyexist') {
throw new moodle_exception('urlalreadyregistered', 'hub',
@@ -63,22 +52,38 @@ if (!empty($error) and $error == 'urlalreadyexist') {
}
//check that we are waiting a confirmation from this hub, and check that the token is correct
core\hub\registration::confirm_registration($token, $newtoken, $hubname);
$registrationmanager = new registration_manager();
$registeredhub = $registrationmanager->get_unconfirmedhub($url);
if (!empty($registeredhub) and $registeredhub->token == $token) {
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('registrationconfirmed', 'hub'), 3, 'main');
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('registrationconfirmed', 'hub'), 3, 'main');
// Display notification message.
echo $OUTPUT->notification(get_string('registrationconfirmedon', 'hub'), 'notifysuccess');
$registeredhub->token = $newtoken;
$registeredhub->confirmed = 1;
$registeredhub->hubname = $hubname;
$registrationmanager->update_registeredhub($registeredhub);
// Display continue button.
$returnurl = !empty($SESSION->registrationredirect) ? clean_param($SESSION->registrationredirect, PARAM_LOCALURL) : null;
unset($SESSION->registrationredirect);
$continueurl = new moodle_url($returnurl ?: '/admin/registration/index.php');
$continuebutton = $OUTPUT->render(new single_button($continueurl, get_string('continue')));
$continuebutton = html_writer::tag('div', $continuebutton, array('class' => 'mdl-align'));
echo $continuebutton;
// Display notification message.
echo $OUTPUT->notification(get_string('registrationconfirmedon', 'hub'), 'notifysuccess');
echo $OUTPUT->footer();
//display continue button
$registrationpage = new moodle_url('/admin/registration/index.php');
$continuebutton = $OUTPUT->render(new single_button($registrationpage, get_string('continue', 'hub')));
$continuebutton = html_writer::tag('div', $continuebutton, array('class' => 'mdl-align'));
echo $continuebutton;
if (!extension_loaded('xmlrpc')) {
//display notice about xmlrpc
$xmlrpcnotification = $OUTPUT->doc_link('admin/environment/php_extension/xmlrpc', '');
$xmlrpcnotification .= get_string('xmlrpcdisabledregistration', 'hub');
echo $OUTPUT->notification($xmlrpcnotification);
}
echo $OUTPUT->footer();
} else {
throw new moodle_exception('wrongtoken', 'hub',
$CFG->wwwroot . '/' . $CFG->admin . '/registration/index.php');
}
+479 -4
View File
@@ -20,7 +20,7 @@
// //
///////////////////////////////////////////////////////////////////////////
/**
/*
* @package moodle
* @subpackage registration
* @author Jerome Mouneyrac <jerome@mouneyrac.com>
@@ -30,7 +30,482 @@
* The forms needed by registration pages.
*/
defined('MOODLE_INTERNAL') || die();
debugging('Support for alternative hubs has been removed from Moodle in 3.4. For communication with moodle.net ' .
'see lib/classes/hub/ .', DEBUG_DEVELOPER);
require_once($CFG->libdir . '/formslib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
/**
* This form display a unregistration form.
*/
class site_unregistration_form extends moodleform {
public function definition() {
$mform = & $this->_form;
$mform->addElement('header', 'site', get_string('unregister', 'hub'));
$huburl = $this->_customdata['huburl'];
$hubname = $this->_customdata['hubname'];
$unregisterlabel = get_string('unregister', 'hub');
$mform->addElement('checkbox', 'unpublishalladvertisedcourses', '',
' ' . get_string('unpublishalladvertisedcourses', 'hub'));
$mform->setType('unpublishalladvertisedcourses', PARAM_INT);
$mform->addElement('checkbox', 'unpublishalluploadedcourses', '',
' ' . get_string('unpublishalluploadedcourses', 'hub'));
$mform->setType('unpublishalluploadedcourses', PARAM_INT);
$mform->addElement('hidden', 'confirm', 1);
$mform->setType('confirm', PARAM_INT);
$mform->addElement('hidden', 'unregistration', 1);
$mform->setType('unregistration', PARAM_INT);
$mform->addElement('hidden', 'huburl', $huburl);
$mform->setType('huburl', PARAM_URL);
$mform->addElement('hidden', 'hubname', $hubname);
$mform->setType('hubname', PARAM_TEXT);
$this->add_action_buttons(true, $unregisterlabel);
}
}
/**
* This form display a clean registration data form.
*/
class site_clean_registration_data_form extends moodleform {
public function definition() {
$mform = & $this->_form;
$mform->addElement('header', 'site', get_string('unregister', 'hub'));
$huburl = $this->_customdata['huburl'];
$hubname = $this->_customdata['hubname'];
$unregisterlabel = get_string('forceunregister', 'hub');
$mform->addElement('static', '', get_string('warning', 'hub'), get_string('forceunregisterconfirmation', 'hub', $hubname));
$mform->addElement('hidden', 'confirm', 1);
$mform->setType('confirm', PARAM_INT);
$mform->addElement('hidden', 'unregistration', 1);
$mform->setType('unregistration', PARAM_INT);
$mform->addElement('hidden', 'cleanregdata', 1);
$mform->setType('cleanregdata', PARAM_INT);
$mform->addElement('hidden', 'huburl', $huburl);
$mform->setType('huburl', PARAM_URL);
$mform->addElement('hidden', 'hubname', $hubname);
$mform->setType('hubname', PARAM_TEXT);
$this->add_action_buttons(true, $unregisterlabel);
}
}
/**
* This form display a hub selector.
* The hub list is retrieved from Moodle.org hub directory.
* Also displayed, a text field to enter private hub url + its password
*/
class hub_selector_form extends moodleform {
public function definition() {
global $CFG, $OUTPUT;
$mform = & $this->_form;
$mform->addElement('header', 'site', get_string('selecthub', 'hub'));
//retrieve the hub list on the hub directory by web service
$function = 'hubdirectory_get_hubs';
$params = array();
$serverurl = HUB_HUBDIRECTORYURL . "/local/hubdirectory/webservice/webservices.php";
require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
$xmlrpcclient = new webservice_xmlrpc_client($serverurl, 'publichubdirectory');
try {
$hubs = $xmlrpcclient->call($function, $params);
} catch (Exception $e) {
$error = $OUTPUT->notification(get_string('errorhublisting', 'hub', $e->getMessage()));
$mform->addElement('static', 'errorhub', '', $error);
$hubs = array();
}
//remove moodle.org from the hub list
foreach ($hubs as $key => $hub) {
if ($hub['url'] == HUB_MOODLEORGHUBURL) {
unset($hubs[$key]);
}
}
//Public hub list
$options = array();
foreach ($hubs as $hub) {
//to not display a name longer than 100 character (too big)
if (core_text::strlen($hub['name']) > 100) {
$hubname = core_text::substr($hub['name'], 0, 100);
$hubname = $hubname . "...";
} else {
$hubname = $hub['name'];
}
$options[$hub['url']] = $hubname;
$mform->addElement('hidden', clean_param($hub['url'], PARAM_ALPHANUMEXT), $hubname);
$mform->setType(clean_param($hub['url'], PARAM_ALPHANUMEXT), PARAM_ALPHANUMEXT);
}
if (!empty($hubs)) {
$mform->addElement('select', 'publichub', get_string('publichub', 'hub'),
$options, array("size" => 15));
$mform->setType('publichub', PARAM_URL);
}
$mform->addElement('static', 'or', '', get_string('orenterprivatehub', 'hub'));
//Private hub
$mform->addElement('text', 'unlistedurl', get_string('privatehuburl', 'hub'),
array('class' => 'registration_textfield'));
$mform->setType('unlistedurl', PARAM_URL);
$mform->addElement('text', 'password', get_string('password'),
array('class' => 'registration_textfield'));
$mform->setType('password', PARAM_RAW);
$this->add_action_buttons(false, get_string('selecthub', 'hub'));
}
/**
* Check the unlisted URL is a URL
*/
function validation($data, $files) {
global $CFG;
$errors = parent::validation($data, $files);
$unlistedurl = $this->_form->_submitValues['unlistedurl'];
if (empty($unlistedurl)) {
$errors['unlistedurl'] = get_string('badurlformat', 'hub');
}
return $errors;
}
}
/**
* The site registration form. Information will be sent to a given hub.
*/
class site_registration_form extends moodleform {
public function definition() {
global $CFG, $DB;
$strrequired = get_string('required');
$mform = & $this->_form;
$huburl = $this->_customdata['huburl'];
$hubname = $this->_customdata['hubname'];
$password = $this->_customdata['password'];
$admin = get_admin();
$site = get_site();
//retrieve config for this hub and set default if they don't exist
$cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
$sitename = get_config('hub', 'site_name_' . $cleanhuburl);
if ($sitename === false) {
$sitename = format_string($site->fullname, true, array('context' => context_course::instance(SITEID)));
}
$sitedescription = get_config('hub', 'site_description_' . $cleanhuburl);
if ($sitedescription === false) {
$sitedescription = $site->summary;
}
$contactname = get_config('hub', 'site_contactname_' . $cleanhuburl);
if ($contactname === false) {
$contactname = fullname($admin, true);
}
$contactemail = get_config('hub', 'site_contactemail_' . $cleanhuburl);
if ($contactemail === false) {
$contactemail = $admin->email;
}
$contactphone = get_config('hub', 'site_contactphone_' . $cleanhuburl);
if ($contactphone === false) {
$contactphone = $admin->phone1;
}
$imageurl = get_config('hub', 'site_imageurl_' . $cleanhuburl);
$privacy = get_config('hub', 'site_privacy_' . $cleanhuburl);
$address = get_config('hub', 'site_address_' . $cleanhuburl);
$region = get_config('hub', 'site_region_' . $cleanhuburl);
$country = get_config('hub', 'site_country_' . $cleanhuburl);
if ($country === false) {
$country = $admin->country;
}
$language = get_config('hub', 'site_language_' . $cleanhuburl);
if ($language === false) {
$language = explode('_', current_language())[0];
}
$geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
$contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
$emailalert = get_config('hub', 'site_emailalert_' . $cleanhuburl);
$emailalert = ($emailalert === 0) ? 0 : 1;
$coursesnumber = get_config('hub', 'site_coursesnumber_' . $cleanhuburl);
$usersnumber = get_config('hub', 'site_usersnumber_' . $cleanhuburl);
$roleassignmentsnumber = get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl);
$postsnumber = get_config('hub', 'site_postsnumber_' . $cleanhuburl);
$questionsnumber = get_config('hub', 'site_questionsnumber_' . $cleanhuburl);
$resourcesnumber = get_config('hub', 'site_resourcesnumber_' . $cleanhuburl);
$badgesnumber = get_config('hub', 'site_badges_' . $cleanhuburl);
$issuedbadgesnumber = get_config('hub', 'site_issuedbadges_' . $cleanhuburl);
$mediancoursesize = get_config('hub', 'site_mediancoursesize_' . $cleanhuburl);
$participantnumberaveragecfg = get_config('hub', 'site_participantnumberaverage_' . $cleanhuburl);
$modulenumberaveragecfg = get_config('hub', 'site_modulenumberaverage_' . $cleanhuburl);
//hidden parameters
$mform->addElement('hidden', 'huburl', $huburl);
$mform->setType('huburl', PARAM_URL);
$mform->addElement('hidden', 'hubname', $hubname);
$mform->setType('hubname', PARAM_TEXT);
$mform->addElement('hidden', 'password', $password);
$mform->setType('password', PARAM_RAW);
//the input parameters
$mform->addElement('header', 'moodle', get_string('registrationinfo', 'hub'));
$mform->addElement('text', 'name', get_string('sitename', 'hub'),
array('class' => 'registration_textfield'));
$mform->addRule('name', $strrequired, 'required', null, 'client');
$mform->setType('name', PARAM_TEXT);
$mform->setDefault('name', $sitename);
$mform->addHelpButton('name', 'sitename', 'hub');
$options = array();
$registrationmanager = new registration_manager();
$options[HUB_SITENOTPUBLISHED] = $registrationmanager->get_site_privacy_string(HUB_SITENOTPUBLISHED);
$options[HUB_SITENAMEPUBLISHED] = $registrationmanager->get_site_privacy_string(HUB_SITENAMEPUBLISHED);
$options[HUB_SITELINKPUBLISHED] = $registrationmanager->get_site_privacy_string(HUB_SITELINKPUBLISHED);
$mform->addElement('select', 'privacy', get_string('siteprivacy', 'hub'), $options);
$mform->setDefault('privacy', $privacy);
$mform->setType('privacy', PARAM_ALPHA);
$mform->addHelpButton('privacy', 'privacy', 'hub');
unset($options);
$mform->addElement('textarea', 'description', get_string('sitedesc', 'hub'),
array('rows' => 8, 'cols' => 41));
$mform->addRule('description', $strrequired, 'required', null, 'client');
$mform->setDefault('description', $sitedescription);
$mform->setType('description', PARAM_TEXT);
$mform->addHelpButton('description', 'sitedesc', 'hub');
$languages = get_string_manager()->get_list_of_languages();
core_collator::asort($languages);
$mform->addElement('select', 'language', get_string('sitelang', 'hub'),
$languages);
$mform->setType('language', PARAM_ALPHANUMEXT);
$mform->addHelpButton('language', 'sitelang', 'hub');
$mform->setDefault('language', $language);
$mform->addElement('textarea', 'address', get_string('postaladdress', 'hub'),
array('rows' => 4, 'cols' => 41));
$mform->setType('address', PARAM_TEXT);
$mform->setDefault('address', $address);
$mform->addHelpButton('address', 'postaladdress', 'hub');
//TODO: use the region array I generated
// $mform->addElement('select', 'region', get_string('selectaregion'), array('-' => '-'));
// $mform->setDefault('region', $region);
$mform->addElement('hidden', 'regioncode', '-');
$mform->setType('regioncode', PARAM_ALPHANUMEXT);
$countries = get_string_manager()->get_list_of_countries();
$mform->addElement('select', 'countrycode', get_string('sitecountry', 'hub'), $countries);
$mform->setDefault('countrycode', $country);
$mform->setType('countrycode', PARAM_ALPHANUMEXT);
$mform->addHelpButton('countrycode', 'sitecountry', 'hub');
$mform->addElement('text', 'geolocation', get_string('sitegeolocation', 'hub'),
array('class' => 'registration_textfield'));
$mform->setDefault('geolocation', $geolocation);
$mform->setType('geolocation', PARAM_RAW);
$mform->addHelpButton('geolocation', 'sitegeolocation', 'hub');
$mform->addElement('text', 'contactname', get_string('siteadmin', 'hub'),
array('class' => 'registration_textfield'));
$mform->addRule('contactname', $strrequired, 'required', null, 'client');
$mform->setType('contactname', PARAM_TEXT);
$mform->setDefault('contactname', $contactname);
$mform->addHelpButton('contactname', 'siteadmin', 'hub');
$mform->addElement('text', 'contactphone', get_string('sitephone', 'hub'),
array('class' => 'registration_textfield'));
$mform->setType('contactphone', PARAM_TEXT);
$mform->addHelpButton('contactphone', 'sitephone', 'hub');
$mform->setForceLtr('contactphone');
$mform->addElement('text', 'contactemail', get_string('siteemail', 'hub'),
array('class' => 'registration_textfield'));
$mform->addRule('contactemail', $strrequired, 'required', null, 'client');
$mform->setType('contactemail', PARAM_EMAIL);
$mform->setDefault('contactemail', $contactemail);
$mform->addHelpButton('contactemail', 'siteemail', 'hub');
$options = array();
$options[0] = get_string("registrationcontactno");
$options[1] = get_string("registrationcontactyes");
$mform->addElement('select', 'contactable', get_string('siteregistrationcontact', 'hub'), $options);
$mform->setDefault('contactable', $contactable);
$mform->setType('contactable', PARAM_INT);
$mform->addHelpButton('contactable', 'siteregistrationcontact', 'hub');
unset($options);
$options = array();
$options[0] = get_string("registrationno");
$options[1] = get_string("registrationyes");
$mform->addElement('select', 'emailalert', get_string('siteregistrationemail', 'hub'), $options);
$mform->setDefault('emailalert', $emailalert);
$mform->setType('emailalert', PARAM_INT);
$mform->addHelpButton('emailalert', 'siteregistrationemail', 'hub');
unset($options);
//TODO site logo
$mform->addElement('hidden', 'imageurl', ''); //TODO: temporary
$mform->setType('imageurl', PARAM_URL);
$mform->addElement('static', 'urlstring', get_string('siteurl', 'hub'), $CFG->wwwroot);
$mform->addHelpButton('urlstring', 'siteurl', 'hub');
$mform->addElement('static', 'versionstring', get_string('siteversion', 'hub'), $CFG->version);
$mform->addElement('hidden', 'moodleversion', $CFG->version);
$mform->setType('moodleversion', PARAM_INT);
$mform->addHelpButton('versionstring', 'siteversion', 'hub');
$mform->addElement('static', 'releasestring', get_string('siterelease', 'hub'), $CFG->release);
$mform->addElement('hidden', 'moodlerelease', $CFG->release);
$mform->setType('moodlerelease', PARAM_TEXT);
$mform->addHelpButton('releasestring', 'siterelease', 'hub');
/// Display statistic that are going to be retrieve by the hub
$coursecount = $DB->count_records('course') - 1;
$usercount = $DB->count_records('user', array('deleted' => 0));
$roleassigncount = $DB->count_records('role_assignments');
$postcount = $DB->count_records('forum_posts');
$questioncount = $DB->count_records('question');
$resourcecount = $DB->count_records('resource');
require_once($CFG->dirroot . "/course/lib.php");
$participantnumberaverage = number_format(average_number_of_participants(), 2);
$modulenumberaverage = number_format(average_number_of_courses_modules(), 2);
require_once($CFG->libdir . '/badgeslib.php');
$badges = $DB->count_records_select('badge', 'status <> ' . BADGE_STATUS_ARCHIVED);
$issuedbadges = $DB->count_records('badge_issued');
if (HUB_MOODLEORGHUBURL != $huburl) {
$mform->addElement('checkbox', 'courses', get_string('sendfollowinginfo', 'hub'),
" " . get_string('coursesnumber', 'hub', $coursecount));
$mform->setDefault('courses', $coursesnumber != -1);
$mform->setType('courses', PARAM_INT);
$mform->addHelpButton('courses', 'sendfollowinginfo', 'hub');
$mform->addElement('checkbox', 'users', '',
" " . get_string('usersnumber', 'hub', $usercount));
$mform->setDefault('users', $usersnumber != -1);
$mform->setType('users', PARAM_INT);
$mform->addElement('checkbox', 'roleassignments', '',
" " . get_string('roleassignmentsnumber', 'hub', $roleassigncount));
$mform->setDefault('roleassignments', $roleassignmentsnumber != -1);
$mform->setType('roleassignments', PARAM_INT);
$mform->addElement('checkbox', 'posts', '',
" " . get_string('postsnumber', 'hub', $postcount));
$mform->setDefault('posts', $postsnumber != -1);
$mform->setType('posts', PARAM_INT);
$mform->addElement('checkbox', 'questions', '',
" " . get_string('questionsnumber', 'hub', $questioncount));
$mform->setDefault('questions', $questionsnumber != -1);
$mform->setType('questions', PARAM_INT);
$mform->addElement('checkbox', 'resources', '',
" " . get_string('resourcesnumber', 'hub', $resourcecount));
$mform->setDefault('resources', $resourcesnumber != -1);
$mform->setType('resources', PARAM_INT);
$mform->addElement('checkbox', 'badges', '',
" " . get_string('badgesnumber', 'hub', $badges));
$mform->setDefault('badges', $badgesnumber != -1);
$mform->setType('badges', PARAM_INT);
$mform->addElement('checkbox', 'issuedbadges', '',
" " . get_string('issuedbadgesnumber', 'hub', $issuedbadges));
$mform->setDefault('issuedbadges', $issuedbadgesnumber != -1);
$mform->setType('issuedbadges', PARAM_INT);
$mform->addElement('checkbox', 'participantnumberaverage', '',
" " . get_string('participantnumberaverage', 'hub', $participantnumberaverage));
$mform->setDefault('participantnumberaverage', $participantnumberaveragecfg != -1);
$mform->setType('participantnumberaverage', PARAM_FLOAT);
$mform->addElement('checkbox', 'modulenumberaverage', '',
" " . get_string('modulenumberaverage', 'hub', $modulenumberaverage));
$mform->setDefault('modulenumberaverage', $modulenumberaveragecfg != -1);
$mform->setType('modulenumberaverage', PARAM_FLOAT);
} else {
$mform->addElement('static', 'courseslabel', get_string('sendfollowinginfo', 'hub'),
" " . get_string('coursesnumber', 'hub', $coursecount));
$mform->addElement('hidden', 'courses', 1);
$mform->setType('courses', PARAM_INT);
$mform->addHelpButton('courseslabel', 'sendfollowinginfo', 'hub');
$mform->addElement('static', 'userslabel', '',
" " . get_string('usersnumber', 'hub', $usercount));
$mform->addElement('hidden', 'users', 1);
$mform->setType('users', PARAM_INT);
$mform->addElement('static', 'roleassignmentslabel', '',
" " . get_string('roleassignmentsnumber', 'hub', $roleassigncount));
$mform->addElement('hidden', 'roleassignments', 1);
$mform->setType('roleassignments', PARAM_INT);
$mform->addElement('static', 'postslabel', '',
" " . get_string('postsnumber', 'hub', $postcount));
$mform->addElement('hidden', 'posts', 1);
$mform->setType('posts', PARAM_INT);
$mform->addElement('static', 'questionslabel', '',
" " . get_string('questionsnumber', 'hub', $questioncount));
$mform->addElement('hidden', 'questions', 1);
$mform->setType('questions', PARAM_INT);
$mform->addElement('static', 'resourceslabel', '',
" " . get_string('resourcesnumber', 'hub', $resourcecount));
$mform->addElement('hidden', 'resources', 1);
$mform->setType('resources', PARAM_INT);
$mform->addElement('static', 'badgeslabel', '',
" " . get_string('badgesnumber', 'hub', $badges));
$mform->addElement('hidden', 'badges', 1);
$mform->setType('badges', PARAM_INT);
$mform->addElement('static', 'issuedbadgeslabel', '',
" " . get_string('issuedbadgesnumber', 'hub', $issuedbadges));
$mform->addElement('hidden', 'issuedbadges', true);
$mform->setType('issuedbadges', PARAM_INT);
$mform->addElement('static', 'participantnumberaveragelabel', '',
" " . get_string('participantnumberaverage', 'hub', $participantnumberaverage));
$mform->addElement('hidden', 'participantnumberaverage', 1);
$mform->setType('participantnumberaverage', PARAM_FLOAT);
$mform->addElement('static', 'modulenumberaveragelabel', '',
" " . get_string('modulenumberaverage', 'hub', $modulenumberaverage));
$mform->addElement('hidden', 'modulenumberaverage', 1);
$mform->setType('modulenumberaverage', PARAM_FLOAT);
}
//check if it's a first registration or update
$hubregistered = $registrationmanager->get_registeredhub($huburl);
if (!empty($hubregistered)) {
$buttonlabel = get_string('updatesite', 'hub',
!empty($hubname) ? $hubname : $huburl);
$mform->addElement('hidden', 'update', true);
$mform->setType('update', PARAM_BOOL);
} else {
$buttonlabel = get_string('registersite', 'hub',
!empty($hubname) ? $hubname : $huburl);
}
$this->add_action_buttons(false, $buttonlabel);
}
}
+171 -84
View File
@@ -15,112 +15,199 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
/*
* @package moodle
* @subpackage registration
* @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 displays the site registration form for Moodle.net.
* It handles redirection to the hub to continue the registration workflow process.
* It also handles update operation by web service.
* On this page the administrator selects which hub he wants to register (except for moodle.net)
* Admins can register with moodle.net via the site admin menu "Registration" link.
* On this page the administrator can also unregister from any hubs including moodle.net.
*/
require_once('../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require('../../config.php');
admin_externalpage_setup('registrationmoodleorg');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.php');
require_once($CFG->dirroot . '/course/publish/lib.php');
require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
admin_externalpage_setup('registrationhubs');
$renderer = $PAGE->get_renderer('core', 'register');
$unregistration = optional_param('unregistration', 0, PARAM_INT);
$cleanregdata = optional_param('cleanregdata', 0, PARAM_BOOL);
$confirm = optional_param('confirm', 0, PARAM_INT);
$huburl = optional_param('huburl', '', PARAM_URL);
$cancel = optional_param('cancel', null, PARAM_ALPHA);
if ($unregistration && \core\hub\registration::is_registered()) {
$siteunregistrationform = new \core\hub\site_unregistration_form();
$registrationmanager = new registration_manager();
$publicationmanager = new course_publish_manager();
$errormessage = '';
if (empty($cancel) and $unregistration and $confirm and confirm_sesskey()) {
if ($siteunregistrationform->is_cancelled()) {
redirect(new moodle_url('/admin/registration/index.php'));
} else if ($data = $siteunregistrationform->get_data()) {
\core\hub\registration::unregister($data->unpublishalladvertisedcourses,
$data->unpublishalluploadedcourses);
if (!\core\hub\registration::is_registered()) {
redirect(new moodle_url('/admin/registration/index.php'));
$hub = $registrationmanager->get_registeredhub($huburl);
//unpublish course and unregister the site by web service
if (!$cleanregdata) {
//check if we need to unpublish courses
//enrollable courses
$unpublishalladvertisedcourses = optional_param('unpublishalladvertisedcourses', 0, PARAM_INT);
$hubcourseids = array();
if ($unpublishalladvertisedcourses) {
$enrollablecourses = $publicationmanager->get_publications($huburl, null, 1);
if (!empty($enrollablecourses)) {
foreach ($enrollablecourses as $enrollablecourse) {
$hubcourseids[] = $enrollablecourse->hubcourseid;
}
}
}
//downloadable courses
$unpublishalluploadedcourses = optional_param('unpublishalluploadedcourses', 0, PARAM_INT);
if ($unpublishalluploadedcourses) {
$downloadablecourses = $publicationmanager->get_publications($huburl, null, 0);
if (!empty($downloadablecourses)) {
foreach ($downloadablecourses as $downloadablecourse) {
$hubcourseids[] = $downloadablecourse->hubcourseid;
}
}
}
//unpublish the courses by web service
if (!empty($hubcourseids)) {
$function = 'hub_unregister_courses';
$params = array('courseids' => $hubcourseids);
$serverurl = $huburl . "/local/hub/webservice/webservices.php";
$xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
try {
$result = $xmlrpcclient->call($function, $params);
//delete the published courses
if (!empty($enrollablecourses)) {
$publicationmanager->delete_hub_publications($huburl, 1);
}
if (!empty($downloadablecourses)) {
$publicationmanager->delete_hub_publications($huburl, 0);
}
} catch (Exception $e) {
$errormessage = $e->getMessage();
$errormessage .= html_writer::empty_tag('br') .
get_string('errorunpublishcourses', 'hub');
$confirm = false;
$cleanregdata = 1;
}
}
}
//course unpublish went ok, unregister the site now
if ($confirm) {
$function = 'hub_unregister_site';
$params = array();
$serverurl = $huburl . "/local/hub/webservice/webservices.php";
$xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
try {
$result = $xmlrpcclient->call($function, $params);
} catch (Exception $e) {
if (!$cleanregdata) {
$errormessage = $e->getMessage();
$confirm = false;
$cleanregdata = 1;
}
}
}
//check that we are still processing the unregistration,
//it could have been unset if an exception were previsouly catched
if ($confirm) {
$registrationmanager->delete_registeredhub($huburl);
}
}
if (empty($cancel) and $unregistration and !$confirm) {
echo $OUTPUT->header();
//do not check sesskey if confirm = false because this script is linked into email message
if (!empty($errormessage)) {
echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
}
$hub = $registrationmanager->get_registeredhub($huburl);
echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', $hub->hubname), 3, 'main');
if ($cleanregdata) {
$siteunregistrationform = new site_clean_registration_data_form('',
array('huburl' => $huburl, 'hubname' => $hub->hubname));
} else {
$siteunregistrationform = new site_unregistration_form('',
array('huburl' => $huburl, 'hubname' => $hub->hubname));
}
$siteunregistrationform->display();
} else {
$registeredonmoodleorg = false;
$moodleorghub = $registrationmanager->get_registeredhub(HUB_MOODLEORGHUBURL);
if (!empty($moodleorghub)) {
$registeredonmoodleorg = true;
}
// load the hub selector form
$hubselectorform = new hub_selector_form();
$fromform = $hubselectorform->get_data();
$selectedhuburl = optional_param('publichub', false, PARAM_URL);
$unlistedhuburl = optional_param('unlistedurl', false, PARAM_TEXT);
$password = optional_param('password', '', PARAM_RAW);
$registeringhuburl = null;
if (!empty($unlistedhuburl)) {
if (clean_param($unlistedhuburl, PARAM_URL) !== '') {
$registeringhuburl = $unlistedhuburl;
}
} else if (!empty($selectedhuburl)) {
$registeringhuburl = $selectedhuburl;
}
// a hub has been selected, redirect to the hub registration page
if (empty($cancel) and !empty($registeringhuburl) and confirm_sesskey()) {
$hubname = optional_param(clean_param($registeringhuburl, PARAM_ALPHANUMEXT), '', PARAM_TEXT);
$params = array('sesskey' => sesskey(), 'huburl' => $registeringhuburl,
'password' => $password, 'hubname' => $hubname);
redirect(new moodle_url($CFG->wwwroot . "/" . $CFG->admin . "/registration/register.php",
$params));
}
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', 'Moodle.net'), 3, 'main');
$siteunregistrationform->display();
echo $OUTPUT->footer();
exit;
}
$isinitialregistration = \core\hub\registration::show_after_install(true);
if (!$returnurl = optional_param('returnurl', null, PARAM_LOCALURL)) {
$returnurl = $isinitialregistration ? '/admin/index.php' : '/admin/registration/index.php';
}
//check if the site is registered on Moodle.org and display a message about registering on MOOCH
$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
if (empty($registered)) {
$warningmsg = get_string('registermoochtips', 'hub');
$warningmsg .= $renderer->single_button(new moodle_url('register.php', array('huburl' => HUB_MOODLEORGHUBURL
, 'hubname' => 'Moodle.org')), get_string('register', 'admin'));
echo $renderer->box($warningmsg, 'buttons mdl-align generalbox adminwarning');
}
$siteregistrationform = new \core\hub\site_registration_form();
$siteregistrationform->set_data(['returnurl' => $returnurl]);
if ($fromform = $siteregistrationform->get_data()) {
//do not check sesskey if confirm = false because this script is linked into email message
if (!empty($errormessage)) {
echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
}
// Save the settings.
\core\hub\registration::save_site_info($fromform);
echo $OUTPUT->heading(get_string('registerwith', 'hub'));
if (\core\hub\registration::is_registered()) {
if (\core\hub\registration::update_manual()) {
redirect(new moodle_url($returnurl));
$hubselectorform->display();
if (extension_loaded('xmlrpc')) {
$hubs = $registrationmanager->get_registered_on_hubs();
if (!empty($hubs)) {
echo $OUTPUT->heading(get_string('registeredon', 'hub'), 3, 'main');
echo $renderer->registeredonhublisting($hubs);
}
redirect(new moodle_url('/admin/registration/index.php', ['returnurl' => $returnurl]));
} else {
\core\hub\registration::register($returnurl);
// This method will redirect away.
} else { //display notice about xmlrpc
$xmlrpcnotification = $OUTPUT->doc_link('admin/environment/php_extension/xmlrpc', '');
$xmlrpcnotification .= get_string('xmlrpcdisabledregistration', 'hub');
echo $OUTPUT->notification($xmlrpcnotification);
}
}
// OUTPUT SECTION.
echo $OUTPUT->header();
// Current status of registration on Moodle.net.
$notificationtype = \core\output\notification::NOTIFY_ERROR;
if (\core\hub\registration::is_registered()) {
$lastupdated = \core\hub\registration::get_last_updated();
if ($lastupdated == 0) {
$registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
} else if (\core\hub\registration::get_new_registration_fields()) {
$registrationmessage = get_string('pleaserefreshregistrationnewdata', 'admin');
} else {
$lastupdated = userdate($lastupdated, get_string('strftimedate', 'langconfig'));
$registrationmessage = get_string('pleaserefreshregistration', 'admin', $lastupdated);
$notificationtype = \core\output\notification::NOTIFY_INFO;
}
echo $OUTPUT->notification($registrationmessage, $notificationtype);
} else if (!$isinitialregistration) {
$registrationmessage = get_string('registrationwarning', 'admin');
echo $OUTPUT->notification($registrationmessage, $notificationtype);
}
// Heading.
if (\core\hub\registration::is_registered()) {
echo $OUTPUT->heading(get_string('updatesite', 'hub', 'Moodle.net'));
} else if ($isinitialregistration) {
echo $OUTPUT->heading(get_string('completeregistration', 'hub'));
} else {
echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
}
$renderer = $PAGE->get_renderer('core', 'admin');
echo $renderer->moodleorg_registration_message();
$siteregistrationform->display();
if (\core\hub\registration::is_registered()) {
// Unregister link.
$unregisterhuburl = new moodle_url("/admin/registration/index.php", ['unregistration' => 1]);
echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister');
} else if ($isinitialregistration) {
echo html_writer::div(html_writer::link(new moodle_url($returnurl), get_string('skipregistration', 'hub')), 'skipregistration');
}
echo $OUTPUT->footer();
+295 -1
View File
@@ -1,4 +1,5 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
@@ -14,4 +15,297 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
defined('MOODLE_INTERNAL') || die();
//// SITE PRIVACY /////
/**
* Site privacy: private
*/
define('HUB_SITENOTPUBLISHED', 'notdisplayed');
/**
* Site privacy: public
*/
define('HUB_SITENAMEPUBLISHED', 'named');
/**
* Site privacy: public and global
*/
define('HUB_SITELINKPUBLISHED', 'linked');
/**
*
* Site registration library
*
* @package course
* @copyright 2010 Moodle Pty Ltd (http://moodle.com)
* @author Jerome Mouneyrac
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class registration_manager {
/**
* Automatically update the registration on all hubs
*/
public function cron() {
global $CFG;
if (extension_loaded('xmlrpc')) {
$function = 'hub_update_site_info';
require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
// Update all hubs where the site is registered.
$hubs = $this->get_registered_on_hubs();
if (empty($hubs)) {
mtrace(get_string('registrationwarning', 'admin'));
}
foreach ($hubs as $hub) {
// Update the registration.
$siteinfo = $this->get_site_info($hub->huburl);
$params = array('siteinfo' => $siteinfo);
$serverurl = $hub->huburl . "/local/hub/webservice/webservices.php";
$xmlrpcclient = new webservice_xmlrpc_client($serverurl, $hub->token);
try {
$result = $xmlrpcclient->call($function, $params);
$this->update_registeredhub($hub); // To update timemodified.
mtrace(get_string('siteupdatedcron', 'hub', $hub->hubname));
} catch (Exception $e) {
$errorparam = new stdClass();
$errorparam->errormessage = $e->getMessage();
$errorparam->hubname = $hub->hubname;
mtrace(get_string('errorcron', 'hub', $errorparam));
}
}
} else {
mtrace(get_string('errorcronnoxmlrpc', 'hub'));
}
}
/**
* Return the site secret for a given hub
* site identifier is assigned to Mooch
* each hub has a unique and personal site secret.
* @param string $huburl
* @return string site secret
*/
public function get_site_secret_for_hub($huburl) {
global $DB;
$existingregistration = $DB->get_record('registration_hubs',
array('huburl' => $huburl));
if (!empty($existingregistration)) {
return $existingregistration->secret;
}
if ($huburl == HUB_MOODLEORGHUBURL) {
$siteidentifier = get_site_identifier();
} else {
$siteidentifier = random_string(32) . $_SERVER['HTTP_HOST'];
}
return $siteidentifier;
}
/**
* When the site register on a hub, he must call this function
* @param object $hub where the site is registered on
* @return integer id of the record
*/
public function add_registeredhub($hub) {
global $DB;
$hub->timemodified = time();
$id = $DB->insert_record('registration_hubs', $hub);
return $id;
}
/**
* When a site unregister from a hub, he must call this function
* @param string $huburl the huburl to delete
*/
public function delete_registeredhub($huburl) {
global $DB;
$DB->delete_records('registration_hubs', array('huburl' => $huburl));
}
/**
* Get a hub on which the site is registered for a given url or token
* Mostly use to check if the site is registered on a specific hub
* @param string $huburl
* @param string $token
* @return object the hub
*/
public function get_registeredhub($huburl = null, $token = null) {
global $DB;
$params = array();
if (!empty($huburl)) {
$params['huburl'] = $huburl;
}
if (!empty($token)) {
$params['token'] = $token;
}
$params['confirmed'] = 1;
$token = $DB->get_record('registration_hubs', $params);
return $token;
}
/**
* Get the hub which has not confirmed that the site is registered on,
* but for which a request has been sent
* @param string $huburl
* @return object the hub
*/
public function get_unconfirmedhub($huburl) {
global $DB;
$params = array();
$params['huburl'] = $huburl;
$params['confirmed'] = 0;
$token = $DB->get_record('registration_hubs', $params);
return $token;
}
/**
* Update a registered hub (mostly use to update the confirmation status)
* @param object $hub the hub
*/
public function update_registeredhub($hub) {
global $DB;
$hub->timemodified = time();
$DB->update_record('registration_hubs', $hub);
}
/**
* Return all hubs where the site is registered
*/
public function get_registered_on_hubs() {
global $DB;
$hubs = $DB->get_records('registration_hubs', array('confirmed' => 1));
return $hubs;
}
/**
* Return site information for a specific hub
* @param string $huburl
* @return array site info
*/
public function get_site_info($huburl) {
global $CFG, $DB;
$siteinfo = array();
$cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
$siteinfo['name'] = get_config('hub', 'site_name_' . $cleanhuburl);
$siteinfo['description'] = get_config('hub', 'site_description_' . $cleanhuburl);
$siteinfo['contactname'] = get_config('hub', 'site_contactname_' . $cleanhuburl);
$siteinfo['contactemail'] = get_config('hub', 'site_contactemail_' . $cleanhuburl);
$siteinfo['contactphone'] = get_config('hub', 'site_contactphone_' . $cleanhuburl);
$siteinfo['imageurl'] = get_config('hub', 'site_imageurl_' . $cleanhuburl);
$siteinfo['privacy'] = get_config('hub', 'site_privacy_' . $cleanhuburl);
$siteinfo['street'] = get_config('hub', 'site_address_' . $cleanhuburl);
$siteinfo['regioncode'] = get_config('hub', 'site_region_' . $cleanhuburl);
$siteinfo['countrycode'] = get_config('hub', 'site_country_' . $cleanhuburl);
$siteinfo['geolocation'] = get_config('hub', 'site_geolocation_' . $cleanhuburl);
$siteinfo['contactable'] = get_config('hub', 'site_contactable_' . $cleanhuburl);
$siteinfo['emailalert'] = get_config('hub', 'site_emailalert_' . $cleanhuburl);
if (get_config('hub', 'site_coursesnumber_' . $cleanhuburl) == -1) {
$coursecount = -1;
} else {
$coursecount = $DB->count_records('course') - 1;
}
$siteinfo['courses'] = $coursecount;
if (get_config('hub', 'site_usersnumber_' . $cleanhuburl) == -1) {
$usercount = -1;
} else {
$usercount = $DB->count_records('user', array('deleted' => 0));
}
$siteinfo['users'] = $usercount;
if (get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl) == -1) {
$roleassigncount = -1;
} else {
$roleassigncount = $DB->count_records('role_assignments');
}
$siteinfo['enrolments'] = $roleassigncount;
if (get_config('hub', 'site_postsnumber_' . $cleanhuburl) == -1) {
$postcount = -1;
} else {
$postcount = $DB->count_records('forum_posts');
}
$siteinfo['posts'] = $postcount;
if (get_config('hub', 'site_questionsnumber_' . $cleanhuburl) == -1) {
$questioncount = -1;
} else {
$questioncount = $DB->count_records('question');
}
$siteinfo['questions'] = $questioncount;
if (get_config('hub', 'site_resourcesnumber_' . $cleanhuburl) == -1) {
$resourcecount = -1;
} else {
$resourcecount = $DB->count_records('resource');
}
$siteinfo['resources'] = $resourcecount;
// Badge statistics.
require_once($CFG->libdir . '/badgeslib.php');
if (get_config('hub', 'site_badges_' . $cleanhuburl) == -1) {
$badges = -1;
} else {
$badges = $DB->count_records_select('badge', 'status <> ' . BADGE_STATUS_ARCHIVED);
}
$siteinfo['badges'] = $badges;
if (get_config('hub', 'site_issuedbadges_' . $cleanhuburl) == -1) {
$issuedbadges = -1;
} else {
$issuedbadges = $DB->count_records('badge_issued');
}
$siteinfo['issuedbadges'] = $issuedbadges;
//TODO
require_once($CFG->dirroot . "/course/lib.php");
if (get_config('hub', 'site_participantnumberaverage_' . $cleanhuburl) == -1) {
$participantnumberaverage = -1;
} else {
$participantnumberaverage = average_number_of_participants();
}
$siteinfo['participantnumberaverage'] = $participantnumberaverage;
if (get_config('hub', 'site_modulenumberaverage_' . $cleanhuburl) == -1) {
$modulenumberaverage = -1;
} else {
$modulenumberaverage = average_number_of_courses_modules();
}
$siteinfo['modulenumberaverage'] = $modulenumberaverage;
$siteinfo['language'] = get_config('hub', 'site_language_' . $cleanhuburl);
$siteinfo['moodleversion'] = $CFG->version;
$siteinfo['moodlerelease'] = $CFG->release;
$siteinfo['url'] = $CFG->wwwroot;
return $siteinfo;
}
/**
* Retrieve the site privacy string matching the define value
* @param string $privacy must match the define into moodlelib.php
* @return string
*/
public function get_site_privacy_string($privacy) {
switch ($privacy) {
case HUB_SITENOTPUBLISHED:
$privacystring = get_string('siteprivacynotpublished', 'hub');
break;
case HUB_SITENAMEPUBLISHED:
$privacystring = get_string('siteprivacypublished', 'hub');
break;
case HUB_SITELINKPUBLISHED:
$privacystring = get_string('siteprivacylinked', 'hub');
break;
}
if (empty($privacystring)) {
throw new moodle_exception('unknownprivacy');
}
return $privacystring;
}
}
?>
+165 -2
View File
@@ -20,7 +20,7 @@
// //
///////////////////////////////////////////////////////////////////////////
/**
/*
* @package moodle
* @subpackage registration
* @author Jerome Mouneyrac <jerome@mouneyrac.com>
@@ -34,5 +34,168 @@
require_once('../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.php');
require_once($CFG->dirroot . '/webservice/lib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
redirect(new moodle_url('/admin/registration/index.php'));
require_sesskey();
$huburl = required_param('huburl', PARAM_URL);
$huburl = rtrim($huburl, "/");
if ($huburl == HUB_MOODLEORGHUBURL) { // register to Moodle.org
admin_externalpage_setup('registrationmoodleorg');
} else { //register to a hub
admin_externalpage_setup('registrationhub');
}
$password = optional_param('password', '', PARAM_TEXT);
$hubname = optional_param('hubname', '', PARAM_TEXT);
$registrationmanager = new registration_manager();
$registeredhub = $registrationmanager->get_registeredhub($huburl);
$siteregistrationform = new site_registration_form('',
array('alreadyregistered' => !empty($registeredhub->token),
'huburl' => $huburl, 'hubname' => $hubname,
'password' => $password));
$fromform = $siteregistrationform->get_data();
if (!empty($fromform) and confirm_sesskey()) {
// Set to -1 all optional data marked as "don't send" by the admin.
// The function get_site_info() will not calculate the optional data if config is set to -1.
$inputnames = array('courses', 'users', 'roleassignments', 'posts', 'questions', 'resources',
'badges', 'issuedbadges', 'modulenumberaverage', 'participantnumberaverage');
foreach ($inputnames as $inputname) {
if (empty($fromform->{$inputname})) {
$fromform->{$inputname} = -1;
}
}
// Save the settings.
$cleanhuburl = clean_param($huburl, PARAM_ALPHANUMEXT);
set_config('site_name_' . $cleanhuburl, $fromform->name, 'hub');
set_config('site_description_' . $cleanhuburl, $fromform->description, 'hub');
set_config('site_contactname_' . $cleanhuburl, $fromform->contactname, 'hub');
set_config('site_contactemail_' . $cleanhuburl, $fromform->contactemail, 'hub');
set_config('site_contactphone_' . $cleanhuburl, $fromform->contactphone, 'hub');
set_config('site_imageurl_' . $cleanhuburl, $fromform->imageurl, 'hub');
set_config('site_privacy_' . $cleanhuburl, $fromform->privacy, 'hub');
set_config('site_address_' . $cleanhuburl, $fromform->address, 'hub');
set_config('site_region_' . $cleanhuburl, $fromform->regioncode, 'hub');
set_config('site_country_' . $cleanhuburl, $fromform->countrycode, 'hub');
set_config('site_language_' . $cleanhuburl, $fromform->language, 'hub');
set_config('site_geolocation_' . $cleanhuburl, $fromform->geolocation, 'hub');
set_config('site_contactable_' . $cleanhuburl, $fromform->contactable, 'hub');
set_config('site_emailalert_' . $cleanhuburl, $fromform->emailalert, 'hub');
set_config('site_coursesnumber_' . $cleanhuburl, $fromform->courses, 'hub');
set_config('site_usersnumber_' . $cleanhuburl, $fromform->users, 'hub');
set_config('site_roleassignmentsnumber_' . $cleanhuburl, $fromform->roleassignments, 'hub');
set_config('site_postsnumber_' . $cleanhuburl, $fromform->posts, 'hub');
set_config('site_questionsnumber_' . $cleanhuburl, $fromform->questions, 'hub');
set_config('site_resourcesnumber_' . $cleanhuburl, $fromform->resources, 'hub');
set_config('site_badges_' . $cleanhuburl, $fromform->badges, 'hub');
set_config('site_issuedbadges_' . $cleanhuburl, $fromform->issuedbadges, 'hub');
set_config('site_modulenumberaverage_' . $cleanhuburl, $fromform->modulenumberaverage, 'hub');
set_config('site_participantnumberaverage_' . $cleanhuburl, $fromform->participantnumberaverage, 'hub');
}
/////// UPDATE ACTION ////////
// update the hub registration
$update = optional_param('update', 0, PARAM_INT);
if ($update and confirm_sesskey()) {
//update the registration
$function = 'hub_update_site_info';
$siteinfo = $registrationmanager->get_site_info($huburl);
$params = array('siteinfo' => $siteinfo);
$serverurl = $huburl . "/local/hub/webservice/webservices.php";
require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
$xmlrpcclient = new webservice_xmlrpc_client($serverurl, $registeredhub->token);
try {
$result = $xmlrpcclient->call($function, $params);
$registrationmanager->update_registeredhub($registeredhub); // To update timemodified.
} catch (Exception $e) {
$error = $OUTPUT->notification(get_string('errorregistration', 'hub', $e->getMessage()));
}
}
/////// FORM REGISTRATION ACTION //////
if (!empty($fromform) and empty($update) and confirm_sesskey()) {
if (!empty($fromform) and confirm_sesskey()) { // if the register button has been clicked
// Retrieve the optional info (specially course number, user number, module number average...).
$siteinfo = $registrationmanager->get_site_info($huburl);
$fromform->courses = $siteinfo['courses'];
$fromform->users = $siteinfo['users'];
$fromform->enrolments = $siteinfo['enrolments'];
$fromform->posts = $siteinfo['posts'];
$fromform->questions = $siteinfo['questions'];
$fromform->resources = $siteinfo['resources'];
$fromform->badges = $siteinfo['badges'];
$fromform->issuedbadges = $siteinfo['issuedbadges'];
$fromform->modulenumberaverage = $siteinfo['modulenumberaverage'];
$fromform->participantnumberaverage = $siteinfo['participantnumberaverage'];
$fromform->street = $siteinfo['street'];
$params = (array) $fromform; //we are using the form input as the redirection parameters (token, url and name)
$unconfirmedhub = $registrationmanager->get_unconfirmedhub($huburl);
if (empty($unconfirmedhub)) {
//we save the token into the communication table in order to have a reference
$unconfirmedhub = new stdClass();
$unconfirmedhub->token = $registrationmanager->get_site_secret_for_hub($huburl);
$unconfirmedhub->secret = $unconfirmedhub->token;
$unconfirmedhub->huburl = $huburl;
$unconfirmedhub->hubname = $hubname;
$unconfirmedhub->confirmed = 0;
$unconfirmedhub->id = $registrationmanager->add_registeredhub($unconfirmedhub);
}
$params['token'] = $unconfirmedhub->token;
$params['url'] = $CFG->wwwroot;
redirect(new moodle_url($huburl . '/local/hub/siteregistration.php', $params));
}
}
/////// OUTPUT SECTION /////////////
echo $OUTPUT->header();
//Display update notification result
if (!empty($registeredhub->confirmed)) {
if (!empty($result)) {
echo $OUTPUT->notification(get_string('siteregistrationupdated', 'hub'), 'notifysuccess');
}
}
if (!empty($error)) {
echo $error;
}
// Some Moodle.org registration explanation.
if ($huburl == HUB_MOODLEORGHUBURL) {
if (!empty($registeredhub->token)) {
if ($registeredhub->timemodified == 0) {
$registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
} else {
$lastupdated = userdate($registeredhub->timemodified, get_string('strftimedate', 'langconfig'));
$registrationmessage = get_string('pleaserefreshregistration', 'admin', $lastupdated);
}
} else {
$registrationmessage = get_string('registrationwarning', 'admin');
}
echo $OUTPUT->notification($registrationmessage);
echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
$renderer = $PAGE->get_renderer('core', 'register');
echo $renderer->moodleorg_registration_message();
}
$siteregistrationform->display();
echo $OUTPUT->footer();
+95
View File
@@ -0,0 +1,95 @@
<?php
///////////////////////////////////////////////////////////////////////////
// //
// This file is part of Moodle - http://moodle.org/ //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// //
// 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/>. //
// //
///////////////////////////////////////////////////////////////////////////
/**
* Registration renderer.
* @package moodle
* @subpackage registration
* @copyright 2010 Moodle Pty Ltd (http://moodle.com)
* @author Jerome Mouneyrac
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_register_renderer extends plugin_renderer_base {
/**
* Display message about the benefits of registering on Moodle.org
*
* @return string
*/
public function moodleorg_registration_message() {
$moodleorgstatslink = html_writer::link('http://moodle.net/stats',
get_string('statsmoodleorg', 'admin'),
array('target' => '_blank'));
$moodleorgregmsg = get_string('registermoodleorg', 'admin');
$items = array(get_string('registermoodleorgli1', 'admin'),
get_string('registermoodleorgli2', 'admin', $moodleorgstatslink));
$moodleorgregmsg .= html_writer::alist($items);
return $moodleorgregmsg;
}
/**
* Display a box message confirming a site registration (add or update)
* @param string $confirmationmessage
* @return string
*/
public function registration_confirmation($confirmationmessage) {
$linktositelist = html_writer::tag('a', get_string('sitelist', 'hub'),
array('href' => new moodle_url('/local/hub/index.php')));
$message = $confirmationmessage . html_writer::empty_tag('br') . $linktositelist;
return $this->output->box($message);
}
/**
* Display the listing of registered on hub
*/
public function registeredonhublisting($hubs) {
global $CFG;
$table = new html_table();
$table->head = array(get_string('hub', 'hub'), get_string('operation', 'hub'));
$table->size = array('80%', '20%');
foreach ($hubs as $hub) {
if ($hub->huburl == HUB_MOODLEORGHUBURL) {
$hub->hubname = get_string('registeredmoodleorg', 'hub', $hub->hubname);
}
$hublink = html_writer::tag('a', $hub->hubname, array('href' => $hub->huburl));
$hublinkcell = html_writer::tag('div', $hublink, array('class' => 'registeredhubrow'));
$unregisterhuburl = new moodle_url("/" . $CFG->admin . "/registration/index.php",
array('sesskey' => sesskey(), 'huburl' => $hub->huburl,
'unregistration' => 1));
$unregisterbutton = new single_button($unregisterhuburl,
get_string('unregister', 'hub'));
$unregisterbutton->class = 'centeredbutton';
$unregisterbuttonhtml = $this->output->render($unregisterbutton);
//add button cells
$cells = array($hublinkcell, $unregisterbuttonhtml);
$row = new html_table_row($cells);
$table->data[] = $row;
}
return html_writer::table($table);
}
}
+33 -29
View File
@@ -20,7 +20,7 @@
// //
///////////////////////////////////////////////////////////////////////////
/**
/*
* @package moodle
* @subpackage registration
* @author Jerome Mouneyrac <jerome@mouneyrac.com>
@@ -33,40 +33,44 @@
require('../../config.php');
require_once($CFG->libdir . '/adminlib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
$url = optional_param('url', '', PARAM_URL);
$hubname = optional_param('hubname', '', PARAM_TEXT);
$token = optional_param('token', '', PARAM_TEXT);
admin_externalpage_setup('registrationmoodleorg');
admin_externalpage_setup('registrationhubs');
if ($url !== HUB_MOODLEORGHUBURL) {
// Allow other plugins to renew registration on hubs other than moodle.net . Plugins implementing this
// callback need to redirect or exit. See https://docs.moodle.org/en/Hub_registration .
$callbacks = get_plugins_with_function('hub_registration');
foreach ($callbacks as $plugintype => $plugins) {
foreach ($plugins as $plugin => $callback) {
$callback('renew');
}
//check that we are waiting a confirmation from this hub, and check that the token is correct
$registrationmanager = new registration_manager();
$registeredhub = $registrationmanager->get_unconfirmedhub($url);
if (!empty($registeredhub) and $registeredhub->token == $token) {
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('renewregistration', 'hub'), 3, 'main');
$hublink = html_writer::tag('a', $hubname, array('href' => $url));
$registrationmanager->delete_registeredhub($url);
//Mooch case, need to recreate the siteidentifier
if ($url == HUB_MOODLEORGHUBURL) {
$CFG->siteidentifier = null;
get_site_identifier();
}
throw new moodle_exception('errorotherhubsnotsupported', 'hub');
$deletedregmsg = get_string('previousregistrationdeleted', 'hub', $hublink);
$button = new single_button(new moodle_url('/admin/registration/index.php'),
get_string('restartregistration', 'hub'));
$button->class = 'restartregbutton';
echo html_writer::tag('div', $deletedregmsg . $OUTPUT->render($button),
array('class' => 'mdl-align'));
echo $OUTPUT->footer();
} else {
throw new moodle_exception('wrongtoken', 'hub',
$CFG->wwwroot . '/' . $CFG->admin . '/registration/index.php');
}
// Check that we are waiting a confirmation from this hub, and check that the token is correct.
\core\hub\registration::reset_site_identifier($token);
echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('renewregistration', 'hub'), 3, 'main');
$hublink = html_writer::tag('a', 'Moodle.net', array('href' => HUB_MOODLEORGHUBURL));
$deletedregmsg = get_string('previousregistrationdeleted', 'hub', $hublink);
$button = new single_button(new moodle_url('/admin/registration/index.php'),
get_string('restartregistration', 'hub'));
$button->class = 'restartregbutton';
echo html_writer::tag('div', $deletedregmsg . $OUTPUT->render($button),
array('class' => 'mdl-align'));
echo $OUTPUT->footer();
+9 -110
View File
@@ -276,19 +276,12 @@ class core_admin_renderer extends plugin_renderer_base {
* @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
* @param string[] $cachewarnings An array containing warnings from the Cache API.
* @param array $eventshandlers Events 1 API handlers.
* @param bool $themedesignermode Warn about the theme designer mode.
* @param bool $devlibdir Warn about development libs directory presence.
* @param bool $mobileconfigured Whether the mobile web services have been enabled
* @param bool $overridetossl Whether or not ssl is being forced.
* @param bool $invalidforgottenpasswordurl Whether the forgotten password URL does not link to a valid URL.
*
* @return string HTML to output.
*/
public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
$buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0,
$themedesignermode = false, $devlibdir = false, $mobileconfigured = false,
$overridetossl = false, $invalidforgottenpasswordurl = false) {
$buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0, $themedesignermode = false) {
global $CFG;
$output = '';
@@ -297,19 +290,15 @@ class core_admin_renderer extends plugin_renderer_base {
$output .= $this->legacy_log_store_writing_error();
$output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : '';
$output .= $this->insecure_dataroot_warning($insecuredataroot);
$output .= $this->development_libs_directories_warning($devlibdir);
$output .= $this->themedesignermode_warning($themedesignermode);
$output .= $this->display_errors_warning($errorsdisplayed);
$output .= $this->buggy_iconv_warning($buggyiconvnomb);
$output .= $this->cron_overdue_warning($cronoverdue);
$output .= $this->db_problems($dbproblems);
$output .= $this->maintenance_mode_warning($maintenancemode);
$output .= $this->overridetossl_warning($overridetossl);
$output .= $this->cache_warnings($cachewarnings);
$output .= $this->events_handlers($eventshandlers);
$output .= $this->registration_warning($registered);
$output .= $this->mobile_configuration_warning($mobileconfigured);
$output .= $this->forgotten_password_url_warning($invalidforgottenpasswordurl);
//////////////////////////////////////////////////////////////////////////////////////////////////
//// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
@@ -531,24 +520,6 @@ class core_admin_renderer extends plugin_renderer_base {
}
}
/**
* Render a warning that a directory with development libs is present.
*
* @param bool $devlibdir True if the warning should be displayed.
* @return string
*/
protected function development_libs_directories_warning($devlibdir) {
if ($devlibdir) {
$moreinfo = new moodle_url('/report/security/index.php');
$warning = get_string('devlibdirpresent', 'core_admin', ['moreinfourl' => $moreinfo->out()]);
return $this->warning($warning, 'error');
} else {
return '';
}
}
/**
* Render an appropriate message if dataroot is insecure.
* @param bool $errorsdisplayed
@@ -673,20 +644,6 @@ class core_admin_renderer extends plugin_renderer_base {
return $this->warning(get_string('sitemaintenancewarning2', 'admin', $url));
}
/**
* Render a warning that ssl is forced because the site was on loginhttps.
*
* @param bool $overridetossl Whether or not ssl is being forced.
* @return string
*/
protected function overridetossl_warning($overridetossl) {
if (!$overridetossl) {
return '';
}
$warning = get_string('overridetossl', 'core_admin');
return $this->warning($warning, 'warning');
}
/**
* Display a warning about installing development code if necesary.
* @param int $maturity
@@ -823,68 +780,19 @@ class core_admin_renderer extends plugin_renderer_base {
*/
protected function registration_warning($registered) {
if (!$registered && site_is_public()) {
if (has_capability('moodle/site:config', context_system::instance())) {
$registerbutton = $this->single_button(new moodle_url('/admin/registration/index.php'),
get_string('register', 'admin'));
$str = 'registrationwarning';
} else {
$registerbutton = '';
$str = 'registrationwarningcontactadmin';
}
if (!$registered) {
return $this->warning( get_string($str, 'admin')
. '&nbsp;' . $this->help_icon('registration', 'admin') . $registerbutton ,
'error alert alert-danger');
$registerbutton = $this->single_button(new moodle_url('/admin/registration/register.php',
array('huburl' => HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.org')),
get_string('register', 'admin'));
return $this->warning( get_string('registrationwarning', 'admin')
. '&nbsp;' . $this->help_icon('registration', 'admin') . $registerbutton );
}
return '';
}
/**
* Return an admin page warning if site is not registered with moodle.org
*
* @return string
*/
public function warn_if_not_registered() {
return $this->registration_warning(\core\hub\registration::is_registered());
}
/**
* Display a warning about the Mobile Web Services being disabled.
*
* @param boolean $mobileconfigured true if mobile web services are enabled
* @return string HTML to output.
*/
protected function mobile_configuration_warning($mobileconfigured) {
$output = '';
if (!$mobileconfigured) {
$settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
$output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . '&nbsp;' . $configurebutton);
}
return $output;
}
/**
* Display a warning about the forgotten password URL not linking to a valid URL.
*
* @param boolean $invalidforgottenpasswordurl true if the forgotten password URL is not valid
* @return string HTML to output.
*/
protected function forgotten_password_url_warning($invalidforgottenpasswordurl) {
$output = '';
if ($invalidforgottenpasswordurl) {
$settingslink = new moodle_url('/admin/settings.php', ['section' => 'manageauths']);
$configurebutton = $this->single_button($settingslink, get_string('check', 'moodle'));
$output .= $this->warning(get_string('invalidforgottenpasswordurl', 'admin') . '&nbsp;' . $configurebutton,
'error alert alert-danger');
}
return $output;
}
/**
* Helper method to render the information about the available Moodle update
*
@@ -1989,7 +1897,7 @@ class core_admin_renderer extends plugin_renderer_base {
if (empty($CFG->docroot) or $environment_result->plugin) {
$report = get_string($stringtouse, 'admin', $rec);
} else {
$report = $this->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec), true);
$report = $this->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec));
}
// Enclose report text in div so feedback text will be displayed underneath it.
$report = html_writer::div($report);
@@ -2083,13 +1991,4 @@ class core_admin_renderer extends plugin_renderer_base {
return $this->warning(get_string('legacylogginginuse'));
}
}
/**
* Display message about the benefits of registering on Moodle.org
*
* @return string
*/
public function moodleorg_registration_message() {
return format_text(get_string('registermoodlenet', 'admin'), FORMAT_HTML, ['noclean' => true]);
}
}
+1 -5
View File
@@ -29,8 +29,7 @@ $mode = required_param('mode', PARAM_ALPHANUMEXT);
$classformode = array(
'assign' => 'core_role_allow_assign_page',
'override' => 'core_role_allow_override_page',
'switch' => 'core_role_allow_switch_page',
'view' => 'core_role_allow_view_page'
'switch' => 'core_role_allow_switch_page'
);
if (!isset($classformode[$mode])) {
print_error('invalidmode', '', '', $mode);
@@ -59,9 +58,6 @@ if (optional_param('submit', false, PARAM_BOOL) && data_submitted() && confirm_s
case 'switch':
$event = \core\event\role_allow_switch_updated::create(array('context' => $syscontext));
break;
case 'view':
$event = \core\event\role_allow_view_updated::create(array('context' => $syscontext));
break;
}
if ($event) {
$event->trigger();
+1 -1
View File
@@ -245,7 +245,7 @@ if ($roleid) {
$select = new single_select($PAGE->url, 'roleid', $nameswithcounts, $roleid, null);
$select->label = get_string('assignanotherrole', 'core_role');
echo $OUTPUT->render($select);
echo '<p><a href="' . $url . '">' . get_string('backtoallroles', 'core_role') . '</a></p>';
echo '<p><a href="' . $PAGE->url . '">' . get_string('backtoallroles', 'core_role') . '</a></p>';
echo '</div>';
} else if (empty($assignableroles)) {
+1 -1
View File
@@ -33,7 +33,7 @@ class core_role_allow_assign_page extends core_role_allow_role_page {
}
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_assign_allowed($fromroleid, $targetroleid);
allow_assign($fromroleid, $targetroleid);
}
protected function get_cell_tooltip($fromrole, $targetrole) {
+1 -1
View File
@@ -33,7 +33,7 @@ class core_role_allow_override_page extends core_role_allow_role_page {
}
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_override_allowed($fromroleid, $targetroleid);
allow_override($fromroleid, $targetroleid);
}
protected function get_cell_tooltip($fromrole, $targetrole) {
+1 -1
View File
@@ -41,7 +41,7 @@ class core_role_allow_switch_page extends core_role_allow_role_page {
}
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_switch_allowed($fromroleid, $targetroleid);
allow_switch($fromroleid, $targetroleid);
}
protected function is_allowed_target($targetroleid) {
-77
View File
@@ -1,77 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Role view matrix.
*
* @package core_role
* @copyright 2016 onwards Andrew Hancox <andrewdchancox@googlemail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Subclass of role_allow_role_page for the Allow views tab.
*
* @package core_role
* @copyright 2016 onwards Andrew Hancox <andrewdchancox@googlemail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_role_allow_view_page extends core_role_allow_role_page {
/** @var array */
protected $allowedtargetroles;
/**
* core_role_allow_view_page constructor.
*/
public function __construct() {
parent::__construct('role_allow_view', 'allowview');
}
/**
* Allow from role to view target role.
* @param int $fromroleid
* @param int $targetroleid
*/
protected function set_allow($fromroleid, $targetroleid) {
core_role_set_view_allowed($fromroleid, $targetroleid);
}
/**
* Get tool tip for cell.
* @param string $fromrole
* @param string $targetrole
* @return string
* @throws \coding_exception
*/
protected function get_cell_tooltip($fromrole, $targetrole) {
$a = new stdClass;
$a->fromrole = $fromrole->localname;
$a->targetrole = $targetrole->localname;
return get_string('allowroletoview', 'core_role', $a);
}
/**
* Get intro text for role allow view page.
* @return string
* @throws \coding_exception
*/
public function get_intro_text() {
return get_string('configallowview', 'core_admin');
}
}
@@ -183,14 +183,9 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
public function get_risk_icon($type) {
global $OUTPUT;
$alt = get_string("{$type}short", "admin");
$title = get_string($type, "admin");
$text = $OUTPUT->pix_icon('i/' . str_replace('risk', 'risk_', $type), $alt, 'moodle', [
'title' => $title,
]);
$text = $OUTPUT->pix_icon('i/' . str_replace('risk', 'risk_', $type), get_string($type . 'short', 'admin'));
$action = new popup_action('click', $this->risksurl, 'docspopup');
$riskicon = $OUTPUT->action_link($this->risksurl, $text, $action);
$riskicon = $OUTPUT->action_link($this->risksurl, $text, $action, array('title'=>get_string($type, 'admin')));
return $riskicon;
}
+2 -5
View File
@@ -69,11 +69,8 @@ class core_role_check_users_selector extends user_selector_base {
if ($coursecontext and $coursecontext != SITEID) {
$sql1 = " FROM {user} u
JOIN (SELECT DISTINCT subu.id
FROM {user} subu
JOIN {user_enrolments} ue ON (ue.userid = subu.id)
JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid1)
) subq ON subq.id = u.id
JOIN {user_enrolments} ue ON (ue.userid = u.id)
JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid1)
WHERE $wherecondition";
$params['courseid1'] = $coursecontext->instanceid;
@@ -42,7 +42,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
protected $allowassign;
protected $allowoverride;
protected $allowswitch;
protected $allowview;
public function __construct($context, $roleid) {
$this->roleid = $roleid;
@@ -73,7 +72,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
$this->allowassign = array_keys($this->get_allow_roles_list('assign'));
$this->allowoverride = array_keys($this->get_allow_roles_list('override'));
$this->allowswitch = array_keys($this->get_allow_roles_list('switch'));
$this->allowview = array_keys($this->get_allow_roles_list('view'));
} else {
$this->role = new stdClass;
@@ -85,7 +83,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
$this->allowassign = array();
$this->allowoverride = array();
$this->allowswitch = array();
$this->allowview = array();
}
parent::load_current_permissions();
}
@@ -103,8 +100,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
$this->role->shortname = core_text::strtolower(clean_param($this->role->shortname, PARAM_ALPHANUMEXT));
if (empty($this->role->shortname)) {
$this->errors['shortname'] = get_string('errorbadroleshortname', 'core_role');
} else if (core_text::strlen($this->role->shortname) > 100) { // Check if it exceeds the max of 100 characters.
$this->errors['shortname'] = get_string('errorroleshortnametoolong', 'core_role');
}
}
if ($DB->record_exists_select('role', 'shortname = ? and id <> ?', array($this->role->shortname, $this->roleid))) {
@@ -167,10 +162,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
if (!is_null($allow)) {
$this->allowswitch = $allow;
}
$allow = optional_param_array('allowview', null, PARAM_INT);
if (!is_null($allow)) {
$this->allowview = $allow;
}
// Now read the permissions for each capability.
parent::read_submitted_permissions();
@@ -187,8 +178,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
* @param int $roleid role id or 0 for no role
* @param array $options array with following keys:
* 'name', 'shortname', 'description', 'permissions', 'archetype',
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch',
* 'allowview'
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch'
*/
public function force_duplicate($roleid, array $options) {
global $DB;
@@ -225,9 +215,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
if ($options['allowswitch']) {
$this->allowswitch = array();
}
if ($options['allowview']) {
$this->allowview = array();
}
if ($options['permissions']) {
foreach ($this->capabilities as $capid => $cap) {
@@ -273,9 +260,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
if ($options['allowswitch']) {
$this->allowswitch = array_keys($this->get_allow_roles_list('switch', $roleid));
}
if ($options['allowview']) {
$this->allowview = array_keys($this->get_allow_roles_list('view', $roleid));
}
if ($options['permissions']) {
$this->permissions = $DB->get_records_menu('role_capabilities',
@@ -296,8 +280,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
* @param string $archetype
* @param array $options array with following keys:
* 'name', 'shortname', 'description', 'permissions', 'archetype',
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch',
* 'allowview'
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch'
*/
public function force_archetype($archetype, array $options) {
$archetypes = get_role_archetypes();
@@ -338,9 +321,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
if ($options['allowswitch']) {
$this->allowswitch = get_default_role_archetype_allows('switch', $archetype);
}
if ($options['allowview']) {
$this->allowview = get_default_role_archetype_allows('view', $archetype);
}
if ($options['permissions']) {
$defaultpermissions = get_default_capabilities($archetype);
@@ -360,8 +340,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
* @param string $xml
* @param array $options array with following keys:
* 'name', 'shortname', 'description', 'permissions', 'archetype',
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch',
* 'allowview'
* 'contextlevels', 'allowassign', 'allowoverride', 'allowswitch'
*/
public function force_preset($xml, array $options) {
if (!$info = core_role_preset::parse_preset($xml)) {
@@ -398,7 +377,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
}
}
foreach (array('assign', 'override', 'switch', 'view') as $type) {
foreach (array('assign', 'override', 'switch') as $type) {
if ($options['allow'.$type]) {
if (isset($info['allow'.$type])) {
$this->{'allow'.$type} = $info['allow'.$type];
@@ -459,7 +438,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
$this->save_allow('assign');
$this->save_allow('override');
$this->save_allow('switch');
$this->save_allow('view');
// Permissions.
parent::save_changes();
@@ -471,7 +449,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
$current = array_keys($this->get_allow_roles_list($type));
$wanted = $this->{'allow'.$type};
$addfunction = "core_role_set_{$type}_allowed";
$addfunction = 'allow_'.$type;
$deltable = 'role_allow_'.$type;
$field = 'allow'.$type;
@@ -498,7 +476,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
}
protected function get_shortname_field($id) {
return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="100" value="' . s($this->role->shortname) . '"' .
return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="254" value="' . s($this->role->shortname) . '"' .
' class="form-control"/>';
}
@@ -528,11 +506,9 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
if (!$this->disabled) {
$output .= '<input type="hidden" name="contextlevel' . $cl . '" value="0" />';
}
$output .= '<div class="form-check justify-content-start w-100">';
$output .= '<input class="form-check-input" type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
$output .= '<input type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
'" value="1" ' . $extraarguments . '/> ';
$output .= '<label class="form-check-label" for="cl' . $cl . '">' . $clname . "</label>\n";
$output .= '</div>';
$output .= '<label for="cl' . $cl . '">' . $clname . "</label><br />\n";
}
return $output;
}
@@ -547,7 +523,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
protected function get_allow_roles_list($type, $roleid = null) {
global $DB;
if ($type !== 'assign' and $type !== 'switch' and $type !== 'override' and $type !== 'view') {
if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
return array();
}
@@ -571,11 +547,11 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
/**
* Returns an array of roles with the allowed type.
*
* @param string $type Must be one of: assign, switch, override or view.
* @param string $type Must be one of: assign, switch, or override.
* @return array Am array of role names with the allowed type
*/
protected function get_allow_role_control($type) {
if ($type !== 'assign' and $type !== 'switch' and $type !== 'override' and $type !== 'view') {
if ($type !== 'assign' and $type !== 'switch' and $type !== 'override') {
debugging('Invalid role allowed type specified', DEBUG_DEVELOPER);
return '';
}
@@ -665,7 +641,6 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
$this->print_field('menuallowassign', get_string('allowassign', 'core_role'), $this->get_allow_role_control('assign'));
$this->print_field('menuallowoverride', get_string('allowoverride', 'core_role'), $this->get_allow_role_control('override'));
$this->print_field('menuallowswitch', get_string('allowswitch', 'core_role'), $this->get_allow_role_control('switch'));
$this->print_field('menuallowview', get_string('allowview', 'core_role'), $this->get_allow_role_control('view'));
if ($risks = $this->get_role_risks_info()) {
$this->print_field('', get_string('rolerisks', 'core_role'), $risks);
}
+2 -2
View File
@@ -84,7 +84,7 @@ class core_role_preset {
$contextlevels->appendChild($dom->createElement('level', $name));
}
foreach (array('assign', 'override', 'switch', 'view') as $type) {
foreach (array('assign', 'override', 'switch') as $type) {
$allows = $dom->createElement('allow'.$type);
$top->appendChild($allows);
$records = $DB->get_records('role_allow_'.$type, array('roleid'=>$roleid), "allow$type ASC");
@@ -205,7 +205,7 @@ class core_role_preset {
}
}
foreach (array('assign', 'override', 'switch', 'view') as $type) {
foreach (array('assign', 'override', 'switch') as $type) {
$values = self::get_node_children_values($dom, '/role/allow'.$type, 'shortname');
if (!isset($values)) {
$info['allow'.$type] = null;
-1
View File
@@ -79,7 +79,6 @@ class core_role_preset_form extends moodleform {
$mform->addElement('advcheckbox', 'allowassign', get_string('allowassign', 'core_role'));
$mform->addElement('advcheckbox', 'allowoverride', get_string('allowoverride', 'core_role'));
$mform->addElement('advcheckbox', 'allowswitch', get_string('allowswitch', 'core_role'));
$mform->addElement('advcheckbox', 'allowview', get_string('allowview', 'core_role'));
$mform->addElement('advcheckbox', 'permissions', get_string('permissions', 'core_role'));
}
-459
View File
@@ -1,459 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for core_role.
*
* @package core_role
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_role\privacy;
defined('MOODLE_INTERNAL') || die();
use \core_privacy\local\metadata\collection;
use \core_privacy\local\request\contextlist;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\transform;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\userlist;
use \core_privacy\local\request\approved_userlist;
/**
* Privacy provider for core_role.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\provider,
\core_privacy\local\request\subsystem\plugin_provider,
\core_privacy\local\request\user_preference_provider,
\core_privacy\local\request\core_userlist_provider {
/**
* Get information about the user data stored by this plugin.
*
* @param collection $collection An object for storing metadata.
* @return collection The metadata.
*/
public static function get_metadata(collection $collection) : collection {
$rolecapabilities = [
'roleid' => 'privacy:metadata:role_capabilities:roleid',
'capability' => 'privacy:metadata:role_capabilities:capability',
'permission' => 'privacy:metadata:role_capabilities:permission',
'timemodified' => 'privacy:metadata:role_capabilities:timemodified',
'modifierid' => 'privacy:metadata:role_capabilities:modifierid'
];
$roleassignments = [
'roleid' => 'privacy:metadata:role_assignments:roleid',
'userid' => 'privacy:metadata:role_assignments:userid',
'timemodified' => 'privacy:metadata:role_assignments:timemodified',
'modifierid' => 'privacy:metadata:role_assignments:modifierid',
'component' => 'privacy:metadata:role_assignments:component',
'itemid' => 'privacy:metadata:role_assignments:itemid'
];
$collection->add_database_table('role_capabilities', $rolecapabilities,
'privacy:metadata:role_capabilities:tableexplanation');
$collection->add_database_table('role_assignments', $roleassignments,
'privacy:metadata:role_assignments:tableexplanation');
$collection->add_user_preference('definerole_showadvanced',
'privacy:metadata:preference:showadvanced');
return $collection;
}
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$showadvanced = get_user_preferences('definerole_showadvanced', null, $userid);
if ($showadvanced !== null) {
writer::export_user_preference('core_role',
'definerole_showadvanced',
transform::yesno($showadvanced),
get_string('privacy:metadata:preference:showadvanced', 'core_role')
);
}
}
/**
* Return all contexts for this userid.
*
* @param int $userid The user ID.
* @return contextlist The list of context IDs.
*/
public static function get_contexts_for_userid(int $userid) : contextlist {
global $DB;
$contextlist = new contextlist();
// The role_capabilities table contains user data.
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$sql = "SELECT ctx.id
FROM {context} ctx
JOIN {role_capabilities} rc
ON rc.contextid = ctx.id
AND ((ctx.contextlevel {$insql} AND rc.modifierid = :modifierid)
OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))";
$params = [
'modifierid' => $userid,
'contextlevel' => CONTEXT_USER,
'userid' => $userid
];
$params += $inparams;
$contextlist->add_from_sql($sql, $params);
// The role_assignments table contains user data.
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$params = [
'userid' => $userid,
'modifierid' => $userid
];
$params += $inparams;
$sql = "SELECT ctx.id
FROM {role_assignments} ra
JOIN {context} ctx
ON ctx.id = ra.contextid
AND ctx.contextlevel {$insql}
WHERE (ra.userid = :userid
OR ra.modifierid = :modifierid)
AND ra.component != 'tool_cohortroles'";
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users within a specific context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
if (empty($userlist)) {
return;
}
$context = $userlist->get_context();
// Include users who created or modified role capabilities.
$sql = "SELECT modifierid as userid
FROM {role_capabilities}
WHERE contextid = :contextid";
$params = [
'contextid' => $context->id
];
$userlist->add_from_sql('userid', $sql, $params);
// Include users that have a role assigned to them.
$sql = "SELECT userid
FROM {role_assignments}
WHERE contextid = :contextid";
$userlist->add_from_sql('userid', $sql, $params);
// Include users who created or modified the role assignment.
// Differentiate and exclude special cases where tool_cohortroles adds records through the
// "Assign user roles to cohort" feature into the role_assignments table.
// These records should be separately processed in tool_cohortroles.
$sql = "SELECT modifierid as userid
FROM {role_assignments}
WHERE contextid = :contextid
AND component != 'tool_cohortroles'";
$userlist->add_from_sql('userid', $sql, $params);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The list of approved contexts for a user.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
if (empty($contextlist)) {
return;
}
$rolesnames = self::get_roles_name();
$userid = $contextlist->get_user()->id;
$ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
// Role Assignments export data.
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, $ctxfields
FROM {role_assignments} ra
JOIN {context} ctx
ON ctx.id = ra.contextid
AND ctx.contextlevel {$inctxsql}
AND (ra.userid = :userid OR ra.modifierid = :modifierid)
AND ra.component != 'tool_cohortroles'
JOIN {role} r
ON r.id = ra.roleid
WHERE ctx.id {$insql}";
$params = ['userid' => $userid, 'modifierid' => $userid];
$params += $inparams;
$params += $ctxparams;
$assignments = $DB->get_recordset_sql($sql, $params);
foreach ($assignments as $assignment) {
\context_helper::preload_from_record($assignment);
$alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
'timemodified' => transform::datetime($assignment->timemodified),
'userid' => transform::user($assignment->userid),
'modifierid' => transform::user($assignment->modifierid)
];
}
$assignments->close();
if (!empty($alldata)) {
array_walk($alldata, function($roledata, $contextid) {
$context = \context::instance_by_id($contextid);
array_walk($roledata, function($data, $rolename) use ($context) {
writer::with_context($context)->export_data(
[get_string('privacy:metadata:role_assignments', 'core_role'), $rolename],
(object)$data);
});
});
unset($alldata);
}
// Role Capabilities export data.
$strpermissions = self::get_permissions_name();
$contexts = [
CONTEXT_SYSTEM,
CONTEXT_USER,
CONTEXT_COURSECAT,
CONTEXT_COURSE,
CONTEXT_MODULE,
CONTEXT_BLOCK
];
list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
$sql = "SELECT rc.id, rc.contextid, rc.capability, rc.permission, rc.timemodified, rc.roleid, $ctxfields
FROM {context} ctx
JOIN {role_capabilities} rc
ON rc.contextid = ctx.id
AND ((ctx.contextlevel {$inctxsql} AND rc.modifierid = :modifierid)
OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))
WHERE ctx.id {$insql}";
$params = [
'modifierid' => $userid,
'contextlevel' => CONTEXT_USER,
'userid' => $userid
];
$params += $inparams;
$params += $ctxparams;
$capabilities = $DB->get_recordset_sql($sql, $params);
foreach ($capabilities as $capability) {
\context_helper::preload_from_record($capability);
$alldata[$capability->contextid][$rolesnames[$capability->roleid]][] = (object)[
'timemodified' => transform::datetime($capability->timemodified),
'capability' => $capability->capability,
'permission' => $strpermissions[$capability->permission]
];
}
$capabilities->close();
if (!empty($alldata)) {
array_walk($alldata, function($capdata, $contextid) {
$context = \context::instance_by_id($contextid);
array_walk($capdata, function($data, $rolename) use ($context) {
writer::with_context($context)->export_data(
[get_string('privacy:metadata:role_capabilities', 'core_role'), $rolename],
(object)$data);
});
});
}
}
/**
* Exports the data relating to tool_cohortroles component on role assignments by
* Assign user roles to cohort feature.
*
* @param int $userid The user ID.
*/
public static function export_user_role_to_cohort(int $userid) {
global $DB;
$rolesnames = self::get_roles_name();
$sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, r.id as roleid
FROM {role_assignments} ra
JOIN {context} ctx
ON ctx.id = ra.contextid
AND ctx.contextlevel = :contextlevel
AND ra.component = 'tool_cohortroles'
JOIN {role} r
ON r.id = ra.roleid
WHERE ctx.instanceid = :instanceid
OR ra.userid = :userid";
$params = ['userid' => $userid, 'instanceid' => $userid, 'contextlevel' => CONTEXT_USER];
$assignments = $DB->get_recordset_sql($sql, $params);
foreach ($assignments as $assignment) {
$alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
'timemodified' => transform::datetime($assignment->timemodified),
'userid' => transform::user($assignment->userid),
'modifierid' => transform::user($assignment->modifierid)
];
}
$assignments->close();
if (!empty($alldata)) {
array_walk($alldata, function($roledata, $contextid) {
$context = \context::instance_by_id($contextid);
array_walk($roledata, function($data, $rolename) use ($context) {
writer::with_context($context)->export_related_data(
[get_string('privacy:metadata:role_cohortroles', 'core_role'), $rolename], 'cohortroles',
(object)$data);
});
});
}
}
/**
* Delete all user data for this context.
*
* @param \context $context The context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
// Don't remove data from role_capabilities.
// Because this data affects the whole Moodle, there are override capabilities.
// Don't belong to the modifier user.
// Remove data from role_assignments.
$DB->delete_records('role_assignments', ['contextid' => $context->id]);
}
/**
* Delete multiple users within a single context.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
global $DB;
// Don't remove data from role_capabilities.
// Because this data affects the whole Moodle, there are override capabilities.
// Don't belong to the modifier user.
$context = $userlist->get_context();
$userids = $userlist->get_userids();
if (empty($userids)) {
return;
}
list($usersql, $userparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$params = ['contextid' => $context->id] + $userparams;
// Remove data from role_assignments.
$DB->delete_records_select('role_assignments',
"contextid = :contextid AND userid {$usersql}", $params);
}
/**
* Delete all user data for this user only.
*
* @param approved_contextlist $contextlist The list of approved contexts for a user.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
// Don't remove data from role_capabilities.
// Because this data affects the whole Moodle, there are override capabilities.
// Don't belong to the modifier user.
// Remove data from role_assignments.
if (empty($contextlist->count())) {
return;
}
$userid = $contextlist->get_user()->id;
$contextids = $contextlist->get_contextids();
list($contextsql, $contextparams) = $DB->get_in_or_equal($contextids, SQL_PARAMS_NAMED);
$params = ['userid' => $userid] + $contextparams;
// Only delete the roles assignments where the user is assigned in all contexts.
$DB->delete_records_select('role_assignments',
"userid = :userid AND contextid {$contextsql}", $params);
}
/**
* Delete user entries in role_assignments related to the feature
* Assign user roles to cohort feature.
*
* @param int $userid The user ID.
*/
public static function delete_user_role_to_cohort(int $userid) {
global $DB;
// Delete entries where userid is a mentor by tool_cohortroles.
$DB->delete_records('role_assignments', ['userid' => $userid, 'component' => 'tool_cohortroles']);
}
/**
* Get all the localised roles name in a simple array.
*
* @return array Array of name of the roles by roleid.
*/
protected static function get_roles_name() {
$roles = role_fix_names(get_all_roles(), \context_system::instance(), ROLENAME_ORIGINAL);
$rolesnames = array();
foreach ($roles as $role) {
$rolesnames[$role->id] = $role->localname;
}
return $rolesnames;
}
/**
* Get all the permissions name in a simple array.
*
* @return array Array of permissions name.
*/
protected static function get_permissions_name() {
$strpermissions = array(
CAP_INHERIT => get_string('inherit', 'role'),
CAP_ALLOW => get_string('allow', 'role'),
CAP_PREVENT => get_string('prevent', 'role'),
CAP_PROHIBIT => get_string('prohibit', 'role')
);
return $strpermissions;
}
}
+2 -4
View File
@@ -103,8 +103,7 @@ if ($action === 'add' and $resettype !== 'none') {
'contextlevels' => 1,
'allowassign' => 1,
'allowoverride' => 1,
'allowswitch' => 1,
'allowview' => 1);
'allowswitch' => 1);
if ($showadvanced) {
$definitiontable = new core_role_define_role_table_advanced($systemcontext, 0);
} else {
@@ -151,8 +150,7 @@ if ($action === 'add' and $resettype !== 'none') {
'contextlevels' => $data->contextlevels,
'allowassign' => $data->allowassign,
'allowoverride' => $data->allowoverride,
'allowswitch' => $data->allowswitch,
'allowview' => $data->allowview);
'allowswitch' => $data->allowswitch);
if ($showadvanced) {
$definitiontable = new core_role_define_role_table_advanced($systemcontext, $roleid);
} else {
-1
View File
@@ -29,7 +29,6 @@ $toprow[] = new tabobject('manage', new moodle_url('/admin/roles/manage.php'), g
$toprow[] = new tabobject('assign', new moodle_url('/admin/roles/allow.php', array('mode'=>'assign')), get_string('allowassign', 'core_role'));
$toprow[] = new tabobject('override', new moodle_url('/admin/roles/allow.php', array('mode'=>'override')), get_string('allowoverride', 'core_role'));
$toprow[] = new tabobject('switch', new moodle_url('/admin/roles/allow.php', array('mode'=>'switch')), get_string('allowswitch', 'core_role'));
$toprow[] = new tabobject('view', new moodle_url('/admin/roles/allow.php', ['mode' => 'view']), get_string('allowview', 'core_role'));
echo $OUTPUT->tabtree($toprow, $currenttab);
-8
View File
@@ -11,7 +11,6 @@
<xs:element ref="allowassign" minOccurs="0"/>
<xs:element ref="allowoverride" minOccurs="0"/>
<xs:element ref="allowswitch" minOccurs="0"/>
<xs:element ref="allowview" minOccurs="0"/>
<xs:element ref="permissions" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
@@ -46,13 +45,6 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="allowview">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" minOccurs="0" ref="shortname"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="permissions">
<xs:complexType>
<xs:sequence>
+1 -1
View File
@@ -44,7 +44,7 @@ class core_role_preset_testcase extends advanced_testcase {
$contextlevels = get_role_contextlevels($role->id);
$this->assertEquals(array_values($contextlevels), array_values($info['contextlevels']));
foreach (array('assign', 'override', 'switch', 'view') as $type) {
foreach (array('assign', 'override', 'switch') as $type) {
$records = $DB->get_records('role_allow_'.$type, array('roleid'=>$role->id), "allow$type ASC");
$allows = array();
foreach ($records as $record) {
-747
View File
@@ -1,747 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy test for core_role
*
* @package core_role
* @category test
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
use \core_role\privacy\provider;
use \core_privacy\local\request\approved_contextlist;
use \core_privacy\local\request\writer;
use \core_privacy\tests\provider_testcase;
use \core_privacy\local\request\transform;
use \tool_cohortroles\api;
use \core_privacy\local\request\approved_userlist;
/**
* Privacy test for core_role
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_role_privacy_testcase extends provider_testcase {
/**
* Test to check export_user_preferences.
* returns user preferences data.
*/
public function test_export_user_preferences() {
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$showadvanced = 1;
set_user_preference('definerole_showadvanced', $showadvanced);
provider::export_user_preferences($user->id);
$writer = writer::with_context(\context_system::instance());
$prefs = $writer->get_user_preferences('core_role');
$this->assertEquals(transform::yesno($showadvanced), transform::yesno($prefs->definerole_showadvanced->value));
$this->assertEquals(get_string('privacy:metadata:preference:showadvanced', 'core_role'),
$prefs->definerole_showadvanced->description);
}
/**
* Check all contexts are returned if there is any user data for this user.
*/
public function test_get_contexts_for_userid() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$this->assertEmpty(provider::get_contexts_for_userid($user->id));
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
$course = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
$coursecat = $this->getDataGenerator()->create_category();
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
$cmcontext = \context_module::instance($cm->cmid);
$page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
$cmcontext2 = \context_module::instance($page->cmid);
$coursecontext = \context_course::instance($course->id);
$coursecontext2 = \context_course::instance($course2->id);
$coursecatcontext = \context_coursecat::instance($coursecat->id);
$systemcontext = \context_system::instance();
$block = $this->getDataGenerator()->create_block('online_users');
$blockcontext = \context_block::instance($block->id);
$student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$manager = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
// Role assignments, where the user is assigned.
role_assign($student->id, $user->id, $cmcontext2->id);
role_assign($student->id, $user->id, $coursecontext2->id);
role_assign($student->id, $user->id, $blockcontext->id);
role_assign($manager->id, $user->id, $usercontext2->id);
// Role assignments, where the user makes assignments.
$this->setUser($user);
role_assign($student->id, $user2->id, $coursecontext->id);
role_assign($manager->id, $user2->id, $coursecatcontext->id);
role_assign($manager->id, $user2->id, $systemcontext->id);
// Role capabilities.
$this->setUser($user);
$result = assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $cmcontext->id);
$contextlist = provider::get_contexts_for_userid($user->id)->get_contextids();
$this->assertCount(8, $contextlist);
$this->assertTrue(in_array($cmcontext->id, $contextlist));
}
/**
* Test that user data is exported correctly.
*/
public function test_export_user_data() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
$course = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
$coursecat = $this->getDataGenerator()->create_category();
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
$cmcontext = \context_module::instance($cm->cmid);
$page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
$cmcontext2 = \context_module::instance($page->cmid);
$coursecontext = \context_course::instance($course->id);
$coursecontext2 = \context_course::instance($course2->id);
$coursecatcontext = \context_coursecat::instance($coursecat->id);
$systemcontext = \context_system::instance();
$block = $this->getDataGenerator()->create_block('online_users');
$blockcontext = \context_block::instance($block->id);
$student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$manager = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
$rolesnames = self::get_roles_name();
$subcontextstudent = [
get_string('privacy:metadata:role_assignments', 'core_role'),
$rolesnames[$student->id]
];
$subcontextmanager = [
get_string('privacy:metadata:role_assignments', 'core_role'),
$rolesnames[$manager->id]
];
$subcontextrc = [
get_string('privacy:metadata:role_capabilities', 'core_role'),
$rolesnames[$student->id]
];
// Test over role assignments.
// Where the user is assigned.
role_assign($student->id, $user->id, $cmcontext2->id);
role_assign($student->id, $user->id, $coursecontext2->id);
role_assign($student->id, $user->id, $blockcontext->id);
role_assign($manager->id, $user->id, $usercontext2->id);
// Where the user makes assignments.
$this->setUser($user);
role_assign($manager->id, $user2->id, $coursecatcontext->id);
role_assign($manager->id, $user2->id, $systemcontext->id);
// Test overridable roles in module, course, category, user, system and block.
assign_capability('moodle/backup:backupactivity', CAP_ALLOW, $student->id, $cmcontext->id, true);
assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $coursecontext->id, true);
assign_capability('moodle/category:manage', CAP_ALLOW, $student->id, $coursecatcontext->id, true);
assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $student->id, $systemcontext->id, true);
assign_capability('moodle/block:edit', CAP_ALLOW, $student->id, $blockcontext->id, true);
assign_capability('moodle/competency:evidencedelete', CAP_ALLOW, $student->id, $usercontext2->id, true);
// Retrieve the user's context ids.
$contextlist = provider::get_contexts_for_userid($user->id);
$approvedcontextlist = new approved_contextlist($user, 'core_role', $contextlist->get_contextids());
$strpermissions = array(
CAP_INHERIT => get_string('inherit', 'role'),
CAP_ALLOW => get_string('allow', 'role'),
CAP_PREVENT => get_string('prevent', 'role'),
CAP_PROHIBIT => get_string('prohibit', 'role')
);
// Retrieve role capabilities and role assignments.
provider::export_user_data($approvedcontextlist);
foreach ($contextlist as $context) {
$writer = writer::with_context($context);
$this->assertTrue($writer->has_any_data());
if ($context->contextlevel == CONTEXT_MODULE) {
if ($data = $writer->get_data($subcontextstudent)) {
$this->assertEquals($user->id, reset($data)->userid);
}
if ($data = $writer->get_data($subcontextrc)) {
$this->assertEquals('moodle/backup:backupactivity', reset($data)->capability);
$this->assertEquals($strpermissions[CAP_ALLOW], reset($data)->permission);
}
}
if ($context->contextlevel == CONTEXT_COURSE) {
if ($data = $writer->get_data($subcontextstudent)) {
$this->assertEquals($user->id, reset($data)->userid);
}
if ($data = $writer->get_data($subcontextrc)) {
$this->assertEquals('moodle/backup:backupcourse', reset($data)->capability);
}
}
if ($context->contextlevel == CONTEXT_COURSECAT) {
if ($data = $writer->get_data($subcontextmanager)) {
$this->assertEquals($user->id, reset($data)->modifierid);
}
if ($data = $writer->get_data($subcontextrc)) {
$this->assertEquals('moodle/category:manage', reset($data)->capability);
}
}
if ($context->contextlevel == CONTEXT_SYSTEM) {
if ($data = $writer->get_data($subcontextmanager)) {
$this->assertEquals($user->id, reset($data)->modifierid);
}
if ($data = $writer->get_data($subcontextrc)) {
$this->assertEquals('moodle/backup:backupcourse', reset($data)->capability);
}
}
if ($context->contextlevel == CONTEXT_BLOCK) {
if ($data = $writer->get_data($subcontextstudent)) {
$this->assertEquals($user->id, reset($data)->userid);
}
if ($data = $writer->get_data($subcontextrc)) {
$this->assertEquals('moodle/block:edit', reset($data)->capability);
}
}
if ($context->contextlevel == CONTEXT_USER) {
if ($data = $writer->get_data($subcontextmanager)) {
$this->assertEquals($user->id, reset($data)->userid);
}
if ($data = $writer->get_data($subcontextrc)) {
$this->assertEquals('moodle/competency:evidencedelete', reset($data)->capability);
}
}
}
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
$user3 = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
$coursecat = $this->getDataGenerator()->create_category();
$coursecatcontext = \context_coursecat::instance($coursecat->id);
$systemcontext = \context_system::instance();
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
$cmcontext = \context_module::instance($cm->cmid);
$student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$manager = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
$block = $this->getDataGenerator()->create_block('online_users');
$blockcontext = \context_block::instance($block->id);
// Role assignments CONTEXT_COURSE.
role_assign($student->id, $user->id, $coursecontext->id);
role_assign($student->id, $user2->id, $coursecontext->id);
role_assign($student->id, $user3->id, $coursecontext->id);
$count = $DB->count_records('role_assignments', ['contextid' => $coursecontext->id]);
$this->assertEquals(3, $count);
// Role assignments CONTEXT_COURSECAT.
role_assign($student->id, $user2->id, $coursecatcontext->id);
role_assign($student->id, $user3->id, $coursecatcontext->id);
$count = $DB->count_records('role_assignments', ['contextid' => $coursecatcontext->id]);
$this->assertEquals(2, $count);
// Role assignments CONTEXT_SYSTEM.
role_assign($student->id, $user->id, $systemcontext->id);
$count = $DB->count_records('role_assignments', ['contextid' => $systemcontext->id]);
$this->assertEquals(1, $count);
// Role assignments CONTEXT_MODULE.
role_assign($student->id, $user->id, $cmcontext->id);
$count = $DB->count_records('role_assignments', ['contextid' => $cmcontext->id]);
$this->assertEquals(1, $count);
// Role assigments CONTEXT_BLOCK.
role_assign($student->id, $user->id, $blockcontext->id);
$count = $DB->count_records('role_assignments', ['contextid' => $blockcontext->id]);
$this->assertEquals(1, $count);
// Role assigments CONTEXT_USER.
role_assign($manager->id, $user->id, $usercontext2->id);
$count = $DB->count_records('role_assignments', ['contextid' => $usercontext2->id]);
$this->assertEquals(1, $count);
// Delete data based on CONTEXT_COURSE context.
provider::delete_data_for_all_users_in_context($coursecontext);
// After deletion, the role_assignments entries for this context should have been deleted.
$count = $DB->count_records('role_assignments', ['contextid' => $coursecontext->id]);
$this->assertEquals(0, $count);
// Check it is not removing data on other contexts.
$count = $DB->count_records('role_assignments', ['contextid' => $coursecatcontext->id]);
$this->assertEquals(2, $count);
$count = $DB->count_records('role_assignments', ['contextid' => $systemcontext->id]);
$this->assertEquals(1, $count);
$count = $DB->count_records('role_assignments', ['contextid' => $cmcontext->id]);
$this->assertEquals(1, $count);
// Delete data based on CONTEXT_COURSECAT context.
provider::delete_data_for_all_users_in_context($coursecatcontext);
// After deletion, the role_assignments entries for this context should have been deleted.
$count = $DB->count_records('role_assignments', ['contextid' => $coursecatcontext->id]);
$this->assertEquals(0, $count);
// Delete data based on CONTEXT_SYSTEM context.
provider::delete_data_for_all_users_in_context($systemcontext);
// After deletion, the role_assignments entries for this context should have been deleted.
$count = $DB->count_records('role_assignments', ['contextid' => $systemcontext->id]);
$this->assertEquals(0, $count);
// Delete data based on CONTEXT_MODULE context.
provider::delete_data_for_all_users_in_context($cmcontext);
// After deletion, the role_assignments entries for this context should have been deleted.
$count = $DB->count_records('role_assignments', ['contextid' => $cmcontext->id]);
$this->assertEquals(0, $count);
// Delete data based on CONTEXT_BLOCK context.
provider::delete_data_for_all_users_in_context($usercontext2);
// After deletion, the role_assignments entries for this context should have been deleted.
$count = $DB->count_records('role_assignments', ['contextid' => $usercontext2->id]);
$this->assertEquals(0, $count);
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$user = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
$user3 = $this->getDataGenerator()->create_user();
$usercontext3 = \context_user::instance($user3->id);
$course = $this->getDataGenerator()->create_course();
$course2 = $this->getDataGenerator()->create_course();
$course3 = $this->getDataGenerator()->create_course();
$coursecontext = \context_course::instance($course->id);
$coursecontext2 = \context_course::instance($course2->id);
$coursecontext3 = \context_course::instance($course3->id);
$coursecat = $this->getDataGenerator()->create_category();
$coursecatcontext = \context_coursecat::instance($coursecat->id);
$systemcontext = \context_system::instance();
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course->id]);
$cmcontext = \context_module::instance($cm->cmid);
$student = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$manager = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
$block = $this->getDataGenerator()->create_block('online_users');
$blockcontext = \context_block::instance($block->id);
// Role assignments, Where the user is assigned.
role_assign($student->id, $user->id, $coursecontext->id);
role_assign($student->id, $user->id, $coursecontext2->id);
role_assign($student->id, $user->id, $coursecatcontext->id);
role_assign($student->id, $user->id, $cmcontext->id);
role_assign($student->id, $user->id, $systemcontext->id);
role_assign($student->id, $user->id, $blockcontext->id);
role_assign($manager->id, $user->id, $usercontext2->id);
role_assign($manager->id, $user->id, $usercontext3->id);
$count = $DB->count_records('role_assignments', ['userid' => $user->id]);
$this->assertEquals(8, $count);
// Role assignments, where the user makes assignments.
$this->setUser($user);
role_assign($student->id, $user2->id, $coursecontext3->id);
role_assign($student->id, $user3->id, $coursecontext3->id);
$count = $DB->count_records('role_assignments', ['modifierid' => $user->id]);
$this->assertEquals(2, $count);
$contextlist = provider::get_contexts_for_userid($user->id);
$approvedcontextlist = new approved_contextlist($user, 'core_role', $contextlist->get_contextids());
provider::delete_data_for_user($approvedcontextlist);
// After deletion, the role_assignments assigned to the user should have been deleted.
$count = $DB->count_records('role_assignments', ['userid' => $user->id]);
$this->assertEquals(0, $count);
// After deletion, the role_assignments assigned by the user should not have been deleted.
$count = $DB->count_records('role_assignments', ['modifierid' => $user->id]);
$this->assertEquals(2, $count);
}
/**
* Export for a user with a key against a script where no instance is specified.
*/
public function test_export_user_role_to_cohort() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Assign user roles to cohort.
$user = $this->getDataGenerator()->create_user();
$contextuser = \context_user::instance($user->id);
$teacher = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
$cohort = $this->getDataGenerator()->create_cohort();
$userassignover = $this->getDataGenerator()->create_user();
$contextuserassignover = \context_user::instance($userassignover->id);
cohort_add_member($cohort->id, $userassignover->id);
$this->setAdminUser();
$params = (object) array(
'userid' => $user->id,
'roleid' => $teacher->id,
'cohortid' => $cohort->id
);
api::create_cohort_role_assignment($params);
api::sync_all_cohort_roles();
$rolesnames = self::get_roles_name();
$subcontextteacher = [
get_string('privacy:metadata:role_cohortroles', 'core_role'),
$rolesnames[$teacher->id]
];
// Test User is assigned role teacher to cohort.
provider::export_user_role_to_cohort($user->id);
$writer = writer::with_context($contextuserassignover);
$this->assertTrue($writer->has_any_data());
$exported = $writer->get_related_data($subcontextteacher, 'cohortroles');
$this->assertEquals($user->id, reset($exported)->userid);
// Test User is member of a cohort which User2 is assigned to role to this cohort.
$user2 = $this->getDataGenerator()->create_user();
$cohort2 = $this->getDataGenerator()->create_cohort();
cohort_add_member($cohort2->id, $user->id);
$params = (object) array(
'userid' => $user2->id,
'roleid' => $teacher->id,
'cohortid' => $cohort2->id
);
api::create_cohort_role_assignment($params);
api::sync_all_cohort_roles();
provider::export_user_role_to_cohort($user->id);
$writer = writer::with_context($contextuser);
$this->assertTrue($writer->has_any_data());
$exported = $writer->get_related_data($subcontextteacher, 'cohortroles');
$this->assertEquals($user2->id, reset($exported)->userid);
}
/**
* Test for provider::delete_user_role_to_cohort().
*/
public function test_delete_user_role_to_cohort() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Assign user roles to cohort.
$user = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$user3 = $this->getDataGenerator()->create_user();
$user4 = $this->getDataGenerator()->create_user();
$teacher = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
$cohort = $this->getDataGenerator()->create_cohort();
cohort_add_member($cohort->id, $user2->id);
cohort_add_member($cohort->id, $user3->id);
cohort_add_member($cohort->id, $user4->id);
$this->setAdminUser();
$params = (object) array(
'userid' => $user->id,
'roleid' => $teacher->id,
'cohortid' => $cohort->id
);
api::create_cohort_role_assignment($params);
api::sync_all_cohort_roles();
$count = $DB->count_records('role_assignments', ['userid' => $user->id, 'component' => 'tool_cohortroles']);
$this->assertEquals(3, $count);
provider::delete_user_role_to_cohort($user->id);
$count = $DB->count_records('role_assignments', ['userid' => $user->id, 'component' => 'tool_cohortroles']);
$this->assertEquals(0, $count);
}
/**
* Test that only users within a course context are fetched.
*/
public function test_get_users_in_context() {
global $DB;
$this->resetAfterTest();
$component = 'core_role';
$this->setAdminUser();
$admin = \core_user::get_user_by_username('admin');
// Create user1.
$user1 = $this->getDataGenerator()->create_user();
$usercontext1 = \context_user::instance($user1->id);
// Create user2.
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
// Create course1.
$course1 = $this->getDataGenerator()->create_course();
$coursecontext1 = \context_course::instance($course1->id);
// Create course category.
$coursecat = $this->getDataGenerator()->create_category();
$coursecatcontext = \context_coursecat::instance($coursecat->id);
// Create chat module.
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course1->id]);
$cmcontext = \context_module::instance($cm->cmid);
$systemcontext = \context_system::instance();
// Create a block.
$block = $this->getDataGenerator()->create_block('online_users');
$blockcontext = \context_block::instance($block->id);
$studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
// Role assignments CONTEXT_COURSE.
role_assign($studentrole->id, $user1->id, $coursecontext1->id);
role_assign($studentrole->id, $user2->id, $coursecontext1->id);
// Role assignments CONTEXT_COURSECAT.
role_assign($studentrole->id, $user2->id, $coursecatcontext->id);
// Role assignments CONTEXT_SYSTEM.
role_assign($studentrole->id, $user1->id, $systemcontext->id);
// Role assignments CONTEXT_MODULE.
role_assign($studentrole->id, $user2->id, $cmcontext->id);
// Role assigments CONTEXT_BLOCK.
role_assign($studentrole->id, $user1->id, $blockcontext->id);
// Role assigments CONTEXT_USER.
role_assign($managerrole->id, $user1->id, $usercontext2->id);
// Role capabilities.
$this->setUser($user1);
assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $studentrole->id, $cmcontext->id);
// The user list for usercontext1 should not return any users.
$userlist1 = new \core_privacy\local\request\userlist($usercontext1, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(0, $userlist1);
// The user list for usercontext2 should user1 and admin (role creator).
$userlist2 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(2, $userlist2);
$expected = [
$user1->id,
$admin->id
];
$this->assertEquals($expected, $userlist2->get_userids(), '', 0.0, 10, true);
// The user list for coursecontext1 should user1, user2 and admin (role creator).
$userlist3 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(3, $userlist3);
$expected = [
$user1->id,
$user2->id,
$admin->id
];
$this->assertEquals($expected, $userlist3->get_userids(), '', 0.0, 10, true);
// The user list for coursecatcontext should user2 and admin (role creator).
$userlist4 = new \core_privacy\local\request\userlist($coursecatcontext, $component);
provider::get_users_in_context($userlist4);
$this->assertCount(2, $userlist4);
$expected = [
$user2->id,
$admin->id
];
$this->assertEquals($expected, $userlist4->get_userids(), '', 0.0, 10, true);
// The user list for systemcontext should user1 and admin (role creator).
$userlist6 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist6);
$this->assertCount(2, $userlist6);
$expected = [
$user1->id,
$admin->id
];
$this->assertEquals($expected, $userlist6->get_userids(), '', 0.0, 10, true);
// The user list for cmcontext should user1, user2 and admin (role creator).
$userlist7 = new \core_privacy\local\request\userlist($cmcontext, $component);
provider::get_users_in_context($userlist7);
$this->assertCount(3, $userlist7);
$expected = [
$user1->id,
$user2->id,
$admin->id
];
$this->assertEquals($expected, $userlist7->get_userids(), '', 0.0, 10, true);
// The user list for blockcontext should user1 and admin (role creator).
$userlist8 = new \core_privacy\local\request\userlist($blockcontext, $component);
provider::get_users_in_context($userlist8);
$this->assertCount(2, $userlist8);
$expected = [
$user1->id,
$admin->id
];
$this->assertEquals($expected, $userlist8->get_userids(), '', 0.0, 10, true);
}
/**
* Test that data for users in approved userlist is deleted.
*/
public function test_delete_data_for_users() {
global $DB;
$this->resetAfterTest();
$component = 'core_role';
$this->setAdminUser();
$admin = \core_user::get_user_by_username('admin');
// Create user1.
$user1 = $this->getDataGenerator()->create_user();
// Create user2.
$user2 = $this->getDataGenerator()->create_user();
$usercontext2 = \context_user::instance($user2->id);
// Create course1.
$course1 = $this->getDataGenerator()->create_course();
$coursecontext1 = \context_course::instance($course1->id);
// Create course category.
$coursecat = $this->getDataGenerator()->create_category();
$coursecatcontext = \context_coursecat::instance($coursecat->id);
// Create chat module.
$cm = $this->getDataGenerator()->create_module('chat', ['course' => $course1->id]);
$cmcontext = \context_module::instance($cm->cmid);
$systemcontext = \context_system::instance();
// Create a block.
$block = $this->getDataGenerator()->create_block('online_users');
$blockcontext = \context_block::instance($block->id);
$studentrole = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
$managerrole = $DB->get_record('role', array('shortname' => 'manager'), '*', MUST_EXIST);
// Role assignments CONTEXT_COURSE.
role_assign($studentrole->id, $user1->id, $coursecontext1->id);
role_assign($studentrole->id, $user2->id, $coursecontext1->id);
// Role assignments CONTEXT_COURSECAT.
role_assign($studentrole->id, $user2->id, $coursecatcontext->id);
// Role assignments CONTEXT_SYSTEM.
role_assign($studentrole->id, $user1->id, $systemcontext->id);
// Role assignments CONTEXT_MODULE.
role_assign($studentrole->id, $user2->id, $cmcontext->id);
// Role assigments CONTEXT_BLOCK.
role_assign($studentrole->id, $user1->id, $blockcontext->id);
// Role assigments CONTEXT_USER.
role_assign($managerrole->id, $user1->id, $usercontext2->id);
// Role capabilities.
$this->setUser($user1);
assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $studentrole->id, $cmcontext->id);
// The user list for usercontext2 should user1 and admin (role creator).
$userlist1 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(2, $userlist1);
// The user list for coursecontext1 should user1, user2 and admin (role creator).
$userlist2 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(3, $userlist2);
// The user list for coursecatcontext should user2 and admin (role creator).
$userlist3 = new \core_privacy\local\request\userlist($coursecatcontext, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(2, $userlist3);
// The user list for systemcontext should user1 and admin (role creator).
$userlist4 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist4);
$this->assertCount(2, $userlist4);
// The user list for cmcontext should user1, user2 and admin (role creator).
$userlist5 = new \core_privacy\local\request\userlist($cmcontext, $component);
provider::get_users_in_context($userlist5);
$this->assertCount(3, $userlist5);
// The user list for blockcontext should user1 and admin (role creator).
$userlist6 = new \core_privacy\local\request\userlist($blockcontext, $component);
provider::get_users_in_context($userlist6);
$this->assertCount(2, $userlist6);
// Convert $userlist1 into an approved_contextlist.
$approvedlist1 = new approved_userlist($usercontext2, $component, $userlist1->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist1);
// Re-fetch users in usercontext2.
$userlist1 = new \core_privacy\local\request\userlist($usercontext2, $component);
provider::get_users_in_context($userlist1);
$this->assertCount(0, $userlist1);
// Convert $userlist2 into an approved_contextlist.
$approvedlist2 = new approved_userlist($coursecontext1, $component, $userlist2->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist2);
// Re-fetch users in coursecontext1.
$userlist2 = new \core_privacy\local\request\userlist($coursecontext1, $component);
provider::get_users_in_context($userlist2);
$this->assertCount(0, $userlist2);
// Convert $userlist3 into an approved_contextlist.
$approvedlist3 = new approved_userlist($coursecatcontext, $component, $userlist3->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist3);
// Re-fetch users in coursecatcontext.
$userlist3 = new \core_privacy\local\request\userlist($coursecatcontext, $component);
provider::get_users_in_context($userlist3);
$this->assertCount(0, $userlist3);
// Convert $userlist4 into an approved_contextlist.
$approvedlist4 = new approved_userlist($systemcontext, $component, $userlist4->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist4);
// Re-fetch users in systemcontext.
$userlist4 = new \core_privacy\local\request\userlist($systemcontext, $component);
provider::get_users_in_context($userlist4);
// The data from role_capabilities should still be present. The user list should return the admin user.
$this->assertCount(1, $userlist4);
$expected = [$admin->id];
$this->assertEquals($expected, $userlist4->get_userids());
// Convert $userlist5 into an approved_contextlist.
$approvedlist5 = new approved_userlist($cmcontext, $component, $userlist5->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist5);
// Re-fetch users in cmcontext.
$userlist5 = new \core_privacy\local\request\userlist($cmcontext, $component);
provider::get_users_in_context($userlist5);
// The data from role_capabilities should still be present. The user list should return user1.
$this->assertCount(1, $userlist5);
$expected = [$user1->id];
$this->assertEquals($expected, $userlist5->get_userids());
// Convert $userlist6 into an approved_contextlist.
$approvedlist6 = new approved_userlist($blockcontext, $component, $userlist6->get_userids());
// Delete using delete_data_for_user.
provider::delete_data_for_users($approvedlist6);
// Re-fetch users in blockcontext.
$userlist6 = new \core_privacy\local\request\userlist($blockcontext, $component);
provider::get_users_in_context($userlist6);
$this->assertCount(0, $userlist6);
}
/**
* Supoort function to get all the localised roles name
* in a simple array for testing.
*
* @return array Array of name of the roles by roleid.
*/
protected static function get_roles_name() {
$roles = role_fix_names(get_all_roles(), \context_system::instance(), ROLENAME_ORIGINAL);
$rolesnames = array();
foreach ($roles as $role) {
$rolesnames[$role->id] = $role->localname;
}
return $rolesnames;
}
}
+5 -23
View File
@@ -5,22 +5,11 @@
require_once('../config.php');
require_once($CFG->libdir.'/adminlib.php');
redirect_if_major_upgrade_required();
$query = trim(optional_param('query', '', PARAM_NOTAGS)); // Search string
$context = context_system::instance();
$PAGE->set_context($context);
$hassiteconfig = has_capability('moodle/site:config', $context);
if ($hassiteconfig && moodle_needs_upgrading()) {
redirect(new moodle_url('/admin/index.php'));
}
// If site registration needs updating, redirect.
\core\hub\registration::registration_reminder('/admin/search.php');
admin_externalpage_setup('search', '', array('query' => $query)); // now hidden page
$adminroot = admin_get_root(); // need all settings here
@@ -32,16 +21,15 @@ $focus = '';
// now we'll deal with the case that the admin has submitted the form with changed settings
if ($data = data_submitted() and confirm_sesskey() and isset($data->action) and $data->action == 'save-settings') {
require_capability('moodle/site:config', $context);
$count = admin_write_settings($data);
if (admin_write_settings($data)) {
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
}
if (!empty($adminroot->errors)) {
$errormsg = get_string('errorwithsettings', 'admin');
$firsterror = reset($adminroot->errors);
$focus = $firsterror->id;
} else {
// No errors. Did we change any setting? If so, then redirect with success.
if ($count) {
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
}
redirect($PAGE->url);
}
}
@@ -50,12 +38,6 @@ if ($data = data_submitted() and confirm_sesskey() and isset($data->action) and
// to modify them
echo $OUTPUT->header($focus);
// Display a warning if site is not registered.
if (empty($query)) {
$adminrenderer = $PAGE->get_renderer('core', 'admin');
echo $adminrenderer->warn_if_not_registered();
}
echo $OUTPUT->heading(get_string('administrationsite'));
if ($errormsg !== '') {
@@ -67,7 +49,7 @@ if ($errormsg !== '') {
$showsettingslinks = true;
if ($hassiteconfig) {
if (has_capability('moodle/site:config', $context)) {
require_once("admin_settings_search_form.php");
$form = new admin_settings_search_form();
$form->display();
+61 -139
View File
@@ -28,139 +28,85 @@ admin_externalpage_setup('searchareas');
$areaid = optional_param('areaid', null, PARAM_ALPHAEXT);
$action = optional_param('action', null, PARAM_ALPHA);
$indexingenabled = \core_search\manager::is_indexing_enabled(); // This restricts many of the actions on this page.
// Get a search manager instance, which we'll need for display and to handle some actions.
try {
$searchmanager = \core_search\manager::instance();
} catch (core_search\engine_exception $searchmanagererror) {
// In action cases, we'll throw this exception below. In non-action cases, we produce a lang string error.
// Continue, we return an error later depending on the requested action.
}
// Handle all the actions.
echo $OUTPUT->header();
if ($action) {
// If dealing with an areaid, we need to check that the area exists.
require_sesskey();
if ($areaid) {
// We need to check that the area exists.
$area = \core_search\manager::get_search_area($areaid);
if ($area === false) {
throw new moodle_exception('invalidrequest');
}
}
// All the indexing actions.
if (in_array($action, ['delete', 'indexall', 'reindexall', 'deleteall'])) {
// All of these actions require that indexing is enabled.
if ($indexingenabled) {
// For all of these actions, we strictly need a manager instance.
if (isset($searchmanagererror)) {
throw $searchmanagererror;
}
// Show confirm prompt for all these actions as they may be inadvisable, or may cause
// an interruption in search functionality, on production systems.
if (!optional_param('confirm', 0, PARAM_INT)) {
// Display confirmation prompt.
$a = null;
if ($areaid) {
$a = html_writer::tag('strong', $area->get_visible_name());
}
$actionparams = ['sesskey' => sesskey(), 'action' => $action, 'confirm' => 1];
if ($areaid) {
$actionparams['areaid'] = $areaid;
}
$actionurl = new moodle_url('/admin/searchareas.php', $actionparams);
$cancelurl = new moodle_url('/admin/searchareas.php');
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('confirm_' . $action, 'search', $a),
new single_button($actionurl, get_string('continue'), 'post', true),
new single_button($cancelurl, get_string('cancel'), 'get'));
echo $OUTPUT->footer();
exit;
} else {
// Confirmed, so run the required action.
require_sesskey();
switch ($action) {
case 'delete':
$searchmanager->delete_index($areaid);
\core\notification::success(get_string('searchindexdeleted', 'admin'));
break;
case 'indexall':
$searchmanager->index();
\core\notification::success(get_string('searchindexupdated', 'admin'));
break;
case 'reindexall':
$searchmanager->index(true);
\core\notification::success(get_string('searchreindexed', 'admin'));
break;
case 'deleteall':
$searchmanager->delete_index();
\core\notification::success(get_string('searchalldeleted', 'admin'));
break;
default:
break;
}
// Redirect back to the main page after taking action.
redirect(new moodle_url('/admin/searchareas.php'));
}
// All actions but enable/disable need the search engine to be ready.
if ($action !== 'enable' && $action !== 'disable') {
if (!empty($searchmanagererror)) {
throw $searchmanagererror;
}
} else if (in_array($action, ['enable', 'disable'])) {
// Toggling search areas requires no confirmation.
require_sesskey();
}
switch ($action) {
case 'enable':
$area->set_enabled(true);
\core\notification::success(get_string('searchareaenabled', 'admin'));
break;
case 'disable':
$area->set_enabled(false);
core\notification::success(get_string('searchareadisabled', 'admin'));
break;
default:
break;
}
redirect(new moodle_url('/admin/searchareas.php'));
} else {
// Invalid action.
throw new moodle_exception('invalidaction');
switch ($action) {
case 'enable':
$area->set_enabled(true);
echo $OUTPUT->notification(get_string('searchareaenabled', 'admin'), \core\output\notification::NOTIFY_SUCCESS);
break;
case 'disable':
$area->set_enabled(false);
echo $OUTPUT->notification(get_string('searchareadisabled', 'admin'), \core\output\notification::NOTIFY_SUCCESS);
break;
case 'delete':
$search = \core_search\manager::instance();
$search->delete_index($areaid);
echo $OUTPUT->notification(get_string('searchindexdeleted', 'admin'), \core\output\notification::NOTIFY_SUCCESS);
break;
case 'indexall':
$searchmanager->index();
echo $OUTPUT->notification(get_string('searchindexupdated', 'admin'), \core\output\notification::NOTIFY_SUCCESS);
break;
case 'reindexall':
$searchmanager->index(true);
echo $OUTPUT->notification(get_string('searchreindexed', 'admin'), \core\output\notification::NOTIFY_SUCCESS);
break;
case 'deleteall':
$searchmanager->delete_index();
echo $OUTPUT->notification(get_string('searchalldeleted', 'admin'), \core\output\notification::NOTIFY_SUCCESS);
break;
default:
throw new moodle_exception('invalidaction');
break;
}
}
// Display.
if (isset($searchmanager) && $indexingenabled) {
\core\notification::info(get_string('indexinginfo', 'admin'));
} else if (isset($searchmanager)) {
$params = (object) [
'url' => (new moodle_url("/admin/settings.php?section=manageglobalsearch#admin-searchindexwhendisabled"))->out(false)
];
\core\notification::error(get_string('indexwhendisabledfullnotice', 'search', $params));
$searchareas = \core_search\manager::get_search_areas_list();
if (empty($searchmanagererror)) {
$areasconfig = $searchmanager->get_areas_config($searchareas);
} else {
// In non-action cases, init errors are translated and displayed to the user as error notifications.
$errorstr = get_string($searchmanagererror->errorcode, $searchmanagererror->module, $searchmanagererror->a);
\core\notification::error($errorstr);
$areasconfig = false;
}
echo $OUTPUT->header();
if (!empty($searchmanagererror)) {
$errorstr = get_string($searchmanagererror->errorcode, $searchmanagererror->module, $searchmanagererror->a);
echo $OUTPUT->notification($errorstr, \core\output\notification::NOTIFY_ERROR);
} else {
echo $OUTPUT->notification(get_string('indexinginfo', 'admin'), \core\output\notification::NOTIFY_INFO);
}
$table = new html_table();
$table->id = 'core-search-areas';
$table->head = [
get_string('searcharea', 'search'),
get_string('enable'),
get_string('newestdocindexed', 'admin'),
get_string('searchlastrun', 'admin'),
get_string('searchindexactions', 'admin')
];
$searchareas = \core_search\manager::get_search_areas_list();
$areasconfig = isset($searchmanager) ? $searchmanager->get_areas_config($searchareas) : false;
$table->head = array(get_string('searcharea', 'search'), get_string('enable'), get_string('newestdocindexed', 'admin'),
get_string('searchlastrun', 'admin'), get_string('searchindexactions', 'admin'));
foreach ($searchareas as $area) {
$areaid = $area->get_area_id();
$columns = array(new html_table_cell($area->get_visible_name()));
@@ -170,7 +116,7 @@ foreach ($searchareas as $area) {
new pix_icon('t/hide', get_string('disable'), 'moodle', array('title' => '', 'class' => 'iconsmall')),
null, array('title' => get_string('disable')));
if ($areasconfig && $indexingenabled) {
if ($areasconfig) {
$columns[] = $areasconfig[$areaid]->lastindexrun;
if ($areasconfig[$areaid]->indexingstart) {
@@ -179,31 +125,14 @@ foreach ($searchareas as $area) {
$areasconfig[$areaid]->docsprocessed . ' , ' .
$areasconfig[$areaid]->recordsprocessed . ' , ' .
$areasconfig[$areaid]->docsignored;
if ($areasconfig[$areaid]->partial) {
$laststatus .= ' ' . get_string('searchpartial', 'admin');
}
} else {
$laststatus = '';
}
$columns[] = $laststatus;
$accesshide = html_writer::span($area->get_visible_name(), 'accesshide');
$actions = [];
$actions[] = $OUTPUT->pix_icon('t/delete', '') .
html_writer::link(admin_searcharea_action_url('delete', $areaid),
get_string('deleteindex', 'search', $accesshide));
if ($area->supports_get_document_recordset()) {
$actions[] = $OUTPUT->pix_icon('i/reload', '') . html_writer::link(
new moodle_url('searchreindex.php', ['areaid' => $areaid]),
get_string('gradualreindex', 'search', $accesshide));
}
$columns[] = html_writer::alist($actions, ['class' => 'unstyled list-unstyled']);
$columns[] = html_writer::link(admin_searcharea_action_url('delete', $areaid), 'Delete index');
} else {
if (!$areasconfig) {
$blankrow = new html_table_cell(get_string('searchnotavailable', 'admin'));
} else {
$blankrow = new html_table_cell(get_string('indexwhendisabledshortnotice', 'search'));
}
$blankrow = new html_table_cell(get_string('searchnotavailable', 'admin'));
$blankrow->colspan = 3;
$columns[] = $blankrow;
}
@@ -222,7 +151,10 @@ foreach ($searchareas as $area) {
}
// Cross-search area tasks.
$options = (isset($searchmanager) && $indexingenabled) ? [] : ['disabled' => true];
$options = array();
if (!empty($searchmanagererror)) {
$options['disabled'] = true;
}
echo $OUTPUT->box_start('search-areas-actions');
echo $OUTPUT->single_button(admin_searcharea_action_url('indexall'), get_string('searchupdateindex', 'admin'), 'get', $options);
echo $OUTPUT->single_button(admin_searcharea_action_url('reindexall'), get_string('searchreindexindex', 'admin'), 'get', $options);
@@ -230,13 +162,6 @@ echo $OUTPUT->single_button(admin_searcharea_action_url('deleteall'), get_string
echo $OUTPUT->box_end();
echo html_writer::table($table);
if (isset($searchmanager)) {
// Show information about queued index requests for specific contexts.
$searchrenderer = $PAGE->get_renderer('core_search');
echo $searchrenderer->render_index_requests_info($searchmanager->get_index_requests_info());
}
echo $OUTPUT->footer();
/**
@@ -247,12 +172,9 @@ echo $OUTPUT->footer();
* @return moodle_url
*/
function admin_searcharea_action_url($action, $areaid = false) {
$params = array('action' => $action);
$params = array('action' => $action, 'sesskey' => sesskey());
if ($areaid) {
$params['areaid'] = $areaid;
}
if ($action === 'disable' || $action === 'enable') {
$params['sesskey'] = sesskey();
}
return new moodle_url('/admin/searchareas.php', $params);
}
-87
View File
@@ -1,87 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Adds a search area to the queue for indexing.
*
* @package core_search
* @copyright 2017 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('NO_OUTPUT_BUFFERING', true);
require(__DIR__ . '/../config.php');
// Check access.
require_once($CFG->libdir . '/adminlib.php');
admin_externalpage_setup('searchareas', '', null, (new moodle_url('/admin/searchreindex.php'))->out(false));
// Get area parameter and check it exists.
$areaid = required_param('areaid', PARAM_ALPHAEXT);
$area = \core_search\manager::get_search_area($areaid);
if ($area === false) {
throw new moodle_exception('invalidrequest');
}
$areaname = $area->get_visible_name();
// Start page output.
$heading = get_string('gradualreindex', 'search', '');
$PAGE->set_title($PAGE->title . ': ' . $heading);
$PAGE->navbar->add($heading);
echo $OUTPUT->header();
echo $OUTPUT->heading($heading);
// If sesskey is supplied, actually carry out the action.
if (optional_param('sesskey', '', PARAM_ALPHANUM)) {
require_sesskey();
// Get all contexts for search area. This query can take time in large cases.
\core_php_time_limit::raise(0);
$contextiterator = $area->get_contexts_to_reindex();
$progress = new \core\progress\display_if_slow('');
$progress->start_progress($areaname);
// Request reindexing for each context (with low priority).
$count = 0;
foreach ($contextiterator as $context) {
\core_php_time_limit::raise(30);
\core_search\manager::request_index($context, $area->get_area_id(),
\core_search\manager::INDEX_PRIORITY_REINDEXING);
$progress->progress();
$count++;
}
// Unset the iterator which should close the recordset (if there is one).
unset($contextiterator);
$progress->end_progress();
$a = (object)['name' => html_writer::tag('strong', $areaname), 'count' => $count];
echo $OUTPUT->box(get_string('gradualreindex_queued', 'search', $a));
echo $OUTPUT->continue_button(new moodle_url('/admin/searchareas.php'));
} else {
// Display confirmation prompt.
echo $OUTPUT->confirm(get_string('gradualreindex_confirm', 'search', html_writer::tag('strong', $areaname)),
new single_button(new moodle_url('/admin/searchreindex.php', ['areaid' => $areaid,
'sesskey' => sesskey()]), get_string('continue'), 'post', true),
new single_button(new moodle_url('/admin/searchareas.php'), get_string('cancel'), 'get'));
}
echo $OUTPUT->footer();
+4 -9
View File
@@ -38,17 +38,12 @@ if (!($settingspage->check_access())) {
$statusmsg = '';
$errormsg = '';
// Form is submitted with changed settings. Do not want to execute when modifying a block.
if ($data = data_submitted() and confirm_sesskey() and isset($data->action) and $data->action == 'save-settings') {
if ($data = data_submitted() and confirm_sesskey()) {
if (admin_write_settings($data)) {
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
}
$count = admin_write_settings($data);
// Regardless of whether any setting change was written (a positive count), check validation errors for those that didn't.
if (empty($adminroot->errors)) {
// No errors. Did we change any setting? If so, then redirect with success.
if ($count) {
redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
}
// We didn't change a setting.
switch ($return) {
case 'site': redirect("$CFG->wwwroot/");
case 'admin': redirect("$CFG->wwwroot/$CFG->admin/");
-110
View File
@@ -1,110 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Adds settings links to admin tree.
*
* @package core_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
if ($hassiteconfig) {
$settings = new admin_settingpage('analyticssettings', new lang_string('analyticssettings', 'analytics'));
$ADMIN->add('analytics', $settings);
if ($ADMIN->fulltree) {
// Select the site prediction's processor.
$predictionprocessors = \core_analytics\manager::get_all_prediction_processors();
$predictors = array();
foreach ($predictionprocessors as $fullclassname => $predictor) {
$pluginname = substr($fullclassname, 1, strpos($fullclassname, '\\', 1) - 1);
$predictors[$fullclassname] = new lang_string('pluginname', $pluginname);
}
$settings->add(new \core_analytics\admin_setting_predictor('analytics/predictionsprocessor',
new lang_string('predictionsprocessor', 'analytics'), new lang_string('predictionsprocessor_help', 'analytics'),
'\mlbackend_php\processor', $predictors)
);
// Log store.
$logmanager = get_log_manager();
$readers = $logmanager->get_readers('core\log\sql_reader');
$options = array();
$defaultreader = null;
foreach ($readers as $plugin => $reader) {
if (!$reader->is_logging()) {
continue;
}
if (!isset($defaultreader)) {
// The top one as default reader.
$defaultreader = $plugin;
}
$options[$plugin] = $reader->get_name();
}
if (empty($defaultreader)) {
// We fall here during initial site installation because log stores are not
// enabled until admin/tool/log/db/install.php is executed and get_readers
// return nothing.
if ($enabledlogstores = get_config('tool_log', 'enabled_stores')) {
$enabledlogstores = explode(',', $enabledlogstores);
$defaultreader = reset($enabledlogstores);
// No need to set the correct name, just the value, this will not be displayed.
$options[$defaultreader] = $defaultreader;
}
}
$settings->add(new admin_setting_configselect('analytics/logstore',
new lang_string('analyticslogstore', 'analytics'), new lang_string('analyticslogstore_help', 'analytics'),
$defaultreader, $options));
// Enable/disable time splitting methods.
$alltimesplittings = \core_analytics\manager::get_all_time_splittings();
$timesplittingoptions = array();
$timesplittingdefaults = array('\core\analytics\time_splitting\quarters_accum',
'\core\analytics\time_splitting\quarters', '\core\analytics\time_splitting\single_range');
foreach ($alltimesplittings as $key => $timesplitting) {
$timesplittingoptions[$key] = $timesplitting->get_name();
}
$settings->add(new admin_setting_configmultiselect('analytics/timesplittings',
new lang_string('enabledtimesplittings', 'analytics'), new lang_string('timesplittingmethod_help', 'analytics'),
$timesplittingdefaults, $timesplittingoptions)
);
// Predictions processor output dir.
$defaultmodeloutputdir = rtrim($CFG->dataroot, '/') . DIRECTORY_SEPARATOR . 'models';
if (empty(get_config('analytics', 'modeloutputdir')) && !file_exists($defaultmodeloutputdir) &&
is_writable($defaultmodeloutputdir)) {
// Automatically create the dir for them so users don't see the invalid value red cross.
mkdir($defaultmodeloutputdir, $CFG->directorypermissions, true);
}
$settings->add(new admin_setting_configdirectory('analytics/modeloutputdir', new lang_string('modeloutputdir', 'analytics'),
new lang_string('modeloutputdirinfo', 'analytics'), $defaultmodeloutputdir));
// Disable web interface evaluation and get predictions.
$settings->add(new admin_setting_configcheckbox('analytics/onlycli', new lang_string('onlycli', 'analytics'),
new lang_string('onlycliinfo', 'analytics'), 1));
// Training and prediction time limit per model.
$settings->add(new admin_setting_configduration('analytics/modeltimelimit', new lang_string('modeltimelimit', 'analytics'),
new lang_string('modeltimelimitinfo', 'analytics'), 20 * MINSECS));
}
}
+2 -3
View File
@@ -22,7 +22,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
$temp->add(new admin_setting_configcheckbox('allowuserthemes', new lang_string('allowuserthemes', 'admin'), new lang_string('configallowuserthemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowcoursethemes', new lang_string('allowcoursethemes', 'admin'), new lang_string('configallowcoursethemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowcategorythemes', new lang_string('allowcategorythemes', 'admin'), new lang_string('configallowcategorythemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowcohortthemes', new lang_string('allowcohortthemes', 'admin'), new lang_string('configallowcohortthemes', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowthemechangeonurl', new lang_string('allowthemechangeonurl', 'admin'), new lang_string('configallowthemechangeonurl', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'), new lang_string('configallowuserblockhiding', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('allowblockstodock', new lang_string('allowblockstodock', 'admin'), new lang_string('configallowblockstodock', 'admin'), 1));
@@ -184,7 +183,7 @@ preferences,moodle|/user/preferences.php|preferences',
new lang_string('confignavcourselimit', 'admin'), 10, PARAM_INT));
$temp->add(new admin_setting_configcheckbox('usesitenameforsitepages', new lang_string('usesitenameforsitepages', 'admin'), new lang_string('configusesitenameforsitepages', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('linkadmincategories', new lang_string('linkadmincategories', 'admin'), new lang_string('linkadmincategories_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('linkcoursesections', new lang_string('linkcoursesections', 'admin'), new lang_string('linkcoursesections_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('linkcoursesections', new lang_string('linkcoursesections', 'admin'), new lang_string('linkcoursesections_help', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('navshowfrontpagemods', new lang_string('navshowfrontpagemods', 'admin'), new lang_string('navshowfrontpagemods_help', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('navadduserpostslinks', new lang_string('navadduserpostslinks', 'admin'), new lang_string('navadduserpostslinks_help', 'admin'), 1));
@@ -200,7 +199,7 @@ preferences,moodle|/user/preferences.php|preferences',
// "documentation" settingpage
$temp = new admin_settingpage('documentation', new lang_string('moodledocs'));
$temp->add(new admin_setting_configtext('docroot', new lang_string('docroot', 'admin'), new lang_string('configdocroot', 'admin'), 'https://docs.moodle.org', PARAM_URL));
$temp->add(new admin_setting_configtext('docroot', new lang_string('docroot', 'admin'), new lang_string('configdocroot', 'admin'), 'http://docs.moodle.org', PARAM_URL));
$ltemp = array('' => get_string('forceno'));
$ltemp += get_string_manager()->get_list_of_translations(true);
$temp->add(new admin_setting_configselect('doclang', get_string('doclang', 'admin'), get_string('configdoclang', 'admin'), '', $ltemp));
+1 -4
View File
@@ -92,9 +92,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
$temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'),
new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));
$temp->add(new admin_setting_configcheckbox('moodlecourse/courseenddateenabled', get_string('courseenddateenabled'),
get_string('courseenddateenabled_desc'), 1));
$temp->add(new admin_setting_configduration('moodlecourse/courseduration', get_string('courseduration'),
get_string('courseduration_desc'), YEARSECS));
@@ -325,7 +322,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_skip_modif_prev', new lang_string('skipmodifprev', 'backup'), new lang_string('skipmodifprevhelp', 'backup'), 0));
// Automated defaults section.
$temp->add(new admin_setting_heading('automatedsettings', new lang_string('automatedsettings','backup'), new lang_string('recyclebin_desc', 'backup')));
$temp->add(new admin_setting_heading('automatedsettings', new lang_string('automatedsettings','backup'), ''));
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_users', new lang_string('generalusers', 'backup'), new lang_string('configgeneralusers', 'backup'), 1));
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_role_assignments', new lang_string('generalroleassignments','backup'), new lang_string('configgeneralroleassignments','backup'), 1));
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_activities', new lang_string('generalactivities','backup'), new lang_string('configgeneralactivities','backup'), 1));
+1 -8
View File
@@ -14,11 +14,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$temp->add(new admin_setting_configcheckbox('dndallowtextandlinks', new lang_string('dndallowtextandlinks', 'admin'), new lang_string('configdndallowtextandlinks', 'admin'), 0));
$temp->add(new admin_setting_configexecutable('pathtosassc', new lang_string('pathtosassc', 'admin'), new lang_string('pathtosassc_help', 'admin'), ''));
$temp->add(new admin_setting_configcheckbox('forceclean', new lang_string('forceclean', 'core_admin'),
new lang_string('forceclean_desc', 'core_admin'), 0));
$ADMIN->add('experimental', $temp);
// "debugging" settingpage
@@ -33,9 +28,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$ADMIN->add('development', $temp);
// "Profiling" settingpage (conditionally if the 'xhprof' extension is available only).
$xhprofenabled = extension_loaded('tideways_xhprof');
$xhprofenabled = $xhprofenabled || extension_loaded('tideways');
$xhprofenabled = $xhprofenabled || extension_loaded('xhprof');
$xhprofenabled = extension_loaded('xhprof') || extension_loaded('tideways');
$temp = new admin_settingpage('profiling', new lang_string('profiling', 'admin'), 'moodle/site:config', !$xhprofenabled);
// Main profiling switch.
$temp->add(new admin_setting_configcheckbox('profilingenabled', new lang_string('profilingenabled', 'admin'), new lang_string('profilingenabled_help', 'admin'), false));
-3
View File
@@ -42,9 +42,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
// enable publishing in exports/imports
$temp->add(new admin_setting_configcheckbox('gradepublishing', new lang_string('gradepublishing', 'grades'), new lang_string('gradepublishing_help', 'grades'), 0));
$temp->add(new admin_setting_configcheckbox('grade_export_exportfeedback', new lang_string('exportfeedback', 'grades'),
new lang_string('exportfeedback_desc', 'grades'), 0));
$temp->add(new admin_setting_configselect('grade_export_displaytype', new lang_string('gradeexportdisplaytype', 'grades'),
new lang_string('gradeexportdisplaytype_desc', 'grades'), GRADE_DISPLAY_TYPE_REAL, $display_types));
+2 -17
View File
@@ -102,7 +102,7 @@ if ($hassiteconfig) {
$temp->add(new admin_setting_configtext('alternateloginurl', new lang_string('alternateloginurl', 'auth'),
new lang_string('alternatelogin', 'auth', htmlspecialchars(get_login_url())), ''));
$temp->add(new admin_setting_configtext('forgottenpasswordurl', new lang_string('forgottenpasswordurl', 'auth'),
new lang_string('forgottenpassword', 'auth'), '', PARAM_URL));
new lang_string('forgottenpassword', 'auth'), ''));
$temp->add(new admin_setting_confightmleditor('auth_instructions', new lang_string('instructions', 'auth'),
new lang_string('authinstructions', 'auth'), ''));
$setting = new admin_setting_configtext('allowemailaddresses', new lang_string('allowemailaddresses', 'admin'),
@@ -556,22 +556,7 @@ if ($hassiteconfig) {
// Search engine selection.
$temp->add(new admin_setting_heading('searchengineheading', new lang_string('searchengine', 'admin'), ''));
$temp->add(new admin_setting_configselect('searchengine',
new lang_string('selectsearchengine', 'admin'), '', 'simpledb', $engines));
$temp->add(new admin_setting_heading('searchoptionsheading', new lang_string('searchoptions', 'admin'), ''));
$temp->add(new admin_setting_configcheckbox('searchindexwhendisabled',
new lang_string('searchindexwhendisabled', 'admin'), new lang_string('searchindexwhendisabled_desc', 'admin'),
0));
$temp->add(new admin_setting_configduration('searchindextime',
new lang_string('searchindextime', 'admin'), new lang_string('searchindextime_desc', 'admin'),
600));
$options = [
0 => new lang_string('searchallavailablecourses_off', 'admin'),
1 => new lang_string('searchallavailablecourses_on', 'admin')
];
$temp->add(new admin_setting_configselect('searchallavailablecourses',
new lang_string('searchallavailablecourses', 'admin'),
new lang_string('searchallavailablecourses_desc', 'admin'),
0, $options));
new lang_string('selectsearchengine', 'admin'), '', 'solr', $engines));
$ADMIN->add('searchplugins', $temp);
$ADMIN->add('searchplugins', new admin_externalpage('searchareas', new lang_string('searchareas', 'admin'),
+3 -11
View File
@@ -18,11 +18,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$temp->add(new admin_setting_configcheckbox('forceloginforprofiles', new lang_string('forceloginforprofiles', 'admin'), new lang_string('configforceloginforprofiles', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('forceloginforprofileimage', new lang_string('forceloginforprofileimage', 'admin'), new lang_string('forceloginforprofileimage_help', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('opentogoogle', new lang_string('opentogoogle', 'admin'), new lang_string('configopentogoogle', 'admin'), 0));
$temp->add(new admin_setting_configselect('allowindexing', new lang_string('allowindexing', 'admin'), new lang_string('allowindexing_desc', 'admin'),
0,
array(0 => new lang_string('allowindexingexceptlogin', 'admin'),
1 => new lang_string('allowindexingeverywhere', 'admin'),
2 => new lang_string('allowindexingnowhere', 'admin'))));
$temp->add(new admin_setting_pickroles('profileroles',
new lang_string('profileroles','admin'),
new lang_string('configprofileroles', 'admin'),
@@ -54,7 +49,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
3600 => new lang_string('numminutes', '', 60))));
$temp->add(new admin_setting_configcheckbox('extendedusernamechars', new lang_string('extendedusernamechars', 'admin'), new lang_string('configextendedusernamechars', 'admin'), 0));
$temp->add(new admin_setting_configtext('sitepolicy', new lang_string('sitepolicy', 'admin'), new lang_string('sitepolicy_help', 'admin'), '', PARAM_RAW));
$temp->add(new admin_setting_configtext('sitepolicyguest', new lang_string('sitepolicyguest', 'admin'), new lang_string('sitepolicyguest_help', 'admin'), (isset($CFG->sitepolicy) ? $CFG->sitepolicy : ''), PARAM_RAW));
$temp->add(new admin_setting_configcheckbox('extendedusernamechars', new lang_string('extendedusernamechars', 'admin'), new lang_string('configextendedusernamechars', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('keeptagnamecase', new lang_string('keeptagnamecase','admin'),new lang_string('configkeeptagnamecase', 'admin'),'1'));
@@ -107,10 +103,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
new lang_string('passwordchangetokendeletion', 'admin'),
new lang_string('passwordchangetokendeletion_desc', 'admin'), 0));
$temp->add(new admin_setting_configduration('tokenduration',
new lang_string('tokenduration', 'admin'),
new lang_string('tokenduration_desc', 'admin'), 12 * WEEKSECS, WEEKSECS));
$temp->add(new admin_setting_configcheckbox('groupenrolmentkeypolicy', new lang_string('groupenrolmentkeypolicy', 'admin'), new lang_string('groupenrolmentkeypolicy_desc', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('disableuserimages', new lang_string('disableuserimages', 'admin'), new lang_string('configdisableuserimages', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('emailchangeconfirmation', new lang_string('emailchangeconfirmation', 'admin'), new lang_string('configemailchangeconfirmation', 'admin'), 1));
@@ -123,7 +115,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
// "httpsecurity" settingpage
$temp = new admin_settingpage('httpsecurity', new lang_string('httpsecurity', 'admin'));
$temp->add(new admin_setting_configcheckbox('loginhttps', new lang_string('loginhttps', 'admin'), new lang_string('configloginhttps', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('cookiesecure', new lang_string('cookiesecure', 'admin'), new lang_string('configcookiesecure', 'admin'), 1));
$temp->add(new admin_setting_configcheckbox('cookiehttponly', new lang_string('cookiehttponly', 'admin'), new lang_string('configcookiehttponly', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('allowframembedding', new lang_string('allowframembedding', 'admin'), new lang_string('allowframembedding_help', 'admin'), 0));
+4 -4
View File
@@ -7,14 +7,11 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
// "systempaths" settingpage
$temp = new admin_settingpage('systempaths', new lang_string('systempaths','admin'));
$temp->add(new admin_setting_configexecutable('pathtophp', new lang_string('pathtophp', 'admin'),
new lang_string('configpathtophp', 'admin'), ''));
$temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('pathtodu', 'admin'), new lang_string('configpathtodu', 'admin'), ''));
$temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'), new lang_string('edhelpaspellpath'), ''));
$temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'), new lang_string('pathtodot_help', 'admin'), ''));
$temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'), new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
$temp->add(new admin_setting_configexecutable('pathtopython', new lang_string('pathtopython', 'admin'),
new lang_string('pathtopythondesc', 'admin'), ''));
$ADMIN->add('server', $temp);
@@ -212,6 +209,9 @@ $temp->add(new admin_setting_configtext('curltimeoutkbitrate', new lang_string('
$ADMIN->add('server', $temp);
$ADMIN->add('server', new admin_externalpage('adminregistration', new lang_string('hubs', 'admin'),
"$CFG->wwwroot/$CFG->admin/registration/index.php"));
// E-mail settings.
$ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));
+4 -22
View File
@@ -15,28 +15,10 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$optionalsubsystems->add(new admin_setting_configcheckbox('messaging', new lang_string('messaging', 'admin'), new lang_string('configmessaging','admin'), 1));
$options = array(
DAYSECS => new lang_string('secondstotime86400'),
WEEKSECS => new lang_string('secondstotime604800'),
2620800 => new lang_string('nummonths', 'moodle', 1),
7862400 => new lang_string('nummonths', 'moodle', 3),
15724800 => new lang_string('nummonths', 'moodle', 6),
0 => new lang_string('never')
);
$optionalsubsystems->add(new admin_setting_configselect(
'messagingdeletereadnotificationsdelay',
new lang_string('messagingdeletereadnotificationsdelay', 'admin'),
new lang_string('configmessagingdeletereadnotificationsdelay', 'admin'),
604800,
$options)
);
$optionalsubsystems->add(new admin_setting_configselect(
'messagingdeleteallnotificationsdelay',
new lang_string('messagingdeleteallnotificationsdelay', 'admin'),
new lang_string('configmessagingdeleteallnotificationsdelay', 'admin'),
2620800,
$options)
);
$optionalsubsystems->add(new admin_setting_configcheckbox('messaginghidereadnotifications', new lang_string('messaginghidereadnotifications', 'admin'), new lang_string('configmessaginghidereadnotifications','admin'), 0));
$options = array(DAYSECS=>new lang_string('secondstotime86400'), WEEKSECS=>new lang_string('secondstotime604800'), 2620800=>new lang_string('nummonths', 'moodle', 1), 15724800=>new lang_string('nummonths', 'moodle', 6),0=>new lang_string('never'));
$optionalsubsystems->add(new admin_setting_configselect('messagingdeletereadnotificationsdelay', new lang_string('messagingdeletereadnotificationsdelay', 'admin'), new lang_string('configmessagingdeletereadnotificationsdelay', 'admin'), 604800, $options));
$optionalsubsystems->add(new admin_setting_configcheckbox('messagingallowemailoverride', new lang_string('messagingallowemailoverride', 'admin'), new lang_string('configmessagingallowemailoverride','admin'), 0));
+8 -2
View File
@@ -11,7 +11,14 @@ $hassiteconfig = has_capability('moodle/site:config', $systemcontext);
$ADMIN->add('root', new admin_externalpage('adminnotifications', new lang_string('notifications'), "$CFG->wwwroot/$CFG->admin/index.php"));
$ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_string('registration', 'admin'),
new moodle_url("/admin/registration/index.php")));
"$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.org&sesskey=" . sesskey()));
$ADMIN->add('root', new admin_externalpage('registrationhub', new lang_string('registerwith', 'hub'),
"$CFG->wwwroot/$CFG->admin/registration/register.php", 'moodle/site:config', true));
$ADMIN->add('root', new admin_externalpage('registrationhubs', new lang_string('hubs', 'admin'),
"$CFG->wwwroot/$CFG->admin/registration/index.php", 'moodle/site:config', true));
$ADMIN->add('root', new admin_externalpage('siteregistrationconfirmed',
new lang_string('registrationconfirmed', 'hub'),
$CFG->wwwroot."/".$CFG->admin."/registration/confirmregistration.php", 'moodle/site:config', true));
// hidden upgrade script
$ADMIN->add('root', new admin_externalpage('upgradesettings', new lang_string('upgradesettings', 'admin'), "$CFG->wwwroot/$CFG->admin/upgradesettings.php", 'moodle/site:config', true));
@@ -23,7 +30,6 @@ if ($hassiteconfig) {
$ADMIN->add('root', new admin_category('users', new lang_string('users','admin')));
$ADMIN->add('root', new admin_category('courses', new lang_string('courses','admin')));
$ADMIN->add('root', new admin_category('grades', new lang_string('grades')));
$ADMIN->add('root', new admin_category('analytics', new lang_string('analytics', 'analytics')));
$ADMIN->add('root', new admin_category('competencies', new lang_string('competencies', 'core_competency')));
$ADMIN->add('root', new admin_category('badges', new lang_string('badges'), empty($CFG->enablebadges)));
$ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
+7 -51
View File
@@ -4,7 +4,6 @@
$ADMIN->add('users', new admin_category('accounts', new lang_string('accounts', 'admin')));
$ADMIN->add('users', new admin_category('roles', new lang_string('permissions', 'role')));
$ADMIN->add('users', new admin_category('privacy', new lang_string('privacyandpolicies', 'admin')));
if ($hassiteconfig
or has_capability('moodle/user:create', $systemcontext)
@@ -16,10 +15,15 @@ if ($hassiteconfig
or has_capability('moodle/cohort:view', $systemcontext)) { // speedup for non-admins, add all caps used on this page
if (empty($CFG->loginhttps)) {
$securewwwroot = $CFG->wwwroot;
} else {
$securewwwroot = str_replace('http:','https:',$CFG->wwwroot);
}
// stuff under the "accounts" subcategory
$ADMIN->add('accounts', new admin_externalpage('editusers', new lang_string('userlist','admin'), "$CFG->wwwroot/$CFG->admin/user.php", array('moodle/user:update', 'moodle/user:delete')));
$ADMIN->add('accounts', new admin_externalpage('userbulk', new lang_string('userbulk','admin'), "$CFG->wwwroot/$CFG->admin/user/user_bulk.php", array('moodle/user:update', 'moodle/user:delete')));
$ADMIN->add('accounts', new admin_externalpage('addnewuser', new lang_string('addnewuser'), "$CFG->wwwroot/user/editadvanced.php?id=-1", 'moodle/user:create'));
$ADMIN->add('accounts', new admin_externalpage('addnewuser', new lang_string('addnewuser'), "$securewwwroot/user/editadvanced.php?id=-1", 'moodle/user:create'));
// "User default preferences" settingpage.
$temp = new admin_settingpage('userdefaultpreferences', new lang_string('userdefaultpreferences', 'admin'));
@@ -29,7 +33,7 @@ if ($hassiteconfig
$choices['1'] = new lang_string('emaildisplayyes');
$choices['2'] = new lang_string('emaildisplaycourse');
$temp->add(new admin_setting_configselect('defaultpreference_maildisplay', new lang_string('emaildisplay'),
new lang_string('emaildisplay_help'), 2, $choices));
'', 2, $choices));
$choices = array();
$choices['0'] = new lang_string('textformat');
@@ -151,7 +155,6 @@ if ($hassiteconfig
$temp->add(new admin_setting_configmultiselect('hiddenuserfields', new lang_string('hiddenuserfields', 'admin'),
new lang_string('confighiddenuserfields', 'admin'), array(),
array('description' => new lang_string('description'),
'email' => new lang_string('email'),
'city' => new lang_string('city'),
'country' => new lang_string('country'),
'timezone' => new lang_string('timezone'),
@@ -186,8 +189,6 @@ if ($hassiteconfig
'phone2' => new lang_string('phone2'),
'department' => new lang_string('department'),
'institution' => new lang_string('institution'),
'city' => new lang_string('city'),
'country' => new lang_string('country'),
)));
$setting = new admin_setting_configtext('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'),
new lang_string('configfullnamedisplay', 'admin'), 'language', PARAM_TEXT, 50);
@@ -211,48 +212,3 @@ if ($hassiteconfig
$ADMIN->add('roles', new admin_externalpage('checkpermissions', new lang_string('checkglobalpermissions', 'role'), "$CFG->wwwroot/$CFG->admin/roles/check.php?contextid=".$systemcontext->id, array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:manage')));
} // end of speedup
// Privacy settings.
if ($hassiteconfig) {
$temp = new admin_settingpage('privacysettings', new lang_string('privacysettings', 'admin'));
$options = array(
0 => get_string('no'),
1 => get_string('yes')
);
$url = new moodle_url('/admin/settings.php?section=supportcontact');
$url = $url->out();
$setting = new admin_setting_configselect('agedigitalconsentverification',
new lang_string('agedigitalconsentverification', 'admin'),
new lang_string('agedigitalconsentverification_desc', 'admin', $url), 0, $options);
$setting->set_force_ltr(true);
$temp->add($setting);
// See {@link https://gdpr-info.eu/art-8-gdpr/}.
$ageofdigitalconsentmap = implode(PHP_EOL, [
'*, 16',
'AT, 14',
'ES, 14',
'US, 13'
]);
$setting = new admin_setting_agedigitalconsentmap('agedigitalconsentmap',
new lang_string('ageofdigitalconsentmap', 'admin'),
new lang_string('ageofdigitalconsentmap_desc', 'admin'),
$ageofdigitalconsentmap,
PARAM_RAW
);
$temp->add($setting);
$ADMIN->add('privacy', $temp);
// Policy settings.
$temp = new admin_settingpage('policysettings', new lang_string('policysettings', 'admin'));
$temp->add(new admin_settings_sitepolicy_handler_select('sitepolicyhandler', new lang_string('sitepolicyhandler', 'core_admin'),
new lang_string('sitepolicyhandler_desc', 'core_admin')));
$temp->add(new admin_setting_configtext('sitepolicy', new lang_string('sitepolicy', 'core_admin'),
new lang_string('sitepolicy_help', 'core_admin'), '', PARAM_RAW));
$temp->add(new admin_setting_configtext('sitepolicyguest', new lang_string('sitepolicyguest', 'core_admin'),
new lang_string('sitepolicyguest_help', 'core_admin'), (isset($CFG->sitepolicy) ? $CFG->sitepolicy : ''), PARAM_RAW));
$ADMIN->add('privacy', $temp);
}
@@ -1,52 +0,0 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_admin/setting_filetypes
Renders the admin_setting_filetypes setting element.
Context variables required for this template:
* id - element id
* name - form element name
* value - element value
* descriptions - data for the core_form/filetypes-descriptions template
Example context (json):
{
"id": "test0",
"name": "test",
"value": ".jpg,.gif",
"descriptions": {
"hasdescriptions": true,
"descriptions": [
{
"description": "Image (JPEG)",
"extensions": ".jpeg .jpe .jpg"
},
{
"description": "Image (GIF)",
"extensions": ".gif"
}
]
}
}
}}
<div class="form-text defaultsnext">
<input type="text" name="{{name}}" value="{{value}}" size="30" id="{{id}}" class="text-ltr">
<span data-filetypesbrowser="{{id}}"></span>
<div data-filetypesdescriptions="{{id}}">{{#descriptions}}{{>core_form/filetypes-descriptions}}{{/descriptions}}</div>
</div>
-1
View File
@@ -40,7 +40,6 @@
<div class="settingsform clearfix">
{{#params}}
<input type="hidden" name="{{name}}" value="{{value}}">
<input type="hidden" name="action" value="save-settings">
{{/params}}
<input type="hidden" name="sesskey" value="{{sesskey}}">
<input type="hidden" name="return" value="{{return}}">
+29 -5
View File
@@ -48,6 +48,7 @@ class behat_admin extends behat_base {
* @param TableNode $table
*/
public function i_set_the_following_administration_settings_values(TableNode $table) {
if (!$data = $table->getRowsHash()) {
return;
}
@@ -56,12 +57,17 @@ class behat_admin extends behat_base {
// We expect admin block to be visible, otherwise go to homepage.
if (!$this->getSession()->getPage()->find('css', '.block_settings')) {
$this->execute('behat_forms::i_am_on_homepage');
$this->getSession()->visit($this->locate_path('/'));
$this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
}
// Search by label.
$this->execute('behat_forms::i_set_the_field_to', [get_string('searchinsettings', 'admin'), $label]);
$this->execute("behat_general::i_click_on_in_the", [get_string('search', 'admin'), 'button', '.block_settings', 'css_element']);
$searchbox = $this->find_field(get_string('searchinsettings', 'admin'));
$searchbox->setValue($label);
$submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]');
$submitsearch->press();
$this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
// Admin settings does not use the same DOM structure than other moodle forms
// but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
@@ -77,17 +83,35 @@ class behat_admin extends behat_base {
"@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]";
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
"/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div");
} catch (ElementNotFoundException $e) {
// Multi element settings, interacting only the first one.
$fieldxpath = "//*[label[normalize-space(.)= $label]|span[normalize-space(.)= $label]]/" .
"ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
"/descendant::div[@class='form-group']/descendant::*[self::input | self::textarea | self::select]" .
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
$fieldnode = $this->find('xpath', $fieldxpath);
// It is the same one that contains the type.
$formfieldtypenode = $fieldnode;
}
$this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]);
$this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']);
// Getting the class which contains the field type.
$classes = explode(' ', $formfieldtypenode->getAttribute('class'));
foreach ($classes as $class) {
if (substr($class, 0, 5) == 'form-') {
$type = substr($class, 5);
}
}
// Instantiating the appropiate field type.
$field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession());
$field->set_value($value);
$this->find_button(get_string('savechanges'))->press();
}
}
@@ -1,74 +1,57 @@
@core @core_admin @core_user
Feature: Allowing multiple accounts to have the same email address
In order to manage user accounts
@core @core_admin
Feature: Enable multiple accounts to have the same email address
In order to have multiple accounts registerd on the system with the same email address
As an admin
I need to be able to set whether to allow multiple accounts with the same email or not
I need to enable multiple accounts to be registered with the same email address and verify it is applied
Scenario Outline: Create a user with the same email as an existing user
Background:
Given I log in as "admin"
Scenario: Enable registration of multiple accounts with the same email address
Given the following config values are set as admin:
| allowaccountssameemail | <allowsameemail> |
And the following "users" exist:
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
When I log in as "admin"
And I navigate to "Users > Accounts > Add a new user" in site administration
| allowaccountssameemail | 1 |
When I navigate to "Add a new user" node in "Site administration>Users>Accounts"
And I set the following fields to these values:
| Username | s2 |
| First name | Jane |
| Surname | Doe |
| Email address | <email> |
| New password | test |
| Username | testmultiemailuser1 |
| Choose an authentication method | Manual accounts |
| New password | test@User1 |
| First name | Test |
| Surname | Multi1 |
| Email address | testmultiemailuser@example.com |
And I press "Create user"
Then I should <expect> "This email address is already registered."
And I should see "Test Multi1"
And I press "Add a new user"
And I set the following fields to these values:
| Username | testmultiemailuser2 |
| Choose an authentication method | Manual accounts |
| New password | test@User2 |
| First name | Test |
| Surname | Multi2 |
| Email address | testmultiemailuser@example.com |
And I press "Create user"
Then I should see "Test Multi2"
And I should not see "This email address is already registered"
Examples:
| allowsameemail | email | expect |
| 0 | s1@example.com | see |
| 0 | S1@EXAMPLE.COM | see |
| 1 | s1@example.com | not see |
| 1 | S1@EXAMPLE.COM | not see |
Scenario Outline: Update a user with the same email as an existing user
Scenario: Disable registration of multiple accounts with the same email address
Given the following config values are set as admin:
| allowaccountssameemail | <allowsameemail> |
And the following "users" exist:
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
| s2 | Jane | Doe | s2@example.com |
When I log in as "admin"
And I navigate to "Users > Accounts > Browse list of users" in site administration
And I click on "Edit" "link" in the "Jane Doe" "table_row"
And I set the field "Email address" to "<email>"
And I press "Update profile"
Then I should <expect> "This email address is already registered."
Examples:
| allowsameemail | email | expect |
| 0 | s1@example.com | see |
| 0 | S1@EXAMPLE.COM | see |
| 1 | s1@example.com | not see |
| 1 | S1@EXAMPLE.COM | not see |
| 0 | S2@EXAMPLE.COM | not see |
| 1 | S2@EXAMPLE.COM | not see |
Scenario Outline: Update own user profile with the same email as an existing user
Given the following config values are set as admin:
| allowaccountssameemail | <allowsameemail> |
And the following "users" exist:
| username | firstname | lastname | email |
| s1 | John | Doe | s1@example.com |
| s2 | Jane | Doe | s2@example.com |
When I log in as "s2"
And I open my profile in edit mode
And I set the field "Email address" to "<email>"
And I press "Update profile"
Then I should <expect> "This email address is already registered."
Examples:
| allowsameemail | email | expect |
| 0 | s1@example.com | see |
| 0 | S1@EXAMPLE.COM | see |
| 1 | s1@example.com | not see |
| 1 | S1@EXAMPLE.COM | not see |
| 0 | S2@EXAMPLE.COM | not see |
| 1 | S2@EXAMPLE.COM | not see |
| allowaccountssameemail | 0 |
When I navigate to "Add a new user" node in "Site administration>Users>Accounts"
And I set the following fields to these values:
| Username | testmultiemailuser1 |
| Choose an authentication method | Manual accounts |
| New password | test@User1 |
| First name | Test |
| Surname | Multi1 |
| Email address | testmultiemailuser@example.com |
And I press "Create user"
And I should see "Test Multi1"
And I press "Add a new user"
And I set the following fields to these values:
| Username | testmultiemailuser2 |
| Choose an authentication method | Manual accounts |
| New password | test@User2 |
| First name | Test |
| Surname | Multi2 |
| Email address | testmultiemailuser@example.com |
And I press "Create user"
Then I should see "This email address is already registered"
-27
View File
@@ -1,27 +0,0 @@
@core @core_admin
Feature: Manage tokens
In order to manage webservice usage
As an admin
I need to be able to create and delete tokens
Background:
Given the following "users" exist:
| username | password | firstname | lastname |
| testuser | testuser | Joe | Bloggs |
| testuser2 | testuser2 | TestFirstname | TestLastname |
And I change window size to "small"
And I log in as "admin"
And I am on site homepage
@javascript
Scenario: Add & delete a token
Given I navigate to "Plugins > Web services > Manage tokens" in site administration
And I follow "Add"
And I set the field "User" to "Joe Bloggs"
And I set the field "IP restriction" to "127.0.0.1"
When I press "Save changes"
Then I should see "Joe Bloggs"
And I should see "127.0.0.1"
And I follow "Delete"
And I press "Delete"
And I should not see "Joe Bloggs"
-21
View File
@@ -1,21 +0,0 @@
@core @core_admin
Feature: Use the search areas admin screen
In order to control search indexing
As an admin
I need to use the search areas admin screen
Background:
Given I log in as "admin"
And I navigate to "Plugins > Search > Search areas" in site administration
Scenario: Disable and enable a search area
When I click on "Disable" "link" in the "Book - resource information" "table_row"
Then I should see "Search area disabled" in the ".alert-success" "css_element"
And I should see "Search area disabled" in the "Book - resource information" "table_row"
When I click on "Enable" "link" in the "Book - resource information" "table_row"
Then I should see "Search area enabled" in the ".alert-success" "css_element"
And I should not see "Search area disabled" in the "Book - resource information" "table_row"
# Note: Other scenarios are not currently easy to implement in Behat because there is no mock
# search engine - we could add testing once Moodle has an internal database search engine.
-1
View File
@@ -1 +0,0 @@
define(["jquery","core/str","core/modal_factory","core/notification"],function(a,b,c,d){return{loadInfo:function(e,f){var g=a('[data-model-log-id="'+e+'"]');b.get_string("loginfo","tool_analytics").then(function(b){var d=a("<ul>");return f.forEach(function(a){d.append("<li>"+a+"</li>")}),d.append("</ul>"),c.create({title:b,body:d.html(),large:!0},g)})["catch"](d.exception)}}});
-1
View File
@@ -1 +0,0 @@
define(["jquery","core/str","core/log","core/notification","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f){var g={clear:{title:{key:"clearpredictions",component:"tool_analytics"},body:{key:"clearmodelpredictions",component:"tool_analytics"}}},h=function(b){return a(b.closest("tr")[0]).find("span.target-name").text()};return{confirmAction:function(i,j){a('[data-action-id="'+i+'"]').on("click",function(i){i.preventDefault();var k=a(i.currentTarget);if("undefined"==typeof g[j])return void c.error('Action "'+j+'" is not allowed.');var l=[g[j].title,g[j].body];l[1].param=h(k);var m=b.get_strings(l),n=e.create({type:e.types.SAVE_CANCEL});a.when(m,n).then(function(a,b){return b.setTitle(a[0]),b.setBody(a[1]),b.setSaveButtonText(a[0]),b.getRoot().on(f.save,function(){window.location.href=k.attr("href")}),b.show(),b}).fail(d.exception)})}}});
-56
View File
@@ -1,56 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Shows a dialogue with info about this logs.
*
* @module tool_analytics/log_info
* @class log_info
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {
return /** @alias module:tool_analytics/log_info */ {
/**
* Prepares a modal info for a log's results.
*
* @method loadInfo
* @param {int} id
* @param {string[]} info
*/
loadInfo: function(id, info) {
var link = $('[data-model-log-id="' + id + '"]');
str.get_string('loginfo', 'tool_analytics').then(function(langString) {
var bodyInfo = $("<ul>");
info.forEach(function(item) {
bodyInfo.append('<li>' + item + '</li>');
});
bodyInfo.append("</ul>");
return ModalFactory.create({
title: langString,
body: bodyInfo.html(),
large: true,
}, link);
}).catch(Notification.exception);
}
};
});
-94
View File
@@ -1,94 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* AMD module for model actions confirmation.
*
* @module tool_analytics/model
* @copyright 2017 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/log', 'core/notification', 'core/modal_factory', 'core/modal_events'],
function($, Str, log, Notification, ModalFactory, ModalEvents) {
/**
* List of actions that require confirmation and confirmation message.
*/
var actionsList = {
clear: {
title: {
key: 'clearpredictions',
component: 'tool_analytics'
}, body: {
key: 'clearmodelpredictions',
component: 'tool_analytics'
}
}
};
/**
* Returns the model name.
*
* @param {Object} actionItem The action item DOM node.
* @return {String}
*/
var getModelName = function(actionItem) {
return $(actionItem.closest('tr')[0]).find('span.target-name').text();
};
/** @alias module:tool_analytics/model */
return {
/**
* Displays a confirm modal window before executing the action.
*
* @param {String} actionId
* @param {String} actionType
*/
confirmAction: function(actionId, actionType) {
$('[data-action-id="' + actionId + '"]').on('click', function(ev) {
ev.preventDefault();
var a = $(ev.currentTarget);
if (typeof actionsList[actionType] === "undefined") {
log.error('Action "' + actionType + '" is not allowed.');
return;
}
var reqStrings = [
actionsList[actionType].title,
actionsList[actionType].body
];
reqStrings[1].param = getModelName(a);
var stringsPromise = Str.get_strings(reqStrings);
var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL});
$.when(stringsPromise, modalPromise).then(function(strings, modal) {
modal.setTitle(strings[0]);
modal.setBody(strings[1]);
modal.setSaveButtonText(strings[0]);
modal.getRoot().on(ModalEvents.save, function() {
window.location.href = a.attr('href');
});
modal.show();
return modal;
}).fail(Notification.exception);
});
}
};
});
@@ -1,55 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Helper class that contains helper functions for cli scripts.
*
* @package tool_analytics
* @copyright 2017 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics;
defined('MOODLE_INTERNAL') || die();
/**
* Helper class that contains helper functions for cli scripts.
*
* @package tool_analytics
* @copyright 2017 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class clihelper {
/**
* List all models in the system. To be used from cli scripts.
*
* @return void
*/
public static function list_models() {
cli_heading("List of models");
echo str_pad(get_string('modelid', 'tool_analytics'), 15, ' ') . ' ' . str_pad(get_string('name'), 50, ' ') .
' ' . str_pad(get_string('status'), 15, ' ') . "\n";
$models = \core_analytics\manager::get_all_models();
foreach ($models as $model) {
$modelid = $model->get_id();
$isenabled = $model->is_enabled() ? get_string('enabled', 'tool_analytics') : get_string('disabled', 'tool_analytics');
$name = $model->get_target()->get_name();
echo str_pad($modelid, 15, ' ') . ' ' . str_pad($name, 50, ' ') . ' ' . str_pad($isenabled, 15, ' ') . "\n";
}
}
}
@@ -1,119 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Model edit form.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\output\form;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot.'/lib/formslib.php');
/**
* Model edit form.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class edit_model extends \moodleform {
/**
* Form definition
*/
public function definition() {
global $OUTPUT;
$mform = $this->_form;
if ($this->_customdata['model']->is_trained()) {
$message = get_string('edittrainedwarning', 'tool_analytics');
$mform->addElement('html', $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING));
}
$mform->addElement('advcheckbox', 'enabled', get_string('enabled', 'tool_analytics'));
$indicators = array();
foreach ($this->_customdata['indicators'] as $classname => $indicator) {
$optionname = \tool_analytics\output\helper::class_to_option($classname);
$indicators[$optionname] = $indicator->get_name();
}
$options = array(
'multiple' => true
);
$mform->addElement('autocomplete', 'indicators', get_string('indicators', 'tool_analytics'), $indicators, $options);
$mform->setType('indicators', PARAM_ALPHANUMEXT);
$timesplittings = array('' => '');
foreach ($this->_customdata['timesplittings'] as $classname => $timesplitting) {
$optionname = \tool_analytics\output\helper::class_to_option($classname);
$timesplittings[$optionname] = $timesplitting->get_name();
}
$mform->addElement('select', 'timesplitting', get_string('timesplittingmethod', 'analytics'), $timesplittings);
$mform->addHelpButton('timesplitting', 'timesplittingmethod', 'analytics');
$mform->addElement('hidden', 'id', $this->_customdata['id']);
$mform->setType('id', PARAM_INT);
$mform->addElement('hidden', 'action', 'edit');
$mform->setType('action', PARAM_ALPHANUMEXT);
$this->add_action_buttons();
}
/**
* Form validation
*
* @param array $data data from the form.
* @param array $files files uploaded.
*
* @return array of errors.
*/
public function validation($data, $files) {
$errors = parent::validation($data, $files);
if (!empty($data['timesplitting'])) {
$realtimesplitting = \tool_analytics\output\helper::option_to_class($data['timesplitting']);
if (\core_analytics\manager::is_valid($realtimesplitting, '\core_analytics\local\time_splitting\base') === false) {
$errors['timesplitting'] = get_string('errorinvalidtimesplitting', 'analytics');
}
}
if (empty($data['indicators'])) {
$errors['indicators'] = get_string('errornoindicators', 'analytics');
} else {
foreach ($data['indicators'] as $indicator) {
$realindicatorname = \tool_analytics\output\helper::option_to_class($indicator);
if (\core_analytics\manager::is_valid($realindicatorname, '\core_analytics\local\indicator\base') === false) {
$errors['indicators'] = get_string('errorinvalidindicator', 'analytics', $realindicatorname);
}
}
}
if (!empty($data['enabled']) && empty($data['timesplitting'])) {
$errors['enabled'] = get_string('errorcantenablenotimesplitting', 'tool_analytics');
}
return $errors;
}
}
@@ -1,61 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Typical crappy helper class with tiny functions.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\output;
defined('MOODLE_INTERNAL') || die();
/**
* Helper class with general purpose tiny functions.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Converts a class full name to a select option key
*
* @param string $class
* @return string
*/
public static function class_to_option($class) {
// Form field is PARAM_ALPHANUMEXT and we are sending fully qualified class names
// as option names, but replacing the backslash for a string that is really unlikely
// to ever be part of a class name.
return str_replace('\\', '2015102400ouuu', $class);
}
/**
* option_to_class
*
* @param string $option
* @return string
*/
public static function option_to_class($option) {
// Really unlikely but yeah, I'm a bad booyyy.
return str_replace('2015102400ouuu', '\\', $option);
}
}
@@ -1,164 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Invalid analysables renderable.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\output;
defined('MOODLE_INTERNAL') || die;
/**
* Invalid analysables renderable.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class invalid_analysables implements \renderable, \templatable {
/**
* @var \core_analytics\model
*/
protected $model = null;
/**
* @var int
*/
protected $page = 0;
/**
* @var int
*/
protected $perpage = 0;
/**
* Inits the invalid analysables renderable.
*
* @param \core_analytics\model $model
* @param int $page
* @param int $perpage
* @return \stdClass
*/
public function __construct(\core_analytics\model $model, $page, $perpage) {
$this->model = $model;
$this->page = $page;
$this->perpage = $perpage;
}
/**
* Export the data.
*
* @param \renderer_base $output
* @return \stdClass
*/
public function export_for_template(\renderer_base $output) {
global $PAGE;
$offset = $this->page * $this->perpage;
$analysables = $this->model->get_analyser(['notimesplitting' => true])->get_analysables();
$skipped = 0;
$enoughresults = false;
$morepages = false;
$results = array();
foreach ($analysables as $key => $analysable) {
$validtraining = $this->model->get_target()->is_valid_analysable($analysable, true);
if ($validtraining === true) {
if ($this->model->is_static()) {
// We still want to show this analysable if it is not valid to get predictions.
$validtraining = get_string('notrainingbasedassumptions', 'analytics');
} else {
// We skip analysables that are valid for training or valid for prediction.
continue;
}
}
$validprediction = $this->model->get_target()->is_valid_analysable($analysable, false);
if ($validprediction === true) {
// We skip analysables that are valid for training or valid for prediction.
continue;
}
if ($offset && $skipped < $offset) {
$skipped++;
continue;
}
// Add a new results if we don't have enough yet.
if (!$enoughresults) {
$results[$analysable->get_id()] = array($analysable, $validtraining, $validprediction);
if ($this->perpage && count($results) === $this->perpage) {
$enoughresults = true;
}
} else {
// Confirmed that we have results we can not fit into this page.
$morepages = true;
break;
}
unset($analysables[$key]);
}
// Prepare the context object.
$data = new \stdClass();
$data->modelname = $this->model->get_target()->get_name();
if ($this->page > 0) {
$prev = clone $PAGE->url;
$prev->param('page', $this->page - 1);
$button = new \single_button($prev, get_string('previouspage', 'tool_analytics'), 'get');
$data->prev = $button->export_for_template($output);
}
if ($morepages) {
$next = clone $PAGE->url;
$next->param('page', $this->page + 1);
$button = new \single_button($next, get_string('nextpage', 'tool_analytics'), 'get');
$data->next = $button->export_for_template($output);
}
$data->analysables = [];
foreach ($results as list($analysable, $validtraining, $validprediction)) {
$obj = new \stdClass();
$obj->url = \html_writer::link($analysable->get_context()->get_url(), $analysable->get_name(),
array('target' => '_blank'));
if ($validtraining !== true) {
$obj->validtraining = $validtraining;
}
if ($validprediction !== true) {
$obj->validprediction = $validprediction;
}
$data->analysables[] = $obj;
}
if (empty($data->analysables)) {
$data->noanalysables = [
'message' => get_string('noinvalidanalysables', 'tool_analytics'),
'announce' => true,
];
}
return $data;
}
}
@@ -1,192 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Model logs table class.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\output;
defined('MOODLE_INTERNAL') || die;
require_once($CFG->libdir . '/tablelib.php');
/**
* Model logs table class.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class model_logs extends \table_sql {
/**
* @var \core_analytics\model
*/
protected $model = null;
/**
* Sets up the table_log parameters.
*
* @param string $uniqueid unique id of form.
* @param \core_analytics\model $model
*/
public function __construct($uniqueid, $model) {
global $PAGE;
parent::__construct($uniqueid);
$this->model = $model;
$this->set_attribute('class', 'modellog generaltable generalbox');
$this->set_attribute('aria-live', 'polite');
$this->define_columns(array('time', 'version', 'indicators', 'timesplitting', 'accuracy', 'info', 'usermodified'));
$this->define_headers(array(
get_string('time'),
get_string('version'),
get_string('indicators', 'tool_analytics'),
get_string('timesplittingmethod', 'analytics'),
get_string('accuracy', 'tool_analytics'),
get_string('info', 'tool_analytics'),
get_string('fullnameuser'),
));
$this->pageable(true);
$this->collapsible(false);
$this->sortable(false);
$this->is_downloadable(false);
$this->define_baseurl($PAGE->url);
}
/**
* Generate the version column.
*
* @param \stdClass $log log data.
* @return string HTML for the version column
*/
public function col_version($log) {
$recenttimestr = get_string('strftimerecent', 'core_langconfig');
return userdate($log->version, $recenttimestr);
}
/**
* Generate the time column.
*
* @param \stdClass $log log data.
* @return string HTML for the time column
*/
public function col_time($log) {
$recenttimestr = get_string('strftimerecent', 'core_langconfig');
return userdate($log->timecreated, $recenttimestr);
}
/**
* Generate the indicators column.
*
* @param \stdClass $log log data.
* @return string HTML for the indicators column
*/
public function col_indicators($log) {
$indicatorclasses = json_decode($log->indicators);
$indicators = array();
foreach ($indicatorclasses as $indicatorclass) {
$indicator = \core_analytics\manager::get_indicator($indicatorclass);
if ($indicator) {
$indicators[] = $indicator->get_name();
} else {
debugging('Can\'t load ' . $indicatorclass . ' indicator', DEBUG_DEVELOPER);
}
}
return '<ul><li>' . implode('</li><li>', $indicators) . '</li></ul>';
}
/**
* Generate the context column.
*
* @param \stdClass $log log data.
* @return string HTML for the context column
*/
public function col_timesplitting($log) {
$timesplitting = \core_analytics\manager::get_time_splitting($log->timesplitting);
return $timesplitting->get_name();
}
/**
* Generate the accuracy column.
*
* @param \stdClass $log log data.
* @return string HTML for the accuracy column
*/
public function col_accuracy($log) {
return strval(round($log->score * 100, 2)) . '%';
}
/**
* Generate the info column.
*
* @param \stdClass $log log data.
* @return string HTML for the score column
*/
public function col_info($log) {
global $PAGE;
if (empty($log->info) && empty($log->dir)) {
return '';
}
$info = array();
if (!empty($log->info)) {
$info = json_decode($log->info);
}
if (!empty($log->dir)) {
$info[] = get_string('predictorresultsin', 'tool_analytics', $log->dir);
}
$PAGE->requires->js_call_amd('tool_analytics/log_info', 'loadInfo', array($log->id, $info));
return \html_writer::link('#', get_string('view'), array('data-model-log-id' => $log->id));
}
/**
* Generate the usermodified column.
*
* @param \stdClass $log log data.
* @return string HTML for the usermodified column
*/
public function col_usermodified($log) {
$user = \core_user::get_user($log->usermodified);
return fullname($user);
}
/**
* Query the logs table. Store results in the object for use by build_table.
*
* @param int $pagesize size of page for paginated displayed table.
* @param bool $useinitialsbar do you want to use the initials bar.
*/
public function query_db($pagesize, $useinitialsbar = true) {
$total = count($this->model->get_logs());
$this->pagesize($pagesize, $total);
$this->rawdata = $this->model->get_logs($this->get_page_start(), $this->get_page_size());
// Set initial bars.
if ($useinitialsbar) {
$this->initialbars($total > $pagesize);
}
}
}
@@ -1,286 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Prediction models list page.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\output;
defined('MOODLE_INTERNAL') || die();
/**
* Shows tool_analytics models list.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class models_list implements \renderable, \templatable {
/**
* models
*
* @var \core_analytics\model[]
*/
protected $models = array();
/**
* __construct
*
* @param \core_analytics\model[] $models
* @return void
*/
public function __construct($models) {
$this->models = $models;
}
/**
* Exports the data.
*
* @param \renderer_base $output
* @return \stdClass
*/
public function export_for_template(\renderer_base $output) {
global $PAGE;
$data = new \stdClass();
$onlycli = get_config('analytics', 'onlycli');
if ($onlycli === false) {
// Default applied if no config found.
$onlycli = 1;
}
$data->models = array();
foreach ($this->models as $model) {
$modeldata = $model->export();
// Check if there is a help icon for the target to show.
$identifier = $modeldata->target->get_identifier();
$component = $modeldata->target->get_component();
if (get_string_manager()->string_exists($identifier . '_help', $component)) {
$helpicon = new \help_icon($identifier, $component);
$modeldata->targethelp = $helpicon->export_for_template($output);
} else {
// We really want to encourage developers to add help to their targets.
debugging("The target '{$modeldata->target}' should include a '{$identifier}_help' string to
describe its purpose.", DEBUG_DEVELOPER);
}
// Check if there is a help icon for the indicators to show.
if (!empty($modeldata->indicators)) {
$indicators = array();
foreach ($modeldata->indicators as $ind) {
// Create the indicator with the details we want for the context.
$indicator = new \stdClass();
$indicator->name = $ind->out();
$identifier = $ind->get_identifier();
$component = $ind->get_component();
if (get_string_manager()->string_exists($identifier . '_help', $component)) {
$helpicon = new \help_icon($identifier, $component);
$indicator->help = $helpicon->export_for_template($output);
} else {
// We really want to encourage developers to add help to their indicators.
debugging("The indicator '{$ind}' should include a '{$identifier}_help' string to
describe its purpose.", DEBUG_DEVELOPER);
}
$indicators[] = $indicator;
}
$modeldata->indicators = $indicators;
}
// Check if there is a help icon for the time splitting method.
if (!empty($modeldata->timesplitting)) {
$identifier = $modeldata->timesplitting->get_identifier();
$component = $modeldata->timesplitting->get_component();
if (get_string_manager()->string_exists($identifier . '_help', $component)) {
$helpicon = new \help_icon($identifier, $component);
$modeldata->timesplittinghelp = $helpicon->export_for_template($output);
} else {
// We really want to encourage developers to add help to their time splitting methods.
debugging("The time splitting method '{$modeldata->timesplitting}' should include a '{$identifier}_help'
string to describe its purpose.", DEBUG_DEVELOPER);
}
} else {
$helpicon = new \help_icon('timesplittingnotdefined', 'tool_analytics');
$modeldata->timesplittinghelp = $helpicon->export_for_template($output);
}
// Has this model generated predictions?.
$predictioncontexts = $model->get_predictions_contexts();
// Model predictions list.
if (!$model->is_enabled()) {
$modeldata->noinsights = get_string('disabledmodel', 'analytics');
} else if ($model->uses_insights()) {
if ($predictioncontexts) {
foreach ($predictioncontexts as $contextid => $unused) {
// We prepare this to be used as single_select template options.
$context = \context::instance_by_id($contextid);
// Special name for system level predictions as showing "System is not visually nice".
if ($contextid == SYSCONTEXTID) {
$contextname = get_string('allpredictions', 'tool_analytics');
} else {
$contextname = shorten_text($context->get_context_name(true, true), 90);
}
$predictioncontexts[$contextid] = $contextname;
}
\core_collator::asort($predictioncontexts);
if (!empty($predictioncontexts)) {
$url = new \moodle_url('/report/insights/insights.php', array('modelid' => $model->get_id()));
$singleselect = new \single_select($url, 'contextid', $predictioncontexts);
$modeldata->insights = $singleselect->export_for_template($output);
}
}
if (empty($modeldata->insights)) {
if ($model->any_prediction_obtained()) {
$modeldata->noinsights = get_string('noinsights', 'analytics');
} else {
$modeldata->noinsights = get_string('nopredictionsyet', 'analytics');
}
}
} else {
$modeldata->noinsights = get_string('noinsightsmodel', 'analytics');
}
// Actions.
$actionsmenu = new \action_menu();
$actionsmenu->set_menu_trigger(get_string('actions'));
$actionsmenu->set_owner_selector('model-actions-' . $model->get_id());
$actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL);
$urlparams = ['id' => $model->get_id(), 'sesskey' => sesskey()];
// Get predictions.
if (!$onlycli && $modeldata->enabled && !empty($modeldata->timesplitting)) {
$urlparams['action'] = 'getpredictions';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('i/notifications',
get_string('getpredictions', 'tool_analytics')), get_string('getpredictions', 'tool_analytics'));
$actionsmenu->add($icon);
}
// Evaluate machine-learning-based models.
if (!$onlycli && $model->get_indicators() && !$model->is_static()) {
$urlparams['action'] = 'evaluate';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')),
get_string('evaluate', 'tool_analytics'));
$actionsmenu->add($icon);
}
// Machine-learning-based models evaluation log.
if (!$model->is_static()) {
$urlparams['action'] = 'log';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('i/report', get_string('viewlog', 'tool_analytics')),
get_string('viewlog', 'tool_analytics'));
$actionsmenu->add($icon);
}
// Edit model.
if (!$model->is_static()) {
$urlparams['action'] = 'edit';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('t/edit', get_string('edit')), get_string('edit'));
$actionsmenu->add($icon);
}
// Enable / disable.
if ($model->is_enabled() || !empty($modeldata->timesplitting)) {
// If there is no timesplitting method set, the model can not be enabled.
if ($model->is_enabled()) {
$action = 'disable';
$text = get_string('disable');
$icontype = 't/block';
} else {
$action = 'enable';
$text = get_string('enable');
$icontype = 'i/checked';
}
$urlparams['action'] = $action;
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
$actionsmenu->add($icon);
}
// Export training data.
if (!$model->is_static() && $model->is_trained()) {
$urlparams['action'] = 'export';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('i/export',
get_string('exporttrainingdata', 'tool_analytics')), get_string('export', 'tool_analytics'));
$actionsmenu->add($icon);
}
// Invalid analysables.
$analyser = $model->get_analyser(['notimesplitting' => true]);
if (!$analyser instanceof \core_analytics\local\analyser\sitewide) {
$urlparams['action'] = 'invalidanalysables';
$url = new \moodle_url('model.php', $urlparams);
$pix = new \pix_icon('i/report', get_string('invalidanalysables', 'tool_analytics'));
$icon = new \action_menu_link_secondary($url, $pix, get_string('invalidanalysables', 'tool_analytics'));
$actionsmenu->add($icon);
}
// Clear model.
if (!empty($predictioncontexts) || $model->is_trained()) {
$actionid = 'clear-' . $model->get_id();
$PAGE->requires->js_call_amd('tool_analytics/model', 'confirmAction', [$actionid, 'clear']);
$urlparams['action'] = 'clear';
$url = new \moodle_url('model.php', $urlparams);
$icon = new \action_menu_link_secondary($url, new \pix_icon('e/cleanup_messy_code',
get_string('clearpredictions', 'tool_analytics')), get_string('clearpredictions', 'tool_analytics'),
['data-action-id' => $actionid]);
$actionsmenu->add($icon);
}
$modeldata->actions = $actionsmenu->export_for_template($output);
$data->models[] = $modeldata;
}
if (!$onlycli) {
$data->warnings = array(
(object)array('message' => get_string('bettercli', 'tool_analytics'), 'closebutton' => true)
);
} else {
$url = new \moodle_url('/admin/settings.php', array('section' => 'analyticssettings'),
'id_s_analytics_onlycli');
$langstrid = 'clievaluationandpredictionsnoadmin';
if (is_siteadmin()) {
$langstrid = 'clievaluationandpredictions';
}
$data->infos = array(
(object)array('message' => get_string($langstrid, 'tool_analytics', $url->out()),
'closebutton' => true)
);
}
return $data;
}
}
@@ -1,221 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Renderer.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\output;
defined('MOODLE_INTERNAL') || die();
use plugin_renderer_base;
use templatable;
use renderable;
/**
* Renderer class.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class renderer extends plugin_renderer_base {
/**
* Defer to template.
*
* @param \tool_analytics\output\models_list $modelslist
* @return string HTML
*/
protected function render_models_list(\tool_analytics\output\models_list $modelslist) {
$data = $modelslist->export_for_template($this);
return parent::render_from_template('tool_analytics/models_list', $data);
}
/**
* Renders a table.
*
* @param \table_sql $table
* @return string HTML
*/
public function render_table(\table_sql $table) {
ob_start();
$table->out(10, true);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
/**
* Web interface evaluate results.
*
* @param \stdClass[] $results
* @param string[] $logs
* @return string HTML
*/
public function render_evaluate_results($results, $logs = array()) {
global $OUTPUT;
$output = '';
foreach ($results as $timesplittingid => $result) {
if (!CLI_SCRIPT) {
$output .= $OUTPUT->box_start('generalbox m-b-3');
}
// Check that the array key is a string, not all results depend on time splitting methods (e.g. general errors).
if (!is_numeric($timesplittingid)) {
$timesplitting = \core_analytics\manager::get_time_splitting($timesplittingid);
$langstrdata = (object)array('name' => $timesplitting->get_name(), 'id' => $timesplittingid);
if (CLI_SCRIPT) {
$output .= $OUTPUT->heading(get_string('getpredictionsresultscli', 'tool_analytics', $langstrdata), 3);
} else {
$output .= $OUTPUT->heading(get_string('getpredictionsresults', 'tool_analytics', $langstrdata), 3);
}
}
if ($result->status == 0) {
$output .= $OUTPUT->notification(get_string('goodmodel', 'tool_analytics'),
\core\output\notification::NOTIFY_SUCCESS);
} else if ($result->status === \core_analytics\model::NO_DATASET) {
$output .= $OUTPUT->notification(get_string('nodatatoevaluate', 'tool_analytics'),
\core\output\notification::NOTIFY_WARNING);
}
if (isset($result->score)) {
// Score.
$output .= $OUTPUT->heading(get_string('accuracy', 'tool_analytics') . ': ' .
round(floatval($result->score), 4) * 100 . '%', 4);
}
if (!empty($result->info)) {
foreach ($result->info as $message) {
$output .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
}
}
if (!CLI_SCRIPT) {
$output .= $OUTPUT->box_end();
}
}
// Info logged during evaluation.
if (!empty($logs) && debugging()) {
$output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 3);
foreach ($logs as $log) {
$output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
}
}
if (!CLI_SCRIPT) {
$output .= $OUTPUT->single_button(new \moodle_url('/admin/tool/analytics/index.php'), get_string('continue'), 'get');
}
return $output;
}
/**
* Web interface training & prediction results.
*
* @param \stdClass|false $trainresults
* @param string[] $trainlogs
* @param \stdClass|false $predictresults
* @param string[] $predictlogs
* @return string HTML
*/
public function render_get_predictions_results($trainresults = false, $trainlogs = array(), $predictresults = false, $predictlogs = array()) {
global $OUTPUT;
$output = '';
if ($trainresults || (!empty($trainlogs) && debugging())) {
$output .= $OUTPUT->heading(get_string('trainingresults', 'tool_analytics'), 3);
}
if ($trainresults) {
if ($trainresults->status == 0) {
$output .= $OUTPUT->notification(get_string('trainingprocessfinished', 'tool_analytics'),
\core\output\notification::NOTIFY_SUCCESS);
} else if ($trainresults->status === \core_analytics\model::NO_DATASET ||
$trainresults->status === \core_analytics\model::NOT_ENOUGH_DATA) {
$output .= $OUTPUT->notification(get_string('nodatatotrain', 'tool_analytics'),
\core\output\notification::NOTIFY_WARNING);
} else {
$output .= $OUTPUT->notification(get_string('generalerror', 'tool_analytics', $trainresults->status),
\core\output\notification::NOTIFY_ERROR);
}
}
if (!empty($trainlogs) && debugging()) {
$output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 4);
foreach ($trainlogs as $log) {
$output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
}
}
if ($predictresults || (!empty($predictlogs) && debugging())) {
$output .= $OUTPUT->heading(get_string('predictionresults', 'tool_analytics'), 3, 'main m-t-3');
}
if ($predictresults) {
if ($predictresults->status == 0) {
$output .= $OUTPUT->notification(get_string('predictionprocessfinished', 'tool_analytics'),
\core\output\notification::NOTIFY_SUCCESS);
} else if ($predictresults->status === \core_analytics\model::NO_DATASET ||
$predictresults->status === \core_analytics\model::NOT_ENOUGH_DATA) {
$output .= $OUTPUT->notification(get_string('nodatatopredict', 'tool_analytics'),
\core\output\notification::NOTIFY_WARNING);
} else {
$output .= $OUTPUT->notification(get_string('generalerror', 'tool_analytics', $predictresults->status),
\core\output\notification::NOTIFY_ERROR);
}
}
if (!empty($predictlogs) && debugging()) {
$output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 4);
foreach ($predictlogs as $log) {
$output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
}
}
if (!CLI_SCRIPT) {
$output .= $OUTPUT->single_button(new \moodle_url('/admin/tool/analytics/index.php'), get_string('continue'), 'get');
}
return $output;
}
/**
* Defer to template.
*
* @param \tool_analytics\output\invalid_analysables $invalidanalysables
* @return string HTML
*/
protected function render_invalid_analysables(\tool_analytics\output\invalid_analysables $invalidanalysables) {
$data = $invalidanalysables->export_for_template($this);
return parent::render_from_template('tool_analytics/invalid_analysables', $data);
}
}
@@ -1,46 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for tool_analytics.
*
* @package tool_analytics
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_analytics implementing null_provider.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}
@@ -1,71 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Predict system models with new data available.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\task;
defined('MOODLE_INTERNAL') || die();
/**
* Predict system models with new data available.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class predict_models extends \core\task\scheduled_task {
/**
* get_name
*
* @return string
*/
public function get_name() {
return get_string('predictmodels', 'tool_analytics');
}
/**
* Executes the prediction task.
*
* @return void
*/
public function execute() {
global $OUTPUT, $PAGE;
$models = \core_analytics\manager::get_all_models(true, true);
if (!$models) {
mtrace(get_string('errornoenabledandtrainedmodels', 'tool_analytics'));
return;
}
foreach ($models as $model) {
$result = $model->predict();
if ($result) {
echo $OUTPUT->heading(get_string('modelresults', 'tool_analytics', $model->get_target()->get_name()));
$renderer = $PAGE->get_renderer('tool_analytics');
echo $renderer->render_get_predictions_results(false, array(), $result, $model->get_analyser()->get_logs());
}
}
}
}
@@ -1,82 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Train system models with new data available.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_analytics\task;
defined('MOODLE_INTERNAL') || die();
/**
* Train system models with new data available.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class train_models extends \core\task\scheduled_task {
/**
* get_name
*
* @return string
*/
public function get_name() {
return get_string('trainmodels', 'tool_analytics');
}
/**
* Executes the prediction task.
*
* @return void
*/
public function execute() {
global $OUTPUT, $PAGE;
$models = \core_analytics\manager::get_all_models(true);
if (!$models) {
mtrace(get_string('errornoenabledmodels', 'tool_analytics'));
return;
}
foreach ($models as $model) {
if ($model->is_static()) {
// Skip models based on assumptions.
continue;
}
if (!$model->get_time_splitting()) {
// Can not train if there is no time splitting method selected.
continue;
}
$result = $model->train();
if ($result) {
echo $OUTPUT->heading(get_string('modelresults', 'tool_analytics', $model->get_target()->get_name()));
$renderer = $PAGE->get_renderer('tool_analytics');
echo $renderer->render_get_predictions_results($result, $model->get_analyser()->get_logs());
}
}
}
}
-79
View File
@@ -1,79 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Enables the provided model.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require_once(__DIR__ . '/../../../../config.php');
require_once($CFG->libdir.'/clilib.php');
$help = "Enables the provided model.
Options:
--modelid Model id
--list List models
--timesplitting Time splitting method full class name
-h, --help Print out this help
Example:
\$ php admin/tool/analytics/cli/enable_model.php --modelid=1 --timesplitting=\"\\core\\analytics\\time_splitting\\quarters\"
";
// Now get cli options.
list($options, $unrecognized) = cli_get_params(
array(
'help' => false,
'list' => false,
'modelid' => false,
'timesplitting' => false
),
array(
'h' => 'help',
)
);
if ($options['help']) {
echo $help;
exit(0);
}
if ($options['list'] || $options['modelid'] === false) {
\tool_analytics\clihelper::list_models();
exit(0);
}
if ($options['timesplitting'] === false) {
echo $help;
exit(0);
}
// We need admin permissions.
\core\session\manager::set_user(get_admin());
$model = new \core_analytics\model($options['modelid']);
// Evaluate its suitability to predict accurately.
$model->enable($options['timesplitting']);
cli_heading(get_string('success'));
exit(0);
-133
View File
@@ -1,133 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Evaluates the provided model.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require_once(__DIR__ . '/../../../../config.php');
require_once($CFG->libdir.'/clilib.php');
$help = "Evaluates the provided model.
Options:
--modelid Model id
--list List models
--non-interactive Not interactive questions
--timesplitting Restrict the evaluation to 1 single time splitting method (Optional)
--filter Analyser dependant. e.g. A courseid would evaluate the model using a single course (Optional)
--reuse-prev-analysed Reuse recently analysed courses instead of analysing the whole site. Set it to false while" .
" coding indicators. Defaults to true (Optional)" . "
-h, --help Print out this help
Example:
\$ php admin/tool/analytics/cli/evaluate_model.php --modelid=1 --timesplitting='\\core\\analytics\\time_splitting\\quarters' --filter=123,321
";
// Now get cli options.
list($options, $unrecognized) = cli_get_params(
array(
'help' => false,
'modelid' => false,
'list' => false,
'timesplitting' => false,
'reuse-prev-analysed' => true,
'non-interactive' => false,
'filter' => false
),
array(
'h' => 'help',
)
);
if ($options['help']) {
echo $help;
exit(0);
}
if ($options['list'] || $options['modelid'] === false) {
\tool_analytics\clihelper::list_models();
exit(0);
}
// Reformat them as an array.
if ($options['filter'] !== false) {
$options['filter'] = explode(',', $options['filter']);
}
// We need admin permissions.
\core\session\manager::set_user(get_admin());
$model = new \core_analytics\model($options['modelid']);
mtrace(get_string('analysingsitedata', 'tool_analytics'));
if ($options['reuse-prev-analysed']) {
mtrace(get_string('evaluationinbatches', 'tool_analytics'));
}
$analyseroptions = array(
'filter' => $options['filter'],
'timesplitting' => $options['timesplitting'],
'reuseprevanalysed' => $options['reuse-prev-analysed'],
);
// Evaluate its suitability to predict accurately.
$results = $model->evaluate($analyseroptions);
$renderer = $PAGE->get_renderer('tool_analytics');
echo $renderer->render_evaluate_results($results, $model->get_analyser()->get_logs());
// Check that we have, at leasa,t 1 valid dataset (not necessarily good) to use.
foreach ($results as $result) {
if ($result->status !== \core_analytics\model::NO_DATASET &&
$result->status !== \core_analytics\model::GENERAL_ERROR) {
$validdatasets = true;
}
}
if (!empty($validdatasets) && !$model->is_enabled() && $options['non-interactive'] === false) {
// Select a dataset, train and enable the model.
$input = cli_input(get_string('clienablemodel', 'tool_analytics'));
while (!\core_analytics\manager::is_valid($input, '\core_analytics\local\time_splitting\base') && $input !== 'none') {
mtrace(get_string('errorunexistingtimesplitting', 'analytics'));
$input = cli_input(get_string('clienablemodel', 'tool_analytics'));
}
if ($input === 'none') {
exit(0);
}
// Refresh the instance to prevent unexpected issues.
$model = new \core_analytics\model($modelobj);
// Set the time splitting method file and enable it.
$model->enable($input);
mtrace(get_string('trainandpredictmodel', 'tool_analytics'));
// Train the model with the selected time splitting method and start predicting.
$model->train();
$model->predict();
}
exit(0);
@@ -1,228 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Guesses course start and end dates based on activity logs.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('CLI_SCRIPT', true);
require_once(__DIR__ . '/../../../../config.php');
require_once($CFG->libdir.'/clilib.php');
require_once($CFG->dirroot . '/course/lib.php');
require_once($CFG->dirroot . '/course/format/weeks/lib.php');
$help = "Guesses course start and end dates based on activity logs.
IMPORTANT: Don't use this script if you keep previous academic years users enrolled in courses. Guesses would not be accurate.
Options:
--guessstart Guess the course start date (default to true)
--guessend Guess the course end date (default to true)
--guessall Guess all start and end dates, even if they are already set (default to false)
--update Update the db or just notify the guess (default to false)
--filter Analyser dependant. e.g. A courseid would evaluate the model using a single course (Optional)
-h, --help Print out this help
Example:
\$ php admin/tool/analytics/cli/guess_course_start_and_end_dates.php --update=1 --filter=123,321
";
// Now get cli options.
list($options, $unrecognized) = cli_get_params(
array(
'help' => false,
'guessstart' => true,
'guessend' => true,
'guessall' => false,
'update' => false,
'filter' => false
),
array(
'h' => 'help',
)
);
if ($options['help']) {
echo $help;
exit(0);
}
if ($options['guessstart'] === false && $options['guessend'] === false && $options['guessall'] === false) {
echo $help;
exit(0);
}
// Reformat them as an array.
if ($options['filter'] !== false) {
$options['filter'] = explode(',', clean_param($options['filter'], PARAM_SEQUENCE));
}
// We need admin permissions.
\core\session\manager::set_user(get_admin());
$conditions = array('id != 1');
if (!$options['guessall']) {
if ($options['guessstart']) {
$conditions[] = '(startdate is null or startdate = 0)';
}
if ($options['guessend']) {
$conditions[] = '(enddate is null or enddate = 0)';
}
}
$coursessql = '';
$params = null;
if ($options['filter']) {
list($coursessql, $params) = $DB->get_in_or_equal($options['filter'], SQL_PARAMS_NAMED);
$conditions[] = 'id ' . $coursessql;
}
$courses = $DB->get_recordset_select('course', implode(' AND ', $conditions), $params, 'sortorder ASC');
foreach ($courses as $course) {
tool_analytics_calculate_course_dates($course, $options);
}
$courses->close();
/**
* tool_analytics_calculate_course_dates
*
* @param stdClass $course
* @param array $options CLI options
* @return void
*/
function tool_analytics_calculate_course_dates($course, $options) {
global $DB, $OUTPUT;
$courseman = new \core_analytics\course($course);
$notification = $course->shortname . ' (id = ' . $course->id . '): ';
$originalenddate = null;
$guessedstartdate = null;
$guessedenddate = null;
$samestartdate = null;
$lowerenddate = null;
if ($options['guessstart'] || $options['guessall']) {
$originalstartdate = $course->startdate;
$guessedstartdate = $courseman->guess_start();
$samestartdate = ($guessedstartdate == $originalstartdate);
$lowerenddate = ($course->enddate && ($course->enddate < $guessedstartdate));
if ($samestartdate) {
if (!$guessedstartdate) {
$notification .= PHP_EOL . ' ' . get_string('cantguessstartdate', 'tool_analytics');
} else {
// No need to update.
$notification .= PHP_EOL . ' ' . get_string('samestartdate', 'tool_analytics') . ': ' . userdate($guessedstartdate);
}
} else if (!$guessedstartdate) {
$notification .= PHP_EOL . ' ' . get_string('cantguessstartdate', 'tool_analytics');
} else if ($lowerenddate) {
$notification .= PHP_EOL . ' ' . get_string('cantguessstartdate', 'tool_analytics') . ': ' .
get_string('enddatebeforestartdate', 'error') . ' - ' . userdate($guessedstartdate);
} else {
// Update it to something we guess.
// We set it to $course even if we don't update because may be needed to guess the end one.
$course->startdate = $guessedstartdate;
$notification .= PHP_EOL . ' ' . get_string('startdate') . ': ' . userdate($guessedstartdate);
// Two different course updates because week's end date may be recalculated after setting the start date.
if ($options['update']) {
update_course($course);
// Refresh course data as end date may have been updated.
$course = $DB->get_record('course', array('id' => $course->id));
$courseman = new \core_analytics\course($course);
}
}
}
if ($options['guessend'] || $options['guessall']) {
if (!empty($lowerenddate) && !empty($guessedstartdate)) {
$course->startdate = $guessedstartdate;
}
$originalenddate = $course->enddate;
$format = course_get_format($course);
$formatoptions = $format->get_format_options();
// Change this for a course formats API level call in MDL-60702.
if (method_exists($format, 'update_end_date') && $formatoptions['automaticenddate']) {
// Special treatment for weeks-based formats with automatic end date.
if ($options['update']) {
$format::update_end_date($course->id);
$course->enddate = $DB->get_field('course', 'enddate', array('id' => $course->id));
$notification .= PHP_EOL . ' ' . get_string('weeksenddateautomaticallyset', 'tool_analytics') . ': ' .
userdate($course->enddate);
} else {
// We can't provide more info without actually updating it in db.
$notification .= PHP_EOL . ' ' . get_string('weeksenddatedefault', 'tool_analytics');
}
} else {
$guessedenddate = $courseman->guess_end();
if ($guessedenddate == $originalenddate) {
if (!$guessedenddate) {
$notification .= PHP_EOL . ' ' . get_string('cantguessenddate', 'tool_analytics');
} else {
// No need to update.
$notification .= PHP_EOL . ' ' . get_string('sameenddate', 'tool_analytics') . ': ' . userdate($guessedenddate);
}
} else if (!$guessedenddate) {
$notification .= PHP_EOL . ' ' . get_string('cantguessenddate', 'tool_analytics');
} else {
// Update it to something we guess.
$course->enddate = $guessedenddate;
$updateit = false;
if ($course->enddate < $course->startdate) {
$notification .= PHP_EOL . ' ' . get_string('errorendbeforestart', 'analytics', userdate($course->enddate));
} else if ($course->startdate + (YEARSECS + (WEEKSECS * 4)) > $course->enddate) {
$notification .= PHP_EOL . ' ' . get_string('coursetoolong', 'analytics');
} else {
$notification .= PHP_EOL . ' ' . get_string('enddate') . ': ' . userdate($course->enddate);
$updateit = true;
}
if ($options['update'] && $updateit) {
update_course($course);
}
}
}
}
mtrace($notification);
}
mtrace(get_string('success'));
exit(0);
-37
View File
@@ -1,37 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Prediction models tool frontend.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../config.php');
require_once($CFG->libdir . '/adminlib.php');
admin_externalpage_setup('analyticmodels', '', null, '', array('pagelayout' => 'report'));
$models = \core_analytics\manager::get_all_models();
echo $OUTPUT->header();
$templatable = new \tool_analytics\output\models_list($models);
echo $PAGE->get_renderer('tool_analytics')->render($templatable);
echo $OUTPUT->footer();
@@ -1,98 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for tool_analytics.
*
* @package tool_analytics
* @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['accuracy'] = 'Accuracy';
$string['allpredictions'] = 'All predictions';
$string['analysingsitedata'] = 'Analysing the site';
$string['analyticmodels'] = 'Analytics models';
$string['bettercli'] = 'Evaluating models and generating predictions may involve heavy processing. It is recommended to run these actions from the command line.';
$string['cantguessstartdate'] = 'Can\'t guess the start date';
$string['cantguessenddate'] = 'Can\'t guess the end date';
$string['clearpredictions'] = 'Clear predictions';
$string['clearmodelpredictions'] = 'Are you sure you want to clear all "{$a}" predictions?';
$string['clienablemodel'] = 'You can enable the model by selecting a time-splitting method by its ID. Note that you can also enable it later using the web interface (\'none\' to exit).';
$string['clievaluationandpredictions'] = 'A scheduled task iterates through enabled models and gets predictions. Models evaluation via the web interface is disabled. You can allow these processes to be executed manually via the web interface by disabling the <a href="{$a}">\'onlycli\'</a> analytics setting.';
$string['clievaluationandpredictionsnoadmin'] = 'A scheduled task iterates through enabled models and gets predictions. Models evaluation via the web interface is disabled. It may be enabled by a site administrator.';
$string['disabled'] = 'Disabled';
$string['editmodel'] = 'Edit "{$a}" model';
$string['edittrainedwarning'] = 'This model has already been trained. Note that changing its indicators or its time-splitting method will delete its previous predictions and start generating new predictions.';
$string['enabled'] = 'Enabled';
$string['errorcantenablenotimesplitting'] = 'You need to select a time-splitting method before enabling the model';
$string['errornoenabledandtrainedmodels'] = 'There are no enabled and trained models to predict.';
$string['errornoenabledmodels'] = 'There are no enabled models to train.';
$string['errornoexport'] = 'Only trained models can be exported';
$string['errornostaticedit'] = 'Models based on assumptions cannot be edited.';
$string['errornostaticevaluated'] = 'Models based on assumptions cannot be evaluated. They are always 100% correct according to how they were defined.';
$string['errornostaticlog'] = 'Models based on assumptions cannot be evaluated because there is no performance log.';
$string['erroronlycli'] = 'Execution only allowed via command line';
$string['errortrainingdataexport'] = 'The model training data could not be exported';
$string['evaluate'] = 'Evaluate';
$string['evaluatemodel'] = 'Evaluate model';
$string['evaluationinbatches'] = 'The site contents are calculated and stored in batches. The evaluation process may be stopped at any time. The next time it is run, it will continue from the point when it was stopped.';
$string['export'] = 'Export';
$string['exporttrainingdata'] = 'Export training data';
$string['getpredictionsresultscli'] = 'Results using {$a->name} (id: {$a->id}) course duration splitting';
$string['getpredictionsresults'] = 'Results using {$a->name} course duration splitting';
$string['extrainfo'] = 'Info';
$string['generalerror'] = 'Evaluation error. Status code {$a}';
$string['getpredictions'] = 'Get predictions';
$string['goodmodel'] = 'This is a good model for using to obtain predictions. Enable it to start obtaining predictions.';
$string['indicators'] = 'Indicators';
$string['info'] = 'Info';
$string['insights'] = 'Insights';
$string['invalidanalysables'] = 'Invalid site elements';
$string['invalidanalysablesinfo'] = 'This page lists analysable elements that can\'t be used by this prediction model. The listed elements can\'t be used either to train the prediction model nor can the prediction model obtain predictions for them.';
$string['invalidanalysablestable'] = 'Invalid site analysable elements table';
$string['invalidprediction'] = 'Invalid to get predictions';
$string['invalidtraining'] = 'Invalid to train the model';
$string['loginfo'] = 'Log extra info';
$string['modelid'] = 'Model ID';
$string['modelinvalidanalysables'] = 'Invalid analysable elements for "{$a}" model';
$string['modelresults'] = '{$a} results';
$string['modeltimesplitting'] = 'Time splitting';
$string['nextpage'] = 'Next page';
$string['nodatatoevaluate'] = 'There is no data to evaluate the model';
$string['nodatatopredict'] = 'No new elements to get predictions for';
$string['nodatatotrain'] = 'There is no new data that can be used for training';
$string['noinvalidanalysables'] = 'This site does not contain any invalid analysable element.';
$string['notdefined'] = 'Not yet defined';
$string['pluginname'] = 'Analytic models';
$string['predictionresults'] = 'Prediction results';
$string['predictmodels'] = 'Predict models';
$string['predictorresultsin'] = 'Predictor logged information in {$a} directory';
$string['predictionprocessfinished'] = 'Prediction process finished';
$string['previouspage'] = 'Previous page';
$string['samestartdate'] = 'Current start date is good';
$string['sameenddate'] = 'Current end date is good';
$string['target'] = 'Target';
$string['timesplittingnotdefined'] = 'Time splitting is not defined.';
$string['timesplittingnotdefined_help'] = 'You need to select a time-splitting method before enabling the model.';
$string['trainandpredictmodel'] = 'Training model and calculating predictions';
$string['trainingprocessfinished'] = 'Training process finished';
$string['trainingresults'] = 'Training results';
$string['trainmodels'] = 'Train models';
$string['viewlog'] = 'Log';
$string['weeksenddateautomaticallyset'] = 'End date automatically set based on start date and the number of sections';
$string['weeksenddatedefault'] = 'End date automatically calculated from the course start date.';
$string['privacy:metadata'] = 'The Analytic models plugin does not store any personal data.';
-241
View File
@@ -1,241 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Model-related actions.
*
* @package tool_analytics
* @copyright 2017 David Monllao {@link http://www.davidmonllao.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../config.php');
$id = required_param('id', PARAM_INT);
$action = required_param('action', PARAM_ALPHANUMEXT);
$context = context_system::instance();
require_login();
$model = new \core_analytics\model($id);
\core_analytics\manager::check_can_manage_models();
$params = array('id' => $id, 'action' => $action);
$url = new \moodle_url('/admin/tool/analytics/model.php', $params);
switch ($action) {
case 'edit':
$title = get_string('editmodel', 'tool_analytics', $model->get_target()->get_name());
break;
case 'evaluate':
$title = get_string('evaluatemodel', 'tool_analytics');
break;
case 'getpredictions':
$title = get_string('getpredictions', 'tool_analytics');
break;
case 'log':
$title = get_string('viewlog', 'tool_analytics');
break;
case 'enable':
$title = get_string('enable');
break;
case 'disable':
$title = get_string('disable');
break;
case 'export':
$title = get_string('export', 'tool_analytics');
break;
case 'clear':
$title = get_string('clearpredictions', 'tool_analytics');
break;
case 'invalidanalysables':
$title = get_string('invalidanalysables', 'tool_analytics');
break;
default:
throw new moodle_exception('errorunknownaction', 'analytics');
}
$PAGE->set_context($context);
$PAGE->set_url($url);
$PAGE->set_pagelayout('report');
$PAGE->set_title($title);
$PAGE->set_heading($title);
$onlycli = get_config('analytics', 'onlycli');
if ($onlycli === false) {
// Default applied if no config found.
$onlycli = 1;
}
switch ($action) {
case 'enable':
confirm_sesskey();
$model->enable();
redirect(new \moodle_url('/admin/tool/analytics/index.php'));
break;
case 'disable':
confirm_sesskey();
$model->update(0, false, false);
redirect(new \moodle_url('/admin/tool/analytics/index.php'));
break;
case 'edit':
confirm_sesskey();
if ($model->is_static()) {
echo $OUTPUT->header();
throw new moodle_exception('errornostaticedit', 'tool_analytics');
}
$customdata = array(
'id' => $model->get_id(),
'model' => $model,
'indicators' => $model->get_potential_indicators(),
'timesplittings' => \core_analytics\manager::get_enabled_time_splitting_methods()
);
$mform = new \tool_analytics\output\form\edit_model(null, $customdata);
if ($mform->is_cancelled()) {
redirect(new \moodle_url('/admin/tool/analytics/index.php'));
} else if ($data = $mform->get_data()) {
// Converting option names to class names.
$indicators = array();
foreach ($data->indicators as $indicator) {
$indicatorclass = \tool_analytics\output\helper::option_to_class($indicator);
$indicators[] = \core_analytics\manager::get_indicator($indicatorclass);
}
$timesplitting = \tool_analytics\output\helper::option_to_class($data->timesplitting);
$model->update($data->enabled, $indicators, $timesplitting);
redirect(new \moodle_url('/admin/tool/analytics/index.php'));
}
echo $OUTPUT->header();
$modelobj = $model->get_model_obj();
$callable = array('\tool_analytics\output\helper', 'class_to_option');
$modelobj->indicators = array_map($callable, json_decode($modelobj->indicators));
$modelobj->timesplitting = \tool_analytics\output\helper::class_to_option($modelobj->timesplitting);
$mform->set_data($modelobj);
$mform->display();
break;
case 'evaluate':
confirm_sesskey();
echo $OUTPUT->header();
if ($model->is_static()) {
throw new moodle_exception('errornostaticevaluate', 'tool_analytics');
}
if ($onlycli) {
throw new moodle_exception('erroronlycli', 'tool_analytics');
}
// Web interface is used by people who can not use CLI nor code stuff, always use
// cached stuff as they will change the model through the web interface as well
// which invalidates the previously analysed stuff.
$results = $model->evaluate(array('reuseprevanalysed' => true));
$renderer = $PAGE->get_renderer('tool_analytics');
echo $renderer->render_evaluate_results($results, $model->get_analyser()->get_logs());
break;
case 'getpredictions':
confirm_sesskey();
echo $OUTPUT->header();
if ($onlycli) {
throw new moodle_exception('erroronlycli', 'tool_analytics');
}
$trainresults = $model->train();
$trainlogs = $model->get_analyser()->get_logs();
// Looks dumb to get a new instance but better be conservative.
$model = new \core_analytics\model($model->get_model_obj());
if ($model->is_trained()) {
$predictresults = $model->predict();
$predictlogs = $model->get_analyser()->get_logs();
} else {
$predictresults = false;
$predictlogs = array();
}
$renderer = $PAGE->get_renderer('tool_analytics');
echo $renderer->render_get_predictions_results($trainresults, $trainlogs, $predictresults, $predictlogs);
break;
case 'log':
echo $OUTPUT->header();
if ($model->is_static()) {
throw new moodle_exception('errornostaticlog', 'tool_analytics');
}
$renderer = $PAGE->get_renderer('tool_analytics');
$modellogstable = new \tool_analytics\output\model_logs('model-' . $model->get_id(), $model);
echo $renderer->render_table($modellogstable);
break;
case 'export':
if ($model->is_static() || !$model->is_trained()) {
throw new moodle_exception('errornoexport', 'tool_analytics');
}
$file = $model->get_training_data();
if (!$file) {
redirect(new \moodle_url('/admin/tool/analytics/index.php'), get_string('errortrainingdataexport', 'tool_analytics'),
null, \core\output\notification::NOTIFY_ERROR);
}
$filename = 'training-data.' . $model->get_id() . '.' . time() . '.csv';
send_file($file, $filename, null, 0, false, true);
break;
case 'clear':
confirm_sesskey();
$model->clear();
redirect(new \moodle_url('/admin/tool/analytics/index.php'));
break;
case 'invalidanalysables':
echo $OUTPUT->header();
$page = optional_param('page', 0, PARAM_INT);
// No option in the UI to change this, only for url hackers ;).
$perpage = optional_param('perpage', 10, PARAM_INT);
$renderable = new \tool_analytics\output\invalid_analysables($model, $page, $perpage);
$renderer = $PAGE->get_renderer('tool_analytics');
echo $renderer->render($renderable);
break;
}
echo $OUTPUT->footer();
@@ -1,85 +0,0 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template tool_analytics/invalid_analysables
Template for invalid analysables.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"modelname": "Not engaging courses",
"analysables": [
{
"url": "<a href=\"#\">Maths</a>",
"validtraining": "Ongoing course",
"validprediction": "Not enough students activity"
}, {
"url": "<a href=\"#\">Psichology</a>",
"validtraining": "No students",
"validprediction": "No students"
}
]
}
}}
<div class="box">
<h3>{{#str}}modelinvalidanalysables, tool_analytics, {{modelname}}{{/str}}</h3>
<div>{{#str}}invalidanalysablesinfo, tool_analytics{{/str}}</div>
{{#noanalysables}}
<div class="m-t-2 m-b-1">
{{> core/notification_info}}
</div>
{{/noanalysables}}
{{^noanalysables}}
<div class="m-t-2 m-b-1">
<span>{{#prev}}{{> core/single_button}}{{/prev}}</span>
<span>{{#next}}{{> core/single_button}}{{/next}}</span>
</div>
<table class="generaltable fullwidth">
<caption class="accesshide">{{#str}}invalidanalysablestable, tool_analytics{{/str}}</caption>
<thead>
<tr>
<th scope="col">{{#str}}name{{/str}}</th>
<th scope="col">{{#str}}invalidtraining, tool_analytics{{/str}}</th>
<th scope="col">{{#str}}invalidprediction, tool_analytics{{/str}}</th>
</tr>
</thead>
<tbody>
{{#analysables}}
<tr>
<td>{{{url}}}</td>
<td>{{validtraining}}</td>
<td>{{validprediction}}</td>
</tr>
{{/analysables}}
</tbody>
</table>
<div class="m-t-1 m-b-2">
<span>{{#prev}}{{> core/single_button}}{{/prev}}</span>
<span>{{#next}}{{> core/single_button}}{{/next}}</span>
</div>
{{/noanalysables}}
</div>
@@ -1,186 +0,0 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template tool_analytics/models_list
Template for models list.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
"models": [
{
"target": "Prevent devs at risk",
"targethelp": [
{
"title": "Help with something",
"url": "http://example.org/help",
"linktext": "",
"icon":{
"extraclasses": "iconhelp",
"attributes": [
{"name": "src", "value": "../../../pix/help.svg"},
{"name": "alt", "value": "Help icon"}
]
}
}
],
"enabled": 1,
"indicators": [{
"name": "Indicator 1",
"help": [{
"title": "Help with something",
"url": "http://example.org/help",
"linktext": "",
"icon":{
"extraclasses": "iconhelp",
"attributes": [
{"name": "src", "value": "../../../pix/help.svg"},
{"name": "alt", "value": "Help icon"}
]
}
}]
},
{
"name": "Indicator 2",
"help": [{
"title": "Help with something",
"url": "http://example.org/help",
"linktext": "",
"icon":{
"extraclasses": "iconhelp",
"attributes": [
{"name": "src", "value": "../../../pix/help.svg"},
{"name": "alt", "value": "Help icon"}
]
}
}]
}],
"timesplitting": "Quarters",
"timesplittinghelp": [
{
"title": "Help with something",
"url": "http://example.org/help",
"linktext": "",
"icon":{
"extraclasses": "iconhelp",
"attributes": [
{"name": "src", "value": "../../../pix/help.svg"},
{"name": "alt", "value": "Help icon"}
]
}
}
],
"noinsights": "No insights available yet"
}
],
"warnings": {
"message": "Hey, this is a warning"
}
}
}}
{{#warnings}}
{{> core/notification_warning}}
{{/warnings}}
{{#infos}}
{{> core/notification_info}}
{{/infos}}
<div class="box">
<table class="generaltable fullwidth">
<caption>{{#str}}analyticmodels, tool_analytics{{/str}}</caption>
<thead>
<tr>
<th scope="col">{{#str}}target, tool_analytics{{/str}}</th>
<th scope="col">{{#str}}enabled, tool_analytics{{/str}}</th>
<th scope="col">{{#str}}indicators, tool_analytics{{/str}}</th>
<th scope="col">{{#str}}modeltimesplitting, tool_analytics{{/str}}</th>
<th scope="col">{{#str}}insights, tool_analytics{{/str}}</th>
<th scope="col">{{#str}}actions{{/str}}</th>
</tr>
</thead>
<tbody>
{{#models}}
<tr>
<td>
<span class="target-name">{{target}}</span>
{{#targethelp}}
{{>core/help_icon}}
{{/targethelp}}
</td>
<td>
{{#enabled}}
{{#pix}}i/checked, core, {{#str}}yes{{/str}}{{/pix}}
{{/enabled}}
{{^enabled}}
{{#str}}no{{/str}}
{{/enabled}}
</td>
<td>
<ul>
{{#indicators}}
<li>
{{name}}
{{#help}}
{{>core/help_icon}}
{{/help}}
</li>
{{/indicators}}
</ul>
</td>
<td>
{{#timesplitting}}
{{timesplitting}}
{{#timesplittinghelp}}
{{>core/help_icon}}
{{/timesplittinghelp}}
{{/timesplitting}}
{{^timesplitting}}
{{#str}}notdefined, tool_analytics{{/str}}
{{#timesplittinghelp}}
{{>core/help_icon}}
{{/timesplittinghelp}}
{{/timesplitting}}
</td>
<td>
{{! models_list renderer is responsible of sending one or the other}}
{{#insights}}
{{> core/single_select }}
{{/insights}}
{{#noinsights}}
{{.}}
{{/noinsights}}
</td>
<td>
{{#actions}}
{{> core/action_menu}}
{{/actions}}
</td>
</tr>
{{/models}}
</tbody>
</table>
</div>
@@ -1,73 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for tool_assignmentupgrade.
*
* @package tool_assignmentupgrade
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_assignmentupgrade\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\writer;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_assignmentupgrade implementing metadata, plugin, and user_preference providers.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\user_preference_provider {
/**
* Returns meta data about this system.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection) : collection {
$collection->add_user_preference(
'tool_assignmentupgrade_perpage',
'privacy:metadata:preference:perpage'
);
return $collection;
}
/**
* Export all user preferences for the plugin.
*
* @param int $userid The userid of the user whose data is to be exported.
*/
public static function export_user_preferences(int $userid) {
$perpage = get_user_preferences('tool_assignmentupgrade_perpage', null, $userid);
if ($perpage !== null) {
writer::export_user_preference(
'tool_assignmentupgrade',
'perpage',
$perpage,
get_string('privacy:metadata:preference:perpage', 'tool_assignmentupgrade')
);
}
}
}
@@ -58,4 +58,3 @@ $string['upgradeallconfirm'] = 'Upgrade all assignments?';
$string['upgradeprogress'] = 'Upgrade assignment {$a->current} of {$a->total}';
$string['upgradesingle'] = 'Upgrade single assignment';
$string['viewcourse'] = 'View the course with the converted assignment';
$string['privacy:metadata:preference:perpage'] = 'The assignment upgrade records per page preference set for the user.';
@@ -1,75 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy tests for tool_assignmentupgrade.
*
* @package tool_assignmentupgrade
* @category test
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
use \core_privacy\tests\provider_testcase;
use \core_privacy\local\request\writer;
use \tool_assignmentupgrade\privacy\provider;
/**
* Unit tests for tool_assignmentupgrade/classes/privacy/policy
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_assignmentupgrade_privacy_testcase extends provider_testcase {
/**
* Overriding setUp() function to always reset after tests.
*/
public function setUp() {
$this->resetAfterTest(true);
}
/**
* Test for provider::test_export_user_preferences().
*/
public function test_export_user_preferences() {
// Test setup.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
// Add a user home page preference for the User.
set_user_preference('tool_assignmentupgrade_perpage', '100', $user);
// Test the user preference exists.
$params = [
'userid' => $user->id,
'name' => 'tool_assignmentupgrade_perpage'
];
// Test the user preferences export contains 1 user preference record for the User.
provider::export_user_preferences($user->id);
$contextuser = context_user::instance($user->id);
$writer = writer::with_context($contextuser);
$this->assertTrue($writer->has_any_data());
$exportedpreferences = $writer->get_user_preferences('tool_assignmentupgrade');
$this->assertCount(1, (array) $exportedpreferences);
$this->assertEquals('100', $exportedpreferences->perpage->value);
}
}
+3 -3
View File
@@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018051400;
$plugin->requires = 2018050800;
$plugin->version = 2017051500;
$plugin->requires = 2017050500;
$plugin->component = 'tool_assignmentupgrade';
$plugin->dependencies = array('mod_assign' => 2018050800);
$plugin->dependencies = array('mod_assign' => 2017050500);
@@ -1,46 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for tool_availabilityconditions.
*
* @package tool_availabilityconditions
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_availabilityconditions\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_availabilityconditions implementing null_provider.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}
@@ -24,4 +24,3 @@
$string['manageplugins'] = 'Manage restrictions';
$string['pluginname'] = 'Availability condition management';
$string['privacy:metadata'] = 'The Availability condition management plugin does not store any personal data.';
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018051400;
$plugin->requires = 2018050800;
$plugin->version = 2017051500;
$plugin->requires = 2017050500;
$plugin->component = 'tool_availabilityconditions';
@@ -1,46 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for tool_behat.
*
* @package tool_behat
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_behat\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_behat implementing null_provider.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason() : string {
return 'privacy:metadata';
}
}

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