Compare commits

..

1258 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 5c5ee48bf6 Moodle release 3.3.9 2018-11-10 20:36:16 +01:00
Eloy Lafuente (stronk7) 040430abff weekly release 3.3.8+ 2018-11-10 12:53:14 +01:00
Eloy Lafuente (stronk7) 2582943f92 Merge branch 'MDL-63960-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-11-10 10:28:39 +01:00
Andrew Nicols 97e8c0abce MDL-63960 dataprivacy: Do not perform strict type checks for id
When inherit is specified in the data registry it is stored as a
string and we cannot perform a strict comparison with it.

We should still compare strict comparison checks against null, or false,
but not for the NOTSET (0) or INHERIT values (-1).
2018-11-10 15:34:11 +08:00
Eloy Lafuente (stronk7) 51894a816f MDL-63919 tool_dataprivacy: admin & notify fixes
This includes the following:

1) Replace $ADMIN->id by get_admin()->id. The former doesn't exist.
2) Only change the notify parameter when it has not been specified
   at creation time (null). If specified, observe it.
3) Set the current user in tests to admin, able to create those
   requests.
2018-11-10 11:01:14 +08:00
Andrew Nicols c0ac0bd256 MDL-62564 tool_dataprivacy: Do not delete deleted user
This also ensures that we do not call delete_user on an already deleted
user.
2018-11-09 17:37:27 +08:00
Jun Pataleta a5c5651a0f Merge branch 'MDL-63942-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-11-09 11:42:11 +08:00
Andrew Nicols 01e64f89c7 Merge branch 'MDL-63919-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-11-09 10:53:48 +08:00
Andrew Nicols a505a4abd7 MDL-63942 dataprivacy: Disable deleted user task by default 2018-11-09 09:39:35 +08:00
Eloy Lafuente (stronk7) c587194dee Merge branch 'MDL-62564-integration-33-1' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-11-08 16:50:45 +01:00
Mihail Geshoski 76c9202996 MDL-63919 privacy: Store the creation method of the data request 2018-11-08 14:50:36 +08:00
Mihail Geshoski 752b63d574 MDL-63919 privacy: Disable notifications for auto created data requests 2018-11-08 14:50:36 +08:00
Mihail Geshoski 4cd4b14df2 MDL-62564 privacy: Create request for deleted users when setting enabled 2018-11-08 10:27:26 +08:00
Mihail Geshoski a49f5519e2 MDL-62564 privacy: Improve bulk deletion 2018-11-08 10:26:40 +08:00
Mihail Geshoski d494848985 MDL-62564 privacy: Add unit tests 2018-11-08 10:15:59 +08:00
Jun Pataleta 950da9db66 MDL-63183 auth_shibboleth: Don't render page when already logged in 2018-11-06 19:10:58 +01:00
Jun Pataleta d3c9d9306c MDL-63183 auth_shibboleth: Add hidden login token in guest login form 2018-11-06 19:10:58 +01:00
Damyon Wiese ff7941f00e MDL-63183 auth: Login protection
CSRF protection for the login form. The authenticate_user_login function was
extended to validate the token (in \core\session\manager) but by default it
does not perform the extra validation. Existing uses of this function from
auth plugins and features like "change password" will continue to work without
changes. New config value $CFG->disablelogintoken can bypass this check.
2018-11-06 19:10:58 +01:00
Eloy Lafuente (stronk7) a02c72d8bb weekly release 3.3.8+ 2018-11-06 19:06:35 +01:00
Eloy Lafuente (stronk7) 3d1ee2568e Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-11-06 19:06:33 +01:00
Andrew Nicols bb560c7012 Merge branch 'MDL-62563-33-3' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-11-06 09:57:19 +08:00
AMOS bot 0e8ebb0ead Automatically generated installer lang files 2018-11-06 00:07:43 +00:00
Mihail Geshoski 0375eb8488 MDL-62563 privacy: Create delete data request for existing deleted users 2018-11-05 16:29:47 +08:00
Mihail Geshoski 1f258e679a MDL-62563 privacy: Add unit tests 2018-11-05 16:22:17 +08:00
Eloy Lafuente (stronk7) 13d2621e23 weekly release 3.3.8+ 2018-11-02 21:08:30 +01:00
David Monllao 2709ae4dcc Merge branch 'MDL-62601-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-10-31 06:47:59 +01:00
Andrew Nicols 9aa05ccfdd MDL-62601 core_privacy: Ensure providers can handle deleted users 2018-10-31 13:44:51 +08:00
Andrew Nicols 6855ebb1eb MDL-62601 editor_atto: Do not use context_user 2018-10-31 13:44:51 +08:00
Eloy Lafuente (stronk7) 3d1949af87 weekly release 3.3.8+ 2018-10-30 18:23:58 +01:00
Andrew Nicols 3cda2cab0e Merge branch 'MDL-63626-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-10-30 11:00:43 +08:00
Andrew Nicols e899bccd8e MDL-63267 privacy: Remove use of int hints 2018-10-28 18:16:12 +08:00
Andrew Nicols a94a0c565b MDL-63267 core_grading: More Fix 5.6 type hints 2018-10-27 19:55:13 +08:00
Andrew Nicols 1171be0c0a MDL-63267 core_grading: Fix 5.6 type hints 2018-10-27 19:52:37 +08:00
Andrew Nicols 12963c1460 Merge branch 'MDL-63267-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2018-10-27 19:30:23 +08:00
Tim Lock d5fea5ba37 MDL-63267 tool_privacy: Handle modules without privacy support. 2018-10-26 18:51:38 -04:00
Adrian Greeve 76a361a821 MDL-63267 grading methods: Unit test update for fix. 2018-10-26 18:51:38 -04:00
Adrian Greeve fb1740d897 MDL-63267 grading methods: Fix for multiple intances.
We were only exporting the one instance per item id.
Instead we should have been exporting all instances for each
item id.
2018-10-26 18:51:38 -04:00
Adrian Greeve 95433e3763 MDL-63267 tool_dataprivacy: Registry shows deprecated interfaces. 2018-10-26 18:51:38 -04:00
Adrian Greeve af7362c323 MDL-63267 privacy: Create deprecated provider interface.
Any interfaces that have become deprecated should extend
this interface.
2018-10-26 18:51:38 -04:00
Adrian Greeve 07d283e56e MDL-63267 core_grading: Unit test for new methods. 2018-10-26 18:51:38 -04:00
Adrian Greeve f1608e1184 MDL-63267 mod_assign: Update to providers to include adv grading. 2018-10-26 18:51:38 -04:00
Adrian Greeve 958dfb534d MDL-63267 core_grading: Update to providers and interface.
The previous interface was inadequate for retrieving user
information stored in the sub-plugins.

A new interface and methods have been added to successfully
deal with user data.
2018-10-26 18:51:31 -04:00
Eloy Lafuente (stronk7) aa561d76e8 weekly release 3.3.8+ 2018-10-26 18:05:00 +02:00
Eloy Lafuente (stronk7) fd497585a8 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-10-26 18:04:58 +02:00
Eloy Lafuente (stronk7) 62c1be5b19 Merge branch 'MDL-62904-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-10-26 00:04:09 +02:00
Andrew Nicols 258057604b MDL-63619 tool_dataprivacy: Cache purposes in form 2018-10-24 08:56:04 +08:00
Andrew Nicols e21e6d3d5b MDL-63619 tool_dataprivacy: Performance improvement 2018-10-24 08:56:04 +08:00
Andrew Nicols dbf4da68de MDL-63619 tool_dataprivacy: Fix inheritance from parent contexts
Inheritance should behave such that all contexts inherit from their
parent context.

Prior to this fix, if the value was not set on a context, then it was
getting a default of 'Inherit', but instead of inheritting from the
parent context, it was inheritting from its parent context _level_ which
is just wrong.
2018-10-24 08:56:04 +08:00
AMOS bot 20f17d1ee3 Automatically generated installer lang files 2018-10-22 00:07:36 +00:00
Eloy Lafuente (stronk7) a0d09bb67e weekly release 3.3.8+ 2018-10-19 17:10:47 +02:00
Eloy Lafuente (stronk7) fc77529235 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-10-19 17:10:45 +02:00
AMOS bot de2c1990eb Automatically generated installer lang files 2018-10-19 00:08:27 +00:00
Eloy Lafuente (stronk7) f8191ba10f Merge branch 'MDL-63632-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-10-18 02:39:43 +02:00
AMOS bot 3ea8d9d89a Automatically generated installer lang files 2018-10-18 00:07:44 +00:00
Andrew Nicols ceb8d8dc60 MDL-63632 forum: Delete where not discussion author 2018-10-18 07:20:29 +08:00
Jun Pataleta 4f232817c2 MDL-62904 tool_dataprivacy: Add data request links in profile page 2018-10-17 16:44:09 +08:00
Eloy Lafuente (stronk7) dabce49529 weekly release 3.3.8+ 2018-10-16 16:05:28 +02:00
Eloy Lafuente (stronk7) 67cc6f70c1 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-10-16 16:05:26 +02:00
Andrew Nicols 33adcf9926 Merge branch 'MDL-63421_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-10-16 08:56:20 +08:00
AMOS bot 7d3536fb48 Automatically generated installer lang files 2018-10-15 00:07:35 +00:00
Shamim Rezaie 0d7f464d4b MDL-63626 mod_quiz: Fixed a bug when there was no attempt on the quiz 2018-10-12 01:02:16 +11:00
Eloy Lafuente (stronk7) 629a97d5c1 weekly release 3.3.8+ 2018-10-11 13:22:43 +02:00
Eloy Lafuente (stronk7) 16f8828e9f Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-10-11 13:22:40 +02:00
AMOS bot fbfa3a0bd2 Automatically generated installer lang files 2018-10-11 00:07:33 +00:00
AMOS bot bb9bb21546 Automatically generated installer lang files 2018-10-10 00:07:30 +00:00
Eloy Lafuente (stronk7) b1da31a63e Merge branch 'MDL-62395-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-10-09 23:07:07 +02:00
Eloy Lafuente (stronk7) c165ee4890 Merge branch 'MDL-63401-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-10-09 11:36:58 +02:00
Adrian Greeve 0446552496 MDL-62491 core_privacy: php 5.6 fix for using current() 2018-10-09 16:22:25 +08:00
Jun Pataleta 7e954344d2 Merge branch 'MDL-62491-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-10-09 14:39:25 +08:00
Adrian Greeve efd6748031 MDL-62491 navigation: Update to tree.js to allow callbacks. 2018-10-09 14:33:16 +08:00
Adrian Greeve 493f79cc6a MDL-62491 mod_assign: Fill in the rewrite plugin urls properly. 2018-10-09 14:33:16 +08:00
Adrian Greeve 0231ce53b1 MDL-62491 core_privacy: Add html files to the user data export.
This adds html to the data export that allows for easier navigation
and reading of data.
2018-10-09 14:33:16 +08:00
Andrew Nicols 222c900018 MDL-63401 tool_dataprivacy: Change default for require end date
We should preserve the existing behaviour.
2018-10-09 08:32:18 +08:00
Andrew Nicols e4d181c4de MDL-63401 tool_dataprivacy: Simplify where processing 2018-10-09 08:22:26 +08:00
Andrew Nicols 56b96699a6 MDL-63401 tool_dataprivacy: Move final cap check to endpoint 2018-10-09 08:22:26 +08:00
Andrew Nicols 5bc61c9686 MDL-63401 tool_dataprivacy: Allow expiriration of users without end date 2018-10-08 20:54:22 +08:00
Andrew Nicols 62165df6dd MDL-63401 tool_dataprivacy: Rewrite expired deletion handling
This change rewrites the way in which expiry is calculated and addresses
a number of closely related issues:

Users can customise, and add blocks with data to, their dashboard.  When
a user had done so, the user could be flagged for deletion, but the
blocks in their Dashboard were subject to the default block retention
policy. In addition there is no way to override the retention policy for
user blocks.

This change modifies the structure of the expiry mechanism:
- to consider any subcontext of the user context to be a part of the user
  context during calculation. User child contexts are not the property
  of the system, and should not be treated separately.
- the way in which the context expiry mechanism worked was to select
  use a multiple different managers based solely on the context level.
  Because of the use of user blocks, this proved to be unreliable as
  blocks has been attributed purely to courses.
  This has been changed to a single manager which is aware of hierarchy
  and deletions as a whole.
- to prepare for upcoming work relating to more detailed expiry
  mechanisms, a new expiry_info class is introduced and used to
  merge the expiry of child contexts into a working in-memory view.

This changeset includes extensive unit tests.
2018-10-08 20:54:20 +08:00
Andrew Nicols 0cd43cccbf MDL-63401 core: Do not delete the user context
As long as we have a user record, we should not delete the context which
relates to it.
2018-10-08 20:54:00 +08:00
Andrew Nicols 0b9cf6ba5e MDL-63401 tool_dataprivacy: Move cap checks to endpoints from API 2018-10-08 20:54:00 +08:00
Eloy Lafuente (stronk7) 6ef7759473 MDL-63421 env: Moodle 3.4.x and 3.5.x do not support PHP 7.3 2018-10-05 13:38:40 +02:00
Eloy Lafuente (stronk7) 6816976c3b weekly release 3.3.8+ 2018-10-05 12:27:53 +02:00
Jun Pataleta 6e7a73c16d MDL-62395 tool_dataprivacy: Purpose name and description in one column
* Show the purpose's name and description under one column.
2018-10-05 09:29:12 +08:00
Jun Pataleta 6fc275038c MDL-62395 tool_dataprivacy: Fix tables display
* Use standard Bootstrap4 table classes for the categories and purposes
  tables.
* Set 25% width for the name and description columns of the purposes
  table.
* Set 50% width for the description column of the categories table.
2018-10-05 09:29:12 +08:00
AMOS bot 41548fb26e Automatically generated installer lang files 2018-10-04 00:07:37 +00:00
Eloy Lafuente (stronk7) 082ef8ef3c weekly release 3.3.8+ 2018-09-27 15:17:50 +02:00
Andrew Nicols 371168e848 Merge branch 'MDL-63346_33' of https://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-09-25 09:13:44 +08:00
Eloy Lafuente (stronk7) 982839422f weekly release 3.3.8+ 2018-09-20 12:11:59 +02:00
Eloy Lafuente (stronk7) cc22614602 MDL-63346 nodejs: Bump to created from scratch shrinkwrap file
Steps:

- remove node_modules & npm-shrinkwrap.json
- npm cache clear --force
- npm install
- npm shrinkwrap
2018-09-20 10:56:29 +02:00
Eloy Lafuente (stronk7) 094fa8ce8a MDL-63346 travis: GRUNT job immune to npm-shrinkwrap.json changes
When upgrading nodejs/npm versions, there are modifications to
different packages or to the format of the npm-shrinkwrap.json
file. Usually that leads to failed jobs untill the bundled file
is updated.

To avoid that, we just ignore the npm-shrinkwrap.json file, so
just the REAL modifications in css/js/ignore stuff are considered.
2018-09-20 10:55:20 +02:00
Eloy Lafuente (stronk7) eca5403915 Merge branch 'MDL-63116-33-1' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-09-18 23:54:41 +02:00
Mihail Geshoski 5924e71021 MDL-61908 privacy: Fix heading in data privacy pages 2018-09-18 18:51:43 +02:00
Eloy Lafuente (stronk7) b9706f8cf3 Merge branch 'MDL-63109-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-09-18 18:32:26 +02:00
Mihail Geshoski b17a7d65a7 MDL-63109 privacy: Add behat tests 2018-09-18 15:08:54 +08:00
Mihail Geshoski 558126aee6 MDL-63109 privacy: Fix the initialisation of the policy acceptance modal 2018-09-18 15:05:15 +08:00
Eloy Lafuente (stronk7) 1cec2b9041 Merge branch 'MDL-63009-33' of git://github.com/mickhawkins/moodle into MOODLE_33_STABLE 2018-09-17 23:31:38 +02:00
Eloy Lafuente (stronk7) 5279b38c8b Merge branch 'MDL-63184-33-2' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-09-17 23:11:54 +02:00
Jun Pataleta 286e9ef666 MDL-63184 tool_dataprivacy: Ensure PO roles have correct capability 2018-09-17 22:36:16 +08:00
David Monllao 026b1ffe51 Merge branch 'MDL-62554-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-09-17 13:46:17 +02:00
Mihail Geshoski 6eddcd1310 MDL-63116 privacy: Add bulk actions to the privacy request table 2018-09-17 08:28:28 +08:00
Mihail Geshoski 4bb3e3fccf MDL-63116 privacy: Add behat tests 2018-09-17 08:28:28 +08:00
Mihail Geshoski be23442e17 MDL-63116 privacy: Add unit tests 2018-09-17 08:28:28 +08:00
Eloy Lafuente (stronk7) e75470d531 weekly release 3.3.8+ 2018-09-14 11:06:45 +02:00
Eloy Lafuente (stronk7) c9a28c645b MDL-61169 iplookup: Change to another block still remaining to SF 2018-09-13 19:07:07 +02:00
Jun Pataleta df84f822bf MDL-62554 tool_dataprivacy: Integration review fixes 2018-09-13 14:58:27 +08:00
Michael Hawkins 4ca488c639 MDL-63009 tool_dataprivacy: Added site name/link to request emails 2018-09-12 17:50:38 +08:00
Jun Pataleta 745f6e7f61 MDL-62554 tool_dataprivacy: Bump version for new WS functions 2018-09-10 12:21:40 +08:00
Jun Pataleta f5b95df245 MDL-62554 tool_dataprivacy: Fix display of activity options 2018-09-10 12:21:40 +08:00
Jun Pataleta 12131e4806 MDL-62554 tool_dataprivacy: Fix template for Bootstrapbase compatibility 2018-09-10 12:21:40 +08:00
Jun Pataleta 2dfd3b9839 MDL-62554 tool_dataprivacy: Remove defaults form
With the changes in this issue, this form is no longer being used.
2018-09-10 12:21:40 +08:00
Jun Pataleta f68fe6bc00 MDL-62554 tool_dataprivacy: Behat tests for managing registry defaults
* Also new step definitions and generator for:
  - Creating categories and purposes
  - Assigning category and purpose to context instances.
2018-09-10 12:21:40 +08:00
Jun Pataleta ea8b23542a MDL-62554 tool_dataprivacy: Unit tests for new WS/API functions 2018-09-10 12:21:40 +08:00
Jun Pataleta 1a228ad894 MDL-62554 tool_dataprivacy: Fix fetching of default contexts
* We also need to handle default contexts for activities. If defaults
  for an activity is set, fetch that. If not, fetch the defaults for
  the context level.
2018-09-10 12:21:40 +08:00
Jun Pataleta 324e9a2800 MDL-62554 tool_dataprivacy: Allow setting of activity defaults
* Allow the setting of data registry defaults for activity modules.
* Rewrite the defaults page so that it uses templates.
* Use a tabbed layout for the defaults page that shows the default
  category and purpose per context level.
* New API and web service functions that enables the setting of the
  defaults.
2018-09-10 12:21:40 +08:00
Eloy Lafuente (stronk7) c37329dc10 Moodle release 3.3.8 2018-09-08 16:49:39 +02:00
AMOS bot c3dbe66477 Automatically generated installer lang files 2018-09-08 00:07:55 +00:00
Jun Pataleta 3bfd32be9b weekly release 3.3.7+ 2018-09-07 11:11:40 +08:00
Jun Pataleta 85a42937b9 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-09-07 11:11:11 +08:00
Jake Dallimore c3db28fe90 Merge branch 'MDL-63302-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-09-06 09:25:10 +08:00
Jun Pataleta 2f1c8a398b MDL-63302 tool_dataprivacy: Increment version of the merged plugin
This is to distinguish the versions available from the plugins directory
from the versions that are part of Moodle standard distribution.
2018-09-06 08:54:23 +08:00
Eloy Lafuente (stronk7) e7c034a8d8 Merge branch 'MDL-63292-33-policyversion' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-09-05 21:10:48 +02:00
David Mudrák 5a6185300a MDL-63292 tool_policy: Increment version of the merged plugin
This is to distinguish the versions available from the plugins directory
from the versions that are part of Moodle standard distribution.
2018-09-05 14:03:15 +02:00
Jake Dallimore 9ab746af27 MDL-62947 mod_feedback: fix feedback so it correctly uses forms API
Feedback code was doing the following, which is incompatible with the
sec-patched quickforms lib:
- appending '[0]' to non-group element names, meaning type checks in
getCleanType() were falling back to PARAM_RAW instead of PARAM_INT,
and meaning _findValue() was comparing elements it thought to be arrays
with scalar submit values (worked with eval() implementation as the 0th
element of a string was the character, but not working when patched).
- external unit tests incorrectly testing multichoice questions in the
process_page tests - patched lib highlighted failures.

It was also doing the following:
- actively setting null as default element values instead of 0 for
radio buttons and dropdowns (for 'not selected'). This is incompatible
with more recent quickforms lib (see MDL-63070).
- creating groups using addElement instead of addGroup - not recommended

This patch addresses the above.
2018-09-05 12:14:05 +08:00
Jake Dallimore a21f18e947 MDL-62947 core_form: fix remote code execution exploit in QuickForms
Applies the patch found upstream:
https://github.com/pear/HTML_QuickForm/commit/
d3a6d5c44dedf3c164c6c79198e4ef479bcedcd2 and make util methods static
for php7 compatibility.
2018-09-05 12:14:05 +08:00
AMOS bot 711d42778a Automatically generated installer lang files 2018-09-05 00:07:48 +00:00
Damyon Wiese d2a497ee03 MDL-62748 course: maxsections is a limit
For course formats shipped with core, maxsections should be a limit to the number of sections
allowed in the course.
2018-09-04 14:40:43 +02:00
Mihail Geshoski 3f8dfe2ab7 MDL-62857 theme_boost: Better filtering on navbar / breadcrumbs 2018-09-04 14:40:43 +02:00
Tim Hunt 09cbca8566 MDL-62880 qtype_ddwtos: drop support for legacy import format
It was more than 8 years since we wrote in that format.
2018-09-04 14:40:43 +02:00
David Monllao 1c2efd6f1b Merge branch 'MDL-62342-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-09-04 14:34:19 +02:00
Jun Pataleta 751bdfd50d Merge branch 'MDL-60901_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-09-04 10:17:54 +08:00
Eloy Lafuente (stronk7) 19c1e9845b MDL-60901 environment: 3.6 requirements
Changes include:
- MySQL 5.6 is required.
- PostgreSQL 8.4 is required.
- Oracle 11.2 is required.
- 64bits architecture is recommended.
2018-09-03 10:13:44 +02:00
Mihail Geshoski 64a736ee72 MDL-62342 privacy: Fix strings used in the consent on behalf modal 2018-09-03 13:02:16 +08:00
Mihail Geshoski 1f319dda3d MDL-62342 privacy: Use singular/plural form in labels 2018-09-03 13:02:16 +08:00
AMOS bot 5790e87939 Automatically generated installer lang files 2018-09-02 00:07:46 +00:00
AMOS bot 40260a258f Automatically generated installer lang files 2018-09-01 00:07:46 +00:00
Eloy Lafuente (stronk7) 86f3c074e9 weekly release 3.3.7+ 2018-08-30 19:04:15 +02:00
Eloy Lafuente (stronk7) cfac8bb5ab Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-08-30 19:04:12 +02:00
Jake Dallimore 772afa0f43 Merge branch 'MDL-63094-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-08-30 13:10:45 +08:00
Andrew Nicols 111ec01643 MDL-63094 tool_policy: Replace '×' with '.close'
This relates to MDL-59883, which was not backported to 33 and beyond.
2018-08-30 11:25:44 +08:00
AMOS bot cf21130cc2 Automatically generated installer lang files 2018-08-30 00:08:24 +00:00
Eloy Lafuente (stronk7) a454fd5f57 Merge branch 'MDL-63094-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-08-29 00:25:18 +02:00
Jun Pataleta 300e220dbc MDL-63187 tool_dataprivacy: Reopen autocomplete on legal basis selection
* The multiselect autocomplete element closes after selection on 33. The
feature where it keeps open on multiselection has only been implemented
since 34 and up. So to select another legal basis, we need to reopen
the autocomplete element again.
2018-08-28 21:05:14 +08:00
Jake Dallimore 5432075187 Merge branch 'MDL-63101-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-08-28 16:56:32 +08:00
Eloy Lafuente (stronk7) a51fa84f50 Merge branch 'MDL-62989-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-08-27 17:51:47 +02:00
Jun Pataleta 052d30081e MDL-63187 tool_dataprivacy: Behat fixes for confirmation lang strings 2018-08-27 22:45:20 +08:00
David Monllao ab883ad6b0 MDL-63187 tool_dataprivacy: Update delete purpose and category lang strings 2018-08-27 12:12:12 +02:00
David Monllao 6069d11046 Merge branch 'MDL-63187-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-08-27 11:59:37 +02:00
Andrew Nicols 1875af2207 MDL-63101 cache: Improve accuracy of cache event invalidation 2018-08-27 14:44:42 +08:00
Mihail Geshoski 65b8d2ab7d MDL-62989 privacy: Improve data request order for users 2018-08-24 15:35:23 +08:00
Jake Dallimore b39379cb98 weekly release 3.3.7+ 2018-08-24 13:08:51 +08:00
Jun Pataleta c840b579cb MDL-63187 tool_dataprivacy: Improve confirm message lang strings
* Updated the delete confirmation messages so that the category/purpose
names are shown in italics. This makes it easier for the privacy officer
to see the category/purpose that is being deleted.
2018-08-23 16:59:13 +08:00
Jun Pataleta 784c21b116 MDL-63187 tool_dataprivacy: Behat tests for purposes/categories CRUD 2018-08-23 16:59:13 +08:00
Jun Pataleta f423dd8ccf MDL-63187 tool_dataprivacy: Fix delete button text
* No need to add the purpose/category name for the delete button itself
* Fix delete confirmation lang strings.
* Add button titles to Add purpose/category buttons so they can be
  clicked on when running Behat tests.
2018-08-23 16:59:13 +08:00
Andrew Nicols f5d57e74bf MDL-63094 tool_policy: Fix the cookie banner to the bottom
Floating banners cause issues with clickability in Behat as it is unable
to understand that it cannot interact with the elements underneath the
floating banner, or that it needs to scroll the page so that the
required content is no longer beneath the floating banner.

Changing the banner to be fixed to the bottom of the page during Behat
runes is a reliable fix.
2018-08-22 11:00:08 +08:00
Andrew Nicols e67669e638 MDL-63094 js: Do not check visibility before hiding backdrop
It's possible for the backdrop to be created during the show, before the
modal is actually fully shown.

This check is unnecessary because the getBackdrop() function always
returns a value and will always succeed.
2018-08-22 10:29:33 +08:00
Andrew Nicols aa881b7717 MDL-63094 tool_policy: Fix race condition in modal display
The way in which the modal was displayed meant that there were no
pending JS items, whilst the modal was rendered, causing random behat
fails.

This JS has been restructured to create the Modal and pass it a set of
Promises for both the title, and body.
2018-08-22 10:28:45 +08:00
Andrew Nicols 19a94ef923 Merge branch 'MDL-62660_33' of https://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-08-22 08:05:03 +08:00
Eloy Lafuente (stronk7) 866d7a064a MDL-62660 xmldb: fix tool_dataprivacy_request_>status to int(2)
So the new defined statuses fit in the column for all databases.
2018-08-22 00:08:01 +02:00
Andrew Nicols 1d5b6e94ee Merge branch 'MDL-62660-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-08-21 11:14:34 +08:00
Jun Pataleta 014628c4c4 MDL-62660 tool_dataprivacy: Behat fix for data deletion 2018-08-21 10:39:12 +08:00
Jun Pataleta 61b0e103b7 MDL-62660 tool_dataprivacy: CI fixes 2018-08-21 09:52:59 +08:00
Jun Pataleta 2a0c44b56d MDL-62660 phpunit: Remove setting of user when running adhoc tasks
Before 3.4 tasks can't run as specific users.
2018-08-21 09:52:59 +08:00
Michael Hawkins ab79c7bf95 MDL-62660 tool_dataprivacy: Behat additions for deletion and data expiry 2018-08-21 09:52:59 +08:00
Michael Hawkins 4415985085 MDL-62660 tool_dataprivacy: Add and update PHPUnit tests
Updated tests with latest statuses.
Added testing for request download expiry functionality and method.
Added assign_site_dpo within a parent class for unit tests.
2018-08-21 09:52:59 +08:00
Michael Hawkins 83c83473f8 MDL-62660 tool_dataprivacy: Add scheduled task to expire data requests 2018-08-21 09:52:59 +08:00
Jun Pataleta 680b9186c7 MDL-62660 tool_dataprivacy: Fix version number in upgrade code 2018-08-21 09:52:59 +08:00
Michael Hawkins 3717d20a33 MDL-62660 tool_dataprivacy: Add ability to expire data requests
Also replaced Completed status with situation specific statuses.
Also improved UX on request pages in line with expiries and the aadditional statuses.
2018-08-21 09:52:59 +08:00
Andrew Nicols e29b668d7b MDL-62660 tool_dataprivacy: Add method for unit tests to run adhoc tasks 2018-08-21 09:52:59 +08:00
Eloy Lafuente (stronk7) 8987e225da weekly release 3.3.7+ 2018-08-17 17:37:34 +02:00
Eloy Lafuente (stronk7) b96151e864 NOBUG: Fixed file access permissions 2018-08-17 17:37:34 +02:00
Eloy Lafuente (stronk7) 1c6f6505b9 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-08-17 17:37:32 +02:00
Damyon Wiese 884aa7b9f7 MDL-62884 privacy: Additional fix for popper.js
The older version of popper needs custom CSS to ensure the menus are
visible without scrolling.
2018-08-17 16:08:09 +08:00
Damyon Wiese 082f2f7dd8 MDL-62884 privacy: Fix styles
An action menu displayed inside a table needs to be tested on every theme. It is
required to ensure that the menu displays correctly, even when it would display outside
the scrollable region for the table.
2018-08-17 16:08:03 +08:00
Jake Dallimore 9bec7f417f Merge branch 'MDL-63050-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-08-16 02:34:29 +02:00
Andrew Nicols b3865f159b Merge branch 'MDL-62600-33' of git://github.com/mickhawkins/moodle into MOODLE_33_STABLE 2018-08-16 02:34:26 +02:00
AMOS bot f03a28c520 Automatically generated installer lang files 2018-08-16 00:08:36 +00:00
AMOS bot 68d882a927 Automatically generated installer lang files 2018-08-15 00:07:58 +00:00
Michael Hawkins 41b628707c MDL-62600 tool_dataprivacy: Corrected availability of PO pages to admins 2018-08-14 13:20:14 +08:00
Karen Holland 2d287b27e3 MDL-62896 Privacy: External plugin Additional label update. 2018-08-14 08:06:14 +08:00
Andrew Nicols b76d708315 Merge branch 'MDL-62799-33-2' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-08-13 13:55:20 +08:00
Jun Pataleta 1f2972764b MDL-62799 core: Add tool_dataprivacy to list of standard plugins 2018-08-13 12:45:35 +08:00
Jun Pataleta 2161e3294d MDL-62799 tool_dataprivacy: Add new data request modal type
* Add a new TYPE_ENQUIRY modal type for the data request modal AMD
  module in order for it to be able to render the appropriate template
  as required:
  1. Use the tool_dataprivacy/data_request_modal template for data
     export/deletion requests;
  2. Or use the tool_dataprivacy/mark_request_complete_modal template
     for general enquiries.
2018-08-13 12:27:07 +08:00
Jun Pataleta 898584944b MDL-62799 tool_dataprivacy: Fix CiBoT complaints 2018-08-13 12:27:07 +08:00
Jun Pataleta 642ad98e28 MDL-62799 tool_dataprivacy: Move user generation within the test
Patch originally from MDL-62962.
2018-08-13 12:26:46 +08:00
sam marshall 6892904225 MDL-62799 tool_dataprivacy: Add capabilities to control data downloads
Patch originally from MDL-61652.
2018-08-13 12:26:30 +08:00
Jun Pataleta 5f7519ba19 MDL-62799 tool_dataprivacy: Behat tests for contacting PO
Patch originally from MDL-62026.
2018-08-13 12:26:07 +08:00
Jun Pataleta 2c904a6c87 MDL-62799 tool_dataprivacy: Allow manual completion of general enquiries
Patch originally from MDL-62026.
2018-08-13 12:25:34 +08:00
Jun Pataleta 91b38b5c30 MDL-62799 tool_dataprivacy: Merge the data privacy tool in 3.3 2018-08-13 09:22:49 +08:00
Eloy Lafuente (stronk7) e60b5bd04d weekly release 3.3.7+ 2018-08-10 13:21:56 +02:00
Andrew Nicols d54b8bb7ee Merge branch 'MDL-62619_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-08-10 08:46:57 +08:00
Eloy Lafuente (stronk7) a300c3479d MDL-62619 privacy: Prevent action when boolean queries are involved
Before the patch, queries like:

SELECT 1 FROM dual UNION SELECT 2 FROM dual

were failing badly, with everything but the first numeric element
being ignored by the optimization.

So, being conservative, now we reduce the query being analysed,
ignoring any subquery, inline view (anything within parenthesis
in general) and, in the remaining query, if a boolean query (UNION,
MINUS, INTERSECT...) is found, we don't apply any optimization.
2018-08-09 16:12:58 +02:00
Eloy Lafuente (stronk7) 38174e03de Merge branch 'MDL-62619-33-privacycontexts' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-08-08 01:03:29 +02:00
Andrew Nicols 0d21b5a2dc MDL-62800 behat: Correct path to P&P
This commit was originally a part of MDL-62950
2018-08-07 14:12:51 +08:00
Andrew Nicols a36a6e4491 Merge branch 'MDL-62800-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-08-07 12:14:25 +08:00
Mihail Geshoski 27621e4bfa MDL-62800 tool_policy: Add policy plugin in standard_plugins_list() 2018-08-07 11:21:44 +08:00
sarjona 939ba8562b MDL-62800 tool_policy: Merge the policy tool to 3.3
The following changes has been done from the original repo:
- Remove README.md, LICENSE.md and .travis.yml
- Review the version.php content, to look like a standard plugin
- Adapt jquery-eu-cookie-law-popup.js and readme_moodle.txt to remove the
eslint-ignore
2018-08-07 11:08:14 +08:00
Andrew Nicols d94a35a5a4 weekly release 3.3.7+ 2018-08-03 11:30:19 +08:00
Andrew Nicols 1f44dfad42 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-08-03 11:30:16 +08:00
Andrew Nicols 62ba30c11f MDL-63050 cachestore_redis: Update hExists to check empty 2018-08-02 11:06:05 +08:00
Andrew Nicols 663c41bf76 MDL-63050 redis: Make session check compatible with Redis 4.0 2018-08-02 11:06:05 +08:00
AMOS bot ded79d63d8 Automatically generated installer lang files 2018-07-28 00:09:05 +00:00
David Mudrák d6dcfee9f5 MDL-62619 privacy: Fix a missing alias in the blog provider class
The new implementation revealed another existing bug that did not expose
before due to coincidently same named table alias in the outer query.
2018-07-27 10:14:28 +02:00
David Mudrák bb478e8ddd MDL-62619 privacy: Fix some bits of performance improvements
* We need to use is_numeric() in this case as is_int() would never
  return true.
* Extend the supported cases, add support for SQL consisting just of
  numerical value or selectinga numerical constant.
* Do not rely on any particulat letter case in provided SQL.
* Add unit tests for the new method. Even when it is a protected one, it
  is an essential unit to be tested on its own.
2018-07-27 10:14:28 +02:00
Andrew Nicols be6fc5b122 MDL-62619 privacy: Improve performance of contexts loading
When possible, we want to use JOIN over WHERE IN. It is known that the
later performs badly in MySQL.
2018-07-27 10:14:28 +02:00
Jun Pataleta cad1e4f427 Merge branch 'MDL-62950-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-07-27 16:06:19 +08:00
Andrew Nicols 858cb072b1 MDL-62950 behat: Disable editing for boost test 2018-07-27 11:08:11 +08:00
Andrew Nicols 5ededd52c0 MDL-62950 behat: Correct path to P&P 2018-07-27 11:07:04 +08:00
Eloy Lafuente (stronk7) cf31c73791 weekly release 3.3.7+ 2018-07-26 19:56:40 +02:00
Eloy Lafuente (stronk7) 265894ee59 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-07-26 19:56:37 +02:00
Jun Pataleta f1a57a3181 Merge branch 'MDL-62653-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-07-26 10:58:07 +08:00
Andrew Nicols ce48eff24e MDL-62653 cron: Fix tab => whitespace 2018-07-26 10:57:22 +08:00
Jun Pataleta 008b92bd0a Merge branch 'MDL-62653-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-07-26 10:46:27 +08:00
Andrew Nicols fe8ca8b78d MDL-62653 behat: Ensure that tasks run properly from behat 2018-07-26 09:52:00 +08:00
Andrew Nicols e5fe5da40c MDL-62653 cron: Move adhoc task to separate fn 2018-07-26 09:23:17 +08:00
Jun Pataleta d8d35d7c1f Merge branch 'MDL-62781-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-07-18 10:03:46 +08:00
Jun Pataleta 680160dca4 MDL-62781 core_question: Remove unnecessary assertion 2018-07-18 10:00:05 +08:00
Tim Hunt 78315808b1 MDL-62781 question/privacy: fix tests with CodeRunner is installed
The tests were assuming that no plugin ever created questions on
install.

Also change the tests to do the counting in the DB. That is more
efficient.
2018-07-18 10:00:05 +08:00
AMOS bot b67c98ca83 Automatically generated installer lang files 2018-07-18 00:07:51 +00:00
AMOS bot d8eb85604f Automatically generated installer lang files 2018-07-17 00:08:38 +00:00
Eloy Lafuente (stronk7) 027b757f20 Moodle release 3.3.7 2018-07-07 06:49:34 +02:00
Eloy Lafuente (stronk7) a21351f43f Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-07-07 06:49:17 +02:00
AMOS bot 573fe725a4 Automatically generated installer lang files 2018-07-07 00:08:48 +00:00
AMOS bot 32bfc786df Automatically generated installer lang files 2018-07-05 00:08:41 +00:00
Tim Hunt 3504a2a99f MDL-62820 question import: properly escape output 2018-07-04 15:42:22 +08:00
Adrian Greeve eca3395a70 MDL-62616 tool_log: Add a setting to disable exporting logs. 2018-07-04 10:01:07 +08:00
Marina Glancy d5a8d310e0 MDL-62790 course: cap check in core_course_get_categories 2018-07-03 12:04:37 +08:00
Jake Dallimore af89e5a896 weekly release 3.3.6+ 2018-06-28 14:02:58 +08:00
Eloy Lafuente (stronk7) 31aa968f43 Merge branch 'wip-MDL-62755-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-06-28 01:57:03 +02:00
Adrian Greeve 560ddebb05 MDL-62755 mod_assign: Update to unit tests.
Overrides are now checked to be exported properly.
2018-06-25 09:54:19 +08:00
Adrian Greeve 45654c4813 MDL-62755 mod_assign: Fix override export problem.
The cutoffdate and allowsubmissionsfromdate were not
being exported.
2018-06-25 09:54:19 +08:00
Eloy Lafuente (stronk7) ff3187ba50 weekly release 3.3.6+ 2018-06-21 14:01:00 +02:00
Eloy Lafuente (stronk7) f5d105b4e0 Merge branch 'MDL-62449-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-06-19 18:52:49 +02:00
David Monllao 6f2c8d1ca6 Merge branch 'MDL-62588-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-06-19 13:00:04 +02:00
Sara Arjona 10c6f9c88f MDL-62449 scorm: Move related data to data in the privacy export 2018-06-18 10:45:08 +02:00
Sara Arjona 33e3839fdc MDL-62449 scorm: Add SCORM data to privacy export (name, description) 2018-06-18 10:45:08 +02:00
Jun Pataleta f60980615c Merge branch 'MDL-62614-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-06-18 16:12:03 +08:00
Jun Pataleta 153f6546bb Merge branch 'wip-MDL-62474-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-06-18 14:32:01 +08:00
Adrian Greeve 6acb8efc76 MDL-62474 theme_boost: Update to provider and unit test.
Theme boost contains a user preference which was not reported
before. Unit tests have been added to test the update.
2018-06-18 14:18:33 +08:00
Willian Mano 73e51962df MDL-62474 theme_boost: Fix Boost privacy provider 2018-06-18 14:12:20 +08:00
Huong Nguyen e56de91383 MDL-62614 Privacy: Core tag provider delete_item_tags function not work 2018-06-18 14:01:02 +08:00
Shamim Rezaie 68aabce476 MDL-62588 enrol_paypal: Add missing instanceid field 2018-06-18 15:20:22 +10:00
Eloy Lafuente (stronk7) 8d53360c70 weekly release 3.3.6+ 2018-06-14 10:55:54 +02:00
Eloy Lafuente (stronk7) 833d4aa42c Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-06-14 10:55:52 +02:00
AMOS bot 6e043dd5ec Automatically generated installer lang files 2018-06-13 00:08:30 +00:00
Jun Pataleta f1c8d8a374 Merge branch 'wip-MDL-62574-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-06-12 11:44:58 +08:00
Adrian Greeve 8e31b3241a MDL-62574 core_privacy: Unit tests to check the context base.
This now tests the possibility of a context being deleted.
2018-06-12 11:29:37 +08:00
Adrian Greeve 86b5d678bc MDL-62574 core_privacy: Check the contextlist for real contexts.
There are situations when contexts will be deleted in the provider.
The context list is not updated and so we have introduced a try
catch.
2018-06-12 11:29:36 +08:00
Eloy Lafuente (stronk7) 1b9f20fdf9 weekly release 3.3.6+ 2018-06-07 16:59:53 +02:00
Andrew Nicols 5204184a9b Merge branch 'm33_MDL-61702_MariaDB_InnoDB10d3d1_Params_Removed' of https://github.com/scara/moodle into MOODLE_33_STABLE 2018-06-06 09:10:48 +08:00
Matteo Scaramuccia a2650c9a7d MDL-61702 dml: MariaDB 10.3 supports only the Barracuda file format.
More details about this change also in https://tracker.moodle.org/browse/MDL-59099

Ref.: https://mariadb.com/kb/en/library/mariadb-1031-release-notes/#other-variables
2018-05-31 23:02:49 +02:00
David Monllao 83832b98a3 weekly release 3.3.6+ 2018-05-31 08:39:31 +02:00
David Monllao 149552615c Merge branch 'm33_MDL-59596_DDL_Issues_With_MariaDB_10p2_SQLMode' of https://github.com/scara/moodle into MOODLE_33_STABLE 2018-05-28 11:49:13 +02:00
Andrew Nicols 33ef4d941d MDL-62543 mod_forum: Add RSS Unit tests 2018-05-28 08:55:32 +08:00
Andrew Nicols 5aa514982d Merge branch 'MDL-62543-33' of git://github.com/tobiasreischmann/moodle into MOODLE_33_STABLE 2018-05-28 08:55:24 +08:00
Eloy Lafuente (stronk7) 2ed6a293df Merge branch 'MDL-62408_33_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_33_STABLE 2018-05-28 02:15:49 +02:00
David Monllao 7c84c195e9 weekly release 3.3.6+ 2018-05-24 10:45:55 +02:00
Tobias Reischmann 5db5c6dcc3 MDL-62543 forum: Switched the usage of the deleted flag for rss
The deleted flag was introduced through the Privacy API and was used
for post selection for the rss feed. In there it was used in the
wrong way, which lead to the exclusion of all non deleted posts instead
of excluding all deleted ones.
This commit fixes this problem.
2018-05-23 14:24:19 +02:00
Eloy Lafuente (stronk7) 8fb6a1a4f3 Merge branch 'MDL-62500-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-21 13:39:29 +02:00
David Monllao 08c753034f Merge branch 'm33_MDL-61893_Accept_Any_Node_Carbon_Version' of https://github.com/scara/moodle into MOODLE_33_STABLE 2018-05-21 12:04:57 +02:00
David Monllao c54ed68179 Merge branch 'MDL-62516-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-21 11:15:21 +02:00
Andrew Nicols 485c8e1f77 MDL-62500 tag: Update checkbox label when updating tag 2018-05-21 15:47:21 +08:00
Andrew Nicols 62994208a1 MDL-62516 mod_forum: Only delete files for requested user 2018-05-21 14:13:03 +08:00
Matteo Scaramuccia 74b5f26b3b MDL-61893 JavaScript: Bumped npm packages
Performed by removing the current 'npm-shrinkwrap.json' file:
$ rm -Rf node_modules
$ rm -f npm-shrinkwrap.json
$ npm install
$ npm shrinkwrap
2018-05-18 00:33:03 +02:00
Matteo Scaramuccia 6bdc80eaf5 MDL-61893 JavaScript: Accept any node version but Carbon (LTS) 2018-05-18 00:33:03 +02:00
Eloy Lafuente (stronk7) 56ff85a36b Moodle release 3.3.6 2018-05-16 18:42:13 +02:00
Marina Glancy c2a6b2b6ec MDL-62469 qtype_calculated: check remaining placeholders, see MDL-62275 2018-05-16 17:40:52 +02:00
David Monllao 96b0818716 Merge branch 'MDL-62456_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-16 08:58:53 +02:00
Andrew Nicols 51f0dbbcda Merge branch 'wip-MDL-62147-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-16 14:30:03 +08:00
Jun Pataleta 1465548ba5 Merge branch 'MDL-62463-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-16 14:21:22 +08:00
Frédéric Massart 06c8d3bf55 MDL-62147 core_grades: Report contexts and data related to scales 2018-05-16 13:53:04 +08:00
Marina Glancy fd982f3030 MDL-62147 core_grades: Declare metadata of scales and import tables 2018-05-16 13:53:04 +08:00
Marina Glancy 876cdf05c4 MDL-62147 portfolio: add missing tables to privacy provider 2018-05-16 13:53:01 +08:00
Marina Glancy b98339b09a MDL-62147 privacy: unittest ensures that all tables covered 2018-05-16 13:52:58 +08:00
Andrew Nicols 4b6f3f6cc1 MDL-62463 mod_glossary: Fix SQL query
The query was doing:
WHERE c.id ... AND ... OR ... OR ...

Which equates to:
WHERE (c.id ... AND ...) OR ... OR ...

Adding parens to:
WHERE (c.id ... AND (... OR ... OR ...))
2018-05-16 13:50:40 +08:00
Marina Glancy 8862838f25 MDL-62147 privacy: corrections to tables, temporary tables 2018-05-16 12:48:29 +08:00
Mark Nelson 5255e8fea9 MDL-62456 mod_lti: add missing add_external_location_link call 2018-05-16 12:23:49 +08:00
Jake Dallimore decd3731df Merge branch 'MDL-62134-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-16 12:02:54 +08:00
Andrew Nicols 60f6712ce1 MDL-62134 core_privacy: Allow for a failure handler 2018-05-16 11:52:46 +08:00
Andrew Nicols 8d85f96696 Merge branch 'MDL-62426-33' of https://github.com/snake/moodle into MOODLE_33_STABLE 2018-05-16 11:02:51 +08:00
Jake Dallimore 23a203618c MDL-62426 core_enrol: control enrolment subcontexts at the provider
Added a function to the core_enrol provider allowing enrol plugins
to set their subcontext relative to a fixed 'enrolments' parent dir.
2018-05-16 10:24:34 +08:00
Jake Dallimore c0c33ab059 MDL-62426 enrol_flatfile: make provider a plugin provider
The enrol_flatfile table can contain userdata relating to pending
enrolments, so this should be exported and deleted as necessary.
2018-05-16 09:36:37 +08:00
Marina Glancy 691e92efa7 MDL-62134 privacy: consistantly call components methods 2018-05-16 09:05:42 +08:00
Eloy Lafuente (stronk7) 1b70269f4e Merge branch 'MDL-62448-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-15 17:29:24 +02:00
Sara Arjona 8197937d22 MDL-62448 block_rss_client: Export all feeds from Privacy API 2018-05-15 14:27:16 +02:00
David Monllao d60618cbea Merge branch 'MDL-62228_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-15 13:31:56 +02:00
Mark Johnson 6a5d9d0705 MDL-62408 behat: Correct PHPUNIT_TEST checks in behat_config_util 2018-05-15 09:15:56 +01:00
David Monllao ac897aedea weekly release 3.3.5+ 2018-05-15 09:42:09 +02:00
David Monllao 6582329fdf Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-05-15 09:42:07 +02:00
Mark Nelson e8279ab994 MDL-62228 core: remove unnecessary context check in privacy providers 2018-05-15 12:02:52 +08:00
Andrew Nicols 85d42a024b Merge branch 'MDL-62444-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-05-15 11:39:25 +08:00
Andrew Nicols 1ea41504b4 Merge branch 'MDL-62428_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-15 11:06:01 +08:00
Zig Tan 8195484581 MDL-62444 mod_assignment: Fix missing lang string. 2018-05-15 10:02:54 +08:00
Jun Pataleta 04f3435b12 Merge branch 'MDL-62432-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-15 09:34:04 +08:00
Andrew Nicols 00ced8dde3 MDL-62432 quiz: Check contexts more carefully 2018-05-15 09:25:51 +08:00
Eloy Lafuente (stronk7) d33d90031e Merge branch 'MDL-62430_33' of git://github.com/dmonllao/moodle into MOODLE_33_STABLE 2018-05-15 02:56:23 +02:00
AMOS bot b26b312e46 Automatically generated installer lang files 2018-05-15 00:06:41 +00:00
David Monllao f90a0107d1 MDL-62430 block_html: Check that block instances are block_html 2018-05-14 17:07:21 +02:00
David Monllao f6d8b2f753 Merge branch 'MDL-62370-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-14 16:01:21 +02:00
Andrew Nicols 533ef686e4 Merge branch 'MDL-62356-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-14 21:03:03 +08:00
Andrew Nicols 3fe971f407 Merge branch 'MDL-62357-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-14 20:47:33 +08:00
Andrew Nicols d334974409 MDL-62370 core_privacy: Directory-less subsystems are compliant 2018-05-14 20:04:41 +08:00
Marina Glancy e58797fb4c MDL-62430 privacy: validate context when deleting all user data 2018-05-14 18:13:52 +08:00
cescobedo ed333da1a8 MDL-62356 enrol_meta: Add privacy implementation for enrol_meta 2018-05-14 10:59:22 +02:00
David Monllao ef9428e9cb Merge branch 'MDL-62425-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-14 10:59:13 +02:00
cescobedo 112aa66679 MDL-62357 enrol_cohort: Add privacy implementation for enrol_cohort 2018-05-14 10:48:16 +02:00
Andrew Nicols 974a90e2e7 MDL-62425 core: Add privacy implementation 2018-05-14 15:44:59 +08:00
Andrew Nicols 674544a52a MDL-62425 core_privacy: Add core to the list of components 2018-05-14 15:43:26 +08:00
Mark Nelson b30fadbae0 MDL-62428 core: fix incorrect early return in privacy providers 2018-05-14 13:08:02 +08:00
Jake Dallimore ccc3f70717 Merge branch 'MDL-62420-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-14 11:58:28 +08:00
Jake Dallimore 2c5e158be1 Merge branch 'MDL-62393-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-14 09:38:18 +08:00
Andrew Nicols f9180359e6 MDL-62420 enrol_lti: Fix random unit test fail in privacy 2018-05-14 08:44:25 +08:00
Eloy Lafuente (stronk7) d567be0d04 Merge branch 'MDL-62371-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-14 02:42:27 +02:00
Eloy Lafuente (stronk7) 98900443b7 Merge branch 'MDL-62251-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-13 23:58:26 +02:00
Andrew Nicols 6d86e2d223 MDL-62371 core_privacy: Add support for progress trace 2018-05-13 15:45:24 +08:00
AMOS bot ab6abffb30 Automatically generated installer lang files 2018-05-13 00:06:57 +00:00
Andrew Nicols 018135947a MDL-62393 message: Fix random unit test fails 2018-05-12 23:02:49 +08:00
Eloy Lafuente (stronk7) 374387c563 weekly release 3.3.5+ 2018-05-12 12:56:41 +02:00
Eloy Lafuente (stronk7) 6ed62aec00 MDL-62275 qtype_calculatedmulti: Fix typo 2018-05-11 21:17:46 +02:00
David Monllao 776503b29a MDL-62029 core_course: Site format is not a standard plugin 2018-05-11 20:19:19 +02:00
Eloy Lafuente (stronk7) 92928baabe Merge branch 'MDL-62384-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-11 18:28:11 +02:00
David Monllao 1560349956 Merge branch 'MDL-61858_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-11 18:07:16 +02:00
David Monllao f39b2d7da8 Merge branch 'MDL-62368_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-11 17:59:36 +02:00
Mark Nelson 739e7f5c79 MDL-61858 gradingform_guide: added missing metadata implementation 2018-05-11 19:42:08 +08:00
Mark Nelson 3747401992 MDL-61858 core_portfolio: added missing metadata implementation 2018-05-11 19:42:08 +08:00
Andrew Nicols e34f261d5e MDL-61858 core_privacy: Add test to ensure component implementations 2018-05-11 19:42:08 +08:00
Eloy Lafuente (stronk7) 7bf7b7e517 Merge branch 'MDL-61951-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-11 13:24:02 +02:00
Sara Arjona 791113dd66 MDL-61951 core_grading: Review SQL to avoid Oracle errors 2018-05-11 13:02:58 +02:00
David Monllao 56141c546f Merge branch 'MDL-61714-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-11 11:31:42 +02:00
Sara Arjona c52dac659c MDL-61714 admin: Removed Slovenian digital age 2018-05-11 10:14:20 +02:00
Shamim Rezaie 41960dcbe8 MDL-62251 Privacy: Fix dir separator in export_file() 2018-05-11 17:44:45 +10:00
Shamim Rezaie 0a65299f7f MDL-62251 Privacy: Url path separator should be platform independant
It should always be forward slash.
2018-05-11 17:43:10 +10:00
Shamim Rezaie f6f1a5f624 MDL-62251 Privacy: Fix get_path() and get_full_path() bug in Windows 2018-05-11 17:39:54 +10:00
Shamim Rezaie 96437cfa3e MDL-62251 backup: Fix replace_tempdir() bug under Windows
rename() fails under Windows if the destination file/directory exists.
I modified the code to only call $this->get_workdir_path() once as that function
creates the directory if doesn't exist. And we don't want that considering the
behaviour of rename on Windows.
2018-05-11 17:37:03 +10:00
Mark Nelson 94f668496c MDL-62368 enrol_lti: implement privacy provider 2018-05-11 15:15:41 +08:00
Eloy Lafuente (stronk7) c31ed14f78 MDL-62354 notes: Reduce string to avoid js_call_amd() lenght limits
That way we are under the max 1024 allowed and also, the help string
is shown properly in the modal (previously part of it was not visible
falling off-window).
2018-05-11 14:53:22 +08:00
Jun Pataleta f6636c4ef6 Merge branch 'MDL-62394-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-11 14:23:25 +08:00
Andrew Nicols 348bdcba70 MDL-62394 privacy: Make JSON export pretty 2018-05-11 14:12:55 +08:00
Mihail Geshoski 7db992398f MDL-62384 privacy: Modify user contexts query for auth_oauth2 2018-05-11 11:14:35 +08:00
Andrew Nicols 6be954134b MDL-62384 core_rating: Move WHERE clauses to JOIN 2018-05-11 11:14:35 +08:00
Andrew Nicols dafd1528c1 MDL-62384 core_grade: Move WHERE clause to JOIN 2018-05-11 11:14:34 +08:00
Andrew Nicols 6951d69b81 MDL-62384 mod_lesson: Move WHERE clause to JOIN 2018-05-11 11:14:34 +08:00
Andrew Nicols 0e9baa7675 MDL-62384 logstore_standard: Remove unnecessary join on context 2018-05-11 11:14:33 +08:00
Andrew Nicols a3aaf32b0a MDL-62384 mod_quiz: Improve performancy of privacy queries 2018-05-11 11:14:32 +08:00
Adrian Greeve a2137340ae MDL-62384 mod_data: Update sql to improve performance. 2018-05-11 11:14:32 +08:00
Adrian Greeve fb7934b2b8 MDL-62384 tool_monitor: Update to sql to fix performance. 2018-05-11 11:14:31 +08:00
Adrian Greeve 2c030c2ccc MDL-62384 core_competency: Update to sql to increase performance. 2018-05-11 11:14:30 +08:00
Adrian Greeve 8de1eaa03b MDL-62384 core_completion: Update to sql to improve performance. 2018-05-11 11:14:30 +08:00
Adrian Greeve b2481afc98 MDL-62384 mod_assign: Update to sql query for performance. 2018-05-11 11:14:30 +08:00
Andrew Nicols c0e4458f28 Merge branch 'wip-MDL-61814-33-fix' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-05-11 10:50:23 +08:00
Adrian Greeve f3bd9db07c MDL-61814 report_stats: Update to sql to increase performance. 2018-05-11 10:42:22 +08:00
Jake Dallimore 83038cdb43 MDL-61951 core_grading: SQL improvements for grading_instance join 2018-05-11 10:20:20 +08:00
Jake Dallimore d1ec251117 Merge branch 'MDL-61951-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-11 10:20:14 +08:00
Jun Pataleta a54eadb25a Merge branch 'MDL-62117-33-fix' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-11 09:30:19 +08:00
Andrew Nicols 5bd702aace MDL-62117 enrol_paypal: Improve SQL efficiency 2018-05-11 08:53:20 +08:00
Tim Hunt 9d1bc62c35 MDL-62275 qtype_calc*: improve validation of formulae
Many thanks to Marina Glancy for helping with this.
2018-05-11 01:33:54 +02:00
David Monllao de464f7105 MDL-62200 css: Updating compiled build 2018-05-10 19:28:24 +02:00
David Monllao ab4ecb487d Merge branch 'MDL-62366-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-05-10 18:14:00 +02:00
David Monllao 3bd2c9cc2d Merge branch 'MDL-61714-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-10 18:11:52 +02:00
David Monllao 255bc952ba Merge branch 'MDL-62200-33' of git://github.com/bmbrands/moodle into MOODLE_33_STABLE 2018-05-10 18:04:31 +02:00
David Monllao 7eb75ea17c Merge branch 'MDL-61949-33-privacy-upgrade-txt' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-05-10 17:53:21 +02:00
Jake Dallimore 9429e8c3ea MDL-61951 core_grading: Several fixes to the privacy implementation
- Fixed legacy polyfill method definitions
- Added unit test for legacy polyfill
- Fixed delete_gradingform_for_userid in gradingform provider
2018-05-10 13:27:03 +02:00
Andrew Nicols 0c392c1a85 MDL-61905 mod_workshop: Adjust privacy SQL queries
This change moves the content of WHERE to the JOIN, thus filtering the
results before they are returned. This reduces the number of joined rows
which gives a big performance benefit.
2018-05-10 13:06:08 +02:00
David Mudrák 9708ed8762 MDL-61949 privacy: Add mention of the new API in upgrade.txt files
The notice is explicitly repeated for activity modules because they
usually process user data heavily.
2018-05-10 12:07:28 +02:00
Eloy Lafuente (stronk7) 7a797d3fe5 Merge branch 'MDL-62354-33-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-05-10 11:39:32 +02:00
Sara Arjona 7658ef16d5 MDL-61714 admin: Update digital age consent map according legislation 2018-05-10 10:33:51 +02:00
Helen Foster c37224a097 MDL-62354 lang: Merge English strings from the en_fix language pack
Significant string changes:

* publishstate_help, core_notes - including GDPR guidance
2018-05-10 09:34:48 +02:00
David Monllao 5439bb15fe Merge branch 'MDL-61309-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-10 08:49:35 +02:00
Andrew Nicols ae396e60f1 MDL-61309 mod_forum: Improve privacy query performance 2018-05-10 14:06:43 +08:00
Sara Arjona 8e72596812 MDL-61951 grading: Implement privacy API 2018-05-10 07:54:11 +02:00
Marina Glancy 0fa43bbd16 MDL-62206 blocks: do not add fixed form elements as hidden 2018-05-10 12:09:05 +08:00
Adam Olley e3a7ffba7d MDL-62210 mod_assign: limit file lookup to the target assign 2018-05-10 11:22:08 +08:00
Brendan Cox 0f3b121f1a MDL-62210 mod_assign: improved validation in portfolio caller class 2018-05-10 11:22:08 +08:00
Jake Dallimore a5a7741d7c Merge branch 'MDL-62383-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-05-10 10:04:43 +08:00
Jun Pataleta b141b2d185 MDL-62383 privacy: Close recordset in contextlist::add_from_sql() 2018-05-10 09:57:02 +08:00
Jake Dallimore 2e0e356228 MDL-62257 mnetservice_enrol: minor fixes to privacy provider 2018-05-10 09:38:20 +08:00
Jake Dallimore a3a8c5b244 Merge branch 'MDL-62257-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-10 09:38:15 +08:00
Eloy Lafuente (stronk7) c092051695 Merge branch 'MDL-61309-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-10 09:19:47 +08:00
David Monllao 8f9e7916e7 Merge branch 'MDL-62308_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-10 09:19:47 +08:00
David Monllao 973405d146 MDL-61976 mod_wiki: Trim returned value to avoid EOF-related failures 2018-05-10 09:19:47 +08:00
Andrew Nicols e676202902 Merge branch 'wip-MDL-62351-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-10 09:19:46 +08:00
David Monllao 7f8fbfe6c7 Merge branch 'MDL-62249-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-05-10 09:19:46 +08:00
Andrew Nicols c606e82d4b Merge branch 'MDL-62217_33' of git://github.com/dmonllao/moodle into MOODLE_33_STABLE 2018-05-10 09:19:45 +08:00
Andrew Nicols f0bec9ecdf Merge branch 'MDL-62269-33' of git://github.com/vmdef/moodle into MOODLE_33_STABLE 2018-05-10 09:19:45 +08:00
David Monllao fd2bb53bf2 Merge branch 'wip-MDL-61976-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-10 09:19:44 +08:00
David Monllao 2465c76ac1 MDL-61994 mod_glossary: Fixing wrong subsystem name 2018-05-10 09:19:44 +08:00
David Monllao e04bb65283 Merge branch 'MDL-61994-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2018-05-10 09:19:44 +08:00
David Monllao af90c1bc4b Merge branch 'MDL-61309-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-10 09:19:43 +08:00
Jun Pataleta 4458f71ab0 MDL-62232 mod_forum: PHPUnit 5.5 needs expectException() 2018-05-10 09:19:43 +08:00
Brendan Cox aa208d1bc2 MDL-62232 mod_forum: Additional tests for portfolio file export 2018-05-10 09:19:42 +08:00
Adam Olley 30ca2558dc MDL-62232 mod_forum: Limit portfolio to files belonging to the post 2018-05-10 09:19:42 +08:00
Andrew Nicols c1fef4c9c3 Merge branch 'MDL-61905-33-privacyworkshop' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-05-10 09:19:41 +08:00
Andrew Nicols 524cd5de9c Merge branch 'MDL-62029-33-2' of git://github.com/snake/moodle into MOODLE_33_STABLE 2018-05-10 09:19:41 +08:00
Jun Pataleta 908ba9fe26 Merge branch 'MDL-62332-33' of git://github.com/bmbrands/moodle into MOODLE_33_STABLE 2018-05-10 09:19:40 +08:00
Andrew Nicols dce8813021 Merge branch 'MDL-62318-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-10 09:19:40 +08:00
Andrew Nicols 9c2f2a1ac0 Merge branch 'MDL-62117-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-10 09:19:40 +08:00
Marina Glancy f83de6d1ba MDL-62233 portfolio: check caller parent class 2018-05-10 09:19:39 +08:00
Zig Tan c47cccc329 MDL-62366 mod_assign: Followup fix for attemptnumber in exported JSON 2018-05-10 09:19:35 +08:00
Andrew Nicols 219ede6ecf MDL-61309 mod_forum: Remove unnecessary deletion check 2018-05-10 07:48:26 +08:00
Mark Nelson 9b7c011e3d MDL-62308 core_backup: implement privacy provider
The provider was added to 'backup/util/ui/' due to
Moodle's implementation of autoclass loading. See
fetch_subsystems() in lib/classes/component.php.
2018-05-09 23:17:27 +08:00
Marina Glancy f88e03e50a MDL-62351 privacy: check that subsystem/plugintype exist 2018-05-09 17:37:58 +08:00
Marina Glancy 369181e33b MDL-61976 mod_wiki: implement privacy API 2018-05-09 17:31:05 +08:00
Victor Deniz 89266764c0 MDL-62269 auth_mnet: Implement privacy API
AMOS BEGIN
 CPY [privacy:metadata:address,core_user],[privacy:metadata:mnet_external:address,auth_mnet]
 CPY [privacy:metadata:aim,core_user],[privacy:metadata:mnet_external:aim,auth_mnet]
 CPY [privacy:metadata:aim,core_user],[privacy:metadata:mnet_external:aim,auth_mnet]
 CPY [privacy:metadata:alternatename,core_user],[privacy:metadata:mnet_external:alternatename,auth_mnet]
 CPY [privacy:metadata:autosubscribe,core_user],[privacy:metadata:mnet_external:autosubscribe,auth_mnet]
 CPY [privacy:metadata:calendartype,core_user],[privacy:metadata:mnet_external:calendartype,auth_mnet]
 CPY [privacy:metadata:city,core_user],[privacy:metadata:mnet_external:city,auth_mnet]
 CPY [privacy:metadata:country,core_user],[privacy:metadata:mnet_external:country,auth_mnet]
 CPY [privacy:metadata:currentlogin,core_user],[privacy:metadata:mnet_external:currentlogin,auth_mnet]
 CPY [privacy:metadata:department,core_user],[privacy:metadata:mnet_external:department,auth_mnet]
 CPY [privacy:metadata:description,core_user],[privacy:metadata:mnet_external:description,auth_mnet]
 CPY [privacy:metadata:email,core_user],[privacy:metadata:mnet_external:email,auth_mnet]
 CPY [privacy:metadata:emailstop,core_user],[privacy:metadata:mnet_external:emailstop,auth_mnet]
 CPY [privacy:metadata:firstaccess,core_user],[privacy:metadata:mnet_external:firstaccess,auth_mnet]
 CPY [privacy:metadata:firstname,core_user],[privacy:metadata:mnet_external:firstname,auth_mnet]
 CPY [privacy:metadata:firstnamephonetic,core_user],[privacy:metadata:mnet_external:firstnamephonetic,auth_mnet]
 CPY [privacy:metadata:icq,core_user],[privacy:metadata:mnet_external:icq,auth_mnet]
 CPY [privacy:metadata:id,core_user],[privacy:metadata:mnet_external:id,auth_mnet]
 CPY [privacy:metadata:idnumber,core_user],[privacy:metadata:mnet_external:idnumber,auth_mnet]
 CPY [privacy:metadata:imagealt,core_user],[privacy:metadata:mnet_external:imagealt,auth_mnet]
 CPY [privacy:metadata:institution,core_user],[privacy:metadata:mnet_external:institution,auth_mnet]
 CPY [privacy:metadata:lang,core_user],[privacy:metadata:mnet_external:lang,auth_mnet]
 CPY [privacy:metadata:lastaccess,core_user],[privacy:metadata:mnet_external:lastaccess,auth_mnet]
 CPY [privacy:metadata:lastlogin,core_user],[privacy:metadata:mnet_external:lastlogin,auth_mnet]
 CPY [privacy:metadata:lastname,core_user],[privacy:metadata:mnet_external:lastname,auth_mnet]
 CPY [privacy:metadata:lastnamephonetic,core_user],[privacy:metadata:mnet_external:lastnamephonetic,auth_mnet]
 CPY [privacy:metadata:maildigest,core_user],[privacy:metadata:mnet_external:maildigest,auth_mnet]
 CPY [privacy:metadata:maildisplay,core_user],[privacy:metadata:mnet_external:maildisplay,auth_mnet]
 CPY [privacy:metadata:middlename,core_user],[privacy:metadata:mnet_external:middlename,auth_mnet]
 CPY [privacy:metadata:msn,core_user],[privacy:metadata:mnet_external:msn,auth_mnet]
 CPY [privacy:metadata:phone,core_user],[privacy:metadata:mnet_external:phone1,auth_mnet]
 CPY [privacy:metadata:picture,core_user],[privacy:metadata:mnet_external:picture,auth_mnet]
 CPY [privacy:metadata:policyagreed,core_user],[privacy:metadata:mnet_external:policyagreed,auth_mnet]
 CPY [privacy:metadata:skype,core_user],[privacy:metadata:mnet_external:skype,auth_mnet]
 CPY [privacy:metadata:suspended,core_user],[privacy:metadata:mnet_external:suspended,auth_mnet]
 CPY [privacy:metadata:timezone,core_user],[privacy:metadata:mnet_external:timezone,auth_mnet]
 CPY [privacy:metadata:trackforums,core_user],[privacy:metadata:mnet_external:trackforums,auth_mnet]
 CPY [privacy:metadata:trustbitmask,core_user],[privacy:metadata:mnet_external:trustbitmask,auth_mnet]
 CPY [privacy:metadata:url,core_user],[privacy:metadata:mnet_external:url,auth_mnet]
 CPY [privacy:metadata:username,core_user],[privacy:metadata:mnet_external:username,auth_mnet]
 CPY [privacy:metadata:yahoo,core_user],[privacy:metadata:mnet_external:yahoo,auth_mnet]
AMOS END
2018-05-09 10:00:13 +01:00
David Monllao 2a869c727e MDL-62217 search_solr: Plugin provider fake implementation 2018-05-09 10:59:14 +02:00
David Monllao 7a5aee27ff MDL-62217 search: Privacy providers 2018-05-09 10:58:26 +02:00
David Mudrák 9515077330 MDL-61905 workshop: Implement privacy API in grading evaluators
Standard workshop ships with only one evaluation method and that one
holds no personal data.
2018-05-09 10:03:31 +02:00
David Mudrák 0f84929153 MDL-61905 workshop: Implement privacy API in assessment allocators
Assessment allocation methods normally do not store any personal data.
Their duty is to create assessment records that are then exported by the
workshop core itself.

Still, some allocators (such as the Manual allocation) can store certain
personal data such as user preferences.
2018-05-09 10:03:31 +02:00
David Mudrák be19685f6b MDL-61905 workshop: Implement privacy API in grading strategies
On low level, standard grading strategies subplugins do not store
personal themselves.  They make use of the grades storage provided by
the workshop itself.  What they do contain though is the information
about how the assessment forms were defined. And they are also
responsible for correctly interpreting the values in the central grades
table.

Grading strategies fulfil the contract with the parent workshop module
by implementing the workshopform_provider interface. That gives them a
chance to export data about the assessment form to each of exported
assessment.
2018-05-09 10:03:31 +02:00
David Mudrák d3ae85a539 MDL-61905 workshop: Implement the privacy API in the workshop core
Workshop module stores personal data in its tables, via user
preference and via core_files and core_plagiarism subsystems.

When exporting the data, we export not only data created by users
themselves (such as their submissions and provided peer-assessments) but
also all relevant data that can (or must) be used to interpret created
content and evaluate the user's performance and skills.

On the other hand, when deleting data at user's request, we delete only
those data that do not affect other users' performance evaluation. The
reasoning is that one's right for privacy does not overweight someone
else's right for fair assessment. For that reason, we can't fully delete
whole provided peer-assessments, for example. Because they are used in
cross-comparison and grading evaluation of all other peers who assessed
the same submission. So instead, we replace provided texts but still
keep the original record.

Workshop defines the interface for its grading strategy subplugins to
allow them attach personal data under their control to the exported
structures.
2018-05-09 10:03:31 +02:00
Jake Dallimore 9e25c063b7 MDL-62029 core_course: Fixes to context-aware provider implementation. 2018-05-09 15:48:15 +08:00
Andrew Nicols 21e93fdbe3 MDL-61309 mod_forum: Implement privacy deletion 2018-05-09 14:03:34 +08:00
Andrew Nicols 2fefe3ca68 MDL-61309 mod_forum: Implement the Privacy API 2018-05-09 14:03:33 +08:00
Andrew Nicols 6b6226160d MDL-61309 core_tags: Add privacy unit test trait 2018-05-09 13:52:59 +08:00
Simey Lameze 97c77877f7 MDL-61994 mod_glossary: add unit tests for provider 2018-05-09 12:15:58 +08:00
Simey Lameze 04fe8c2a63 MDL-61994 mod_glossary: implement privacy providers 2018-05-09 12:15:53 +08:00
Shamim Rezaie 80936f77ef MDL-62318 core_group: Updating cache when deleting group memberships 2018-05-09 13:35:18 +10:00
Shamim Rezaie 9c172adefe MDL-62318 core_group: Add implementation of privacy API 2018-05-09 13:35:11 +10:00
Adrian Greeve d7882b3815 MDL-62029 core_privacy: context aware provider creation. 2018-05-09 09:39:59 +08:00
Adrian Greeve e2ba4fd896 MDL-62029 core_course: Create privacy files for core_course. 2018-05-09 09:39:51 +08:00
Marina Glancy 7981a0b125 MDL-61996 core: when loggedin always check user is complete 2018-05-09 02:56:56 +02:00
Andrew Nicols 856b970904 Merge branch 'MDL-62010-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-09 08:53:56 +08:00
cescobedo af9f57975c MDL-62010 core_enrol: Add privacy implementation for core_enrol 2018-05-08 19:04:37 +02:00
David Monllao 8322e9a1ee MDL-61814 core_user: Remove empty line to avoid ci warning 2018-05-08 17:20:18 +02:00
David Monllao 6817208044 Merge branch 'wip-MDL-61814-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-05-08 17:20:04 +02:00
David Monllao 5eae39feb0 Merge branch 'MDL-61943-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-08 16:44:17 +02:00
David Monllao e77114bf70 weekly release 3.3.5+ 2018-05-08 14:02:11 +02:00
David Monllao 3da5a3c348 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-05-08 14:02:09 +02:00
cescobedo a6c263e33d MDL-61943 core_role: Add privacy implementation for core_role 2018-05-08 13:50:37 +02:00
Bas Brands 10662a78b9 MDL-62332 Theme boost: paging bar empty active link 2018-05-08 10:10:47 +02:00
cescobedo dfd93e3617 MDL-62257 mnetservice_enrol: Implement Privacy API 2018-05-08 10:06:32 +02:00
Andrew Nicols 6554a3d31e Merge branch 'wip-MDL-61937-33-fix' of https://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-08 14:45:40 +08:00
Marina Glancy 767e94894a MDL-61937 mod_data: fix commentarea name 2018-05-08 14:40:38 +08:00
Adrian Greeve c875879050 MDL-61814 report_stats: Update to be a full privacy provider. 2018-05-08 14:35:47 +08:00
Adrian Greeve 18920002b9 MDL-61814 core_portfolio: Update to portfolio provider. 2018-05-08 14:35:47 +08:00
Adrian Greeve 08c3fc7493 MDL-61814 core_user: Implement privacy system for user. 2018-05-08 14:35:47 +08:00
Zig Tan eda9ba5e21 MDL-62249 block_tag_flickr: Corrected privacy providers 2018-05-08 12:17:44 +08:00
Marina Glancy 7ceb3f8568 MDL-61976 privacy: replace pluginfile in test writer 2018-05-08 12:03:18 +08:00
Marina Glancy 5a4cbdb34f MDL-61976 privacy: add subcontext argument to has_any_data 2018-05-08 12:03:18 +08:00
Andrew Nicols 3ff77e753b Merge branch 'wip-MDL-62068-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-08 11:48:35 +08:00
Marina Glancy 669fba527d MDL-62068 core_tag: implement privacy API 2018-05-08 11:35:14 +08:00
Shamim Rezaie 31842699a0 MDL-62117 enrol_paypal: Add implementation of Privacy API 2018-05-08 13:30:09 +10:00
Andrew Nicols eb8a915468 Merge branch 'MDL-62285-33' of git://github.com/ryanwyllie/moodle into MOODLE_33_STABLE 2018-05-08 11:16:20 +08:00
Ryan Wyllie c8c5d741ab MDL-62285 privacy: use context id when generating context path
moodle_content_writer::get_context_path() now includes the context
id in the path to ensure that it will always generate unique paths
even when the context names are not unique.
2018-05-08 01:41:45 +00:00
Eloy Lafuente (stronk7) 94f42309c5 Merge branch 'MDL-61521-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2018-05-08 01:45:44 +02:00
David Monllao 5fd78d27ae Merge branch 'MDL-62326-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-07 12:11:22 +02:00
Andrew Nicols 77518888c8 MDL-62326 core_antivirus: Implement null provider 2018-05-07 17:37:18 +08:00
Andrew Nicols 9b3ce309f7 Merge branch 'MDL-62169-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-05-07 17:27:18 +08:00
Zig Tan c13aaef075 MDL-62169 mod_assignment: Improved phpunit test reliability 2018-05-07 16:46:07 +08:00
Andrew Nicols 19afe6488f Merge branch 'MDL-61919_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-07 15:53:33 +08:00
Andrew Nicols f819f0f992 Merge branch 'wip-MDL-62137-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-05-07 15:30:49 +08:00
Adrian Greeve 3c38e56b83 MDL-62137 core_privacy: Update to helper to use core_completion 2018-05-07 14:22:50 +08:00
Adrian Greeve a3b8f6a288 MDL-62137 core_completion: Privacy files for core_completion. 2018-05-07 14:22:50 +08:00
Andrew Nicols 266d7f04ff Merge branch 'MDL-62169-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-05-07 14:18:56 +08:00
Zig Tan 3f6f7b1804 MDL-62169 mod_assignment: Implemented privacy providers 2018-05-07 13:52:43 +08:00
Andrew Nicols 01bde600e3 Merge branch 'MDL-61407-33-fix' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-05-07 13:52:22 +08:00
Jun Pataleta 3a2e28454d MDL-61407 mod_quiz: Determine quiz step for manual comment 2018-05-07 13:42:17 +08:00
Andrew Nicols e178d5ec21 MDL-61937 mod_data: Correct rating export args in privacy 2018-05-07 09:43:28 +08:00
David Monllao a5543d0731 MDL-61937 mod_data: Target the correct area 2018-05-07 09:43:27 +08:00
Andrew Nicols 820148bd89 MDL-61407 question: Export step files in privacy 2018-05-07 07:10:19 +08:00
Eloy Lafuente (stronk7) 39558fa5dd MDL-61693 core_calendar: make results deterministic for better testing 2018-05-06 18:17:52 +02:00
Eloy Lafuente (stronk7) 99c76ad3ce Merge branch 'MDL-62315-33-privacycoreform' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-05-04 15:42:11 +02:00
Bas Brands 3372b77957 MDL-62200 Theme boost: popup in popup styles 2018-05-04 14:10:08 +02:00
David Mudrák eddf0a076f MDL-62315 form: Fix privacy API implementation for core_form subsystem
Only during the testing, we realized that the user preference was added
only in 3.4 in MDL-59407 so we have to declare no personal data in 3.3.
No need for custom unit test as the implementation is covered by
privacy/tests/provider_test.php
2018-05-04 13:08:57 +02:00
Frédéric Massart 101f6c43e1 MDL-61877 core_competency: False negative due to random ordering 2018-05-04 11:18:52 +02:00
Zig Tan 3da2da51b8 MDL-61693 core_calendar: Simplified get calendar event details SQL 2018-05-04 13:10:28 +08:00
Jake Dallimore df122c79cd Merge branch 'MDL-61407-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-04 11:59:31 +08:00
Andrew Nicols e6c53933a5 Merge branch 'wip-MDL-61937-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-04 11:30:29 +08:00
Jun Pataleta 34dcee8f34 Merge branch 'MDL-61877-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-04 11:24:08 +08:00
Marina Glancy e3c8b00866 MDL-61937 mod_data: implement privacy provider 2018-05-04 11:21:47 +08:00
Marina Glancy 5c3ee69c74 MDL-61937 tag: new method in privacy api 2018-05-04 11:21:41 +08:00
Marina Glancy bcd7e54804 MDL-61937 rating: delete method in privacy provider 2018-05-04 11:21:04 +08:00
Marina Glancy 8d141bb1ef MDL-61937 comment: do not use API in provider
When exporting comments we can not use comments API because:
- we don't need to call component validate, comments may be disabled right now but
  are still stored
- we don't need to call display callback
- we need to export all comments and not only first 15 of them
2018-05-04 11:21:04 +08:00
Marina Glancy d1778bc5a0 MDL-61937 mod_data: generator for all field types 2018-05-04 11:21:01 +08:00
cescobedo 156233b745 MDL-61937 datafield: Add privacy implementation for all datafield 2018-05-04 11:20:46 +08:00
Mark Nelson 88f53cf84e MDL-61919 core_message: implement privacy provider 2018-05-04 11:17:47 +08:00
Jake Dallimore 111f55d95e Merge branch 'MDL-62046-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-05-04 10:28:08 +08:00
Jake Dallimore ddc0b2c805 Merge branch 'MDL-62032-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-05-04 09:57:36 +08:00
Jake Dallimore 9acdfbcdda Merge branch 'MDL-62030-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-05-04 09:52:16 +08:00
Jake Dallimore 421628ec0b Merge branch 'MDL-59845-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-04 09:48:12 +08:00
Jake Dallimore 61cf3e9178 Merge branch 'MDL-62007-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-05-04 09:23:29 +08:00
Eloy Lafuente (stronk7) cefc325958 Merge branch 'MDL-62315-33-privacycoreform' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-05-03 23:40:57 +02:00
Eloy Lafuente (stronk7) 2886a5e64d Merge branch 'MDL-61800-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-03 23:29:28 +02:00
David Mudrák 8da3291abb MDL-62315 form: Implement the privacy API for core_form subsystem
Forms subsystem has no own database table. The only personal data is the
user preference 'filemanager_recentviewmode' that stores the view mode
of the file picker element.

It was discussed whether handling of this preference should be added
here into core_form, or rather into core_repository subsystem. The final
decision was to consider the preference as owned by the core_form
because it is affecting the display of a form element, not the
repository backend (even though the strings describing it had been put
into core_repository strings).
2018-05-03 19:06:50 +02:00
Andrew Nicols b618310364 Merge branch 'MDL-62240-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-03 19:06:33 +08:00
Jake Dallimore 4b51386d9a Merge branch 'MDL-62310-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-03 18:04:46 +08:00
Jun Pataleta 08f2b6063f Merge branch 'MDL-61194-33' of git://git.cameron1729.xyz/moodle into MOODLE_33_STABLE 2018-05-03 17:06:00 +08:00
Cameron Ball b22bc26c51 MDL-61194 assignfeedback_editpdf: Check if we can convert online text
This patch adds a check to make sure there is a converter available that
will be able to handle html->pdf conversion before adding onlinetext
submissions to the list of files to combine.
2018-05-03 16:47:37 +08:00
Mihail Geshoski 044656f96a MDL-62046 profilefield_textarea: Add privacy files and unit tests 2018-05-03 16:28:48 +08:00
David Monllao 0612aa3418 Merge branch 'MDL-61693-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-05-03 10:25:03 +02:00
Andrew Nicols c73a9d5cbe MDL-61407 privacy: Reset the writer after writer tests
The writer was not reset after these tests which had the potential to
affect the next test after these were run.
2018-05-03 16:14:37 +08:00
Andrew Nicols 07049468e6 MDL-61407 quizaccess: Add null_writer implementations 2018-05-03 16:14:36 +08:00
Andrew Nicols 0a8a57943c MDL-61407 quiz: Add reports for quiz 2018-05-03 16:14:36 +08:00
Andrew Nicols 9c9d3ab247 MDL-61407 qtype: Add null_writer for all qtypes 2018-05-03 16:14:35 +08:00
Andrew Nicols 1b03a7f54d MDL-61407 qformat: Add null_writer for all qformats
Questions formats do not store any personal data.
Any contrib format which does store personal data should utilise the
standard export interfaces as this subsystem will not call them directly.
2018-05-03 16:14:35 +08:00
Andrew Nicols a6a8ecc369 MDL-61407 question: Add null_writer for all behaviours
Behaviours do not store any personal data.
Any contrib behaviour which does store personal data should utilise the
standard export interfaces as this subsystem will not call them directly.
2018-05-03 16:14:34 +08:00
Andrew Nicols 84b5f665ee MDL-61407 mod_quiz: Add initial privacy implementation 2018-05-03 16:14:34 +08:00
Andrew Nicols 5b2b0e66c1 MDL-61407 question: Add initial privacy implementation 2018-05-03 16:14:34 +08:00
David Monllao 03d182e726 Merge branch 'MDL-62059-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-03 10:08:24 +02:00
Mihail Geshoski 79380f1408 MDL-62032 profilefield_text: Add privacy files and unit tests 2018-05-03 16:05:33 +08:00
Mihail Geshoski f1034de3af MDL-62030 profilefield_menu: Add privacy files and unit tests 2018-05-03 15:54:40 +08:00
Mihail Geshoski 0756be091c MDL-62007 profilefield_checkbox: Modify privacy provider 2018-05-03 15:31:38 +08:00
Mihail Geshoski 3ec3295ae1 MDL-62007 profilefield_datetime: Add privacy files and unit tests 2018-05-03 15:24:24 +08:00
Sara Arjona 9543ced2b4 MDL-62240 privacy: Avoid error when path is higher than allowed
A new method shorten_filenames has been added to moodlelib.
2018-05-03 09:17:56 +02:00
Andrew Nicols 61140b097b MDL-62240 file: Add includehash to shorten_filename + unit tests 2018-05-03 08:33:01 +02:00
Jake Dallimore 40e33083b7 Merge branch 'MDL-62264-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-05-03 14:08:39 +08:00
Jun Pataleta e916aa4ae3 Merge branch 'MDL-62202-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-03 13:31:39 +08:00
Andrew Nicols 0202ab0473 Merge branch 'MDL-62009-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-03 12:36:18 +08:00
Andrew Nicols bce56f5031 Merge branch 'wip-MDL-62312-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-03 11:11:55 +08:00
Jake Dallimore e98ad2ad05 Merge branch 'MDL-62280-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-03 10:53:54 +08:00
Marina Glancy 74a3c0a49a MDL-62312 course: Move core_publish renderer methods to course renderer 2018-05-03 10:09:13 +08:00
Jun Pataleta 3618a1a90d Merge branch 'MDL-60414-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-05-03 09:31:14 +08:00
AMOS bot 1b6af94da4 Automatically generated installer lang files 2018-05-03 00:06:43 +00:00
Andrew Nicols 7597722505 MDL-61407 question: Allow formatters to ignore caps 2018-05-03 07:29:05 +08:00
Andrew Nicols f9f59314e9 MDL-61407 privacy: Track changes in any context 2018-05-03 07:29:05 +08:00
Jun Pataleta c66ec12365 MDL-62312 admin: Move core_register renderer methods to admin renderer
* Plus CI fixes
2018-05-03 06:53:00 +08:00
Luca Bösch 4099ae4896 MDL-60414 theme_boost: bootstrap dropdown menu html spec char rendering 2018-05-02 23:03:33 +02:00
cescobedo 23e11831bf MDL-62310 core_admin: Implement Privacy API 2018-05-02 12:02:36 +02:00
Andrew Nicols acd75c858e MDL-62135 tool_log: Use plugintype_class_callback 2018-05-02 17:48:17 +08:00
Andrew Nicols 78404d4134 Merge branch 'MDL-62135-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-02 17:47:59 +08:00
cescobedo 9abf9488e1 MDL-62264 core_mnet: Implement Privacy API 2018-05-02 11:23:07 +02:00
Frédéric Massart 5881e25d35 MDL-62135 logstore_legacy: Implement privacy API 2018-05-02 17:17:47 +08:00
Frédéric Massart e8861b846e MDL-62135 logstore_database: Implement privacy API 2018-05-02 17:17:47 +08:00
Frédéric Massart f37406011f MDL-62135 logstore_standard: Implement privacy API 2018-05-02 17:17:46 +08:00
Frédéric Massart 8ff7363219 MDL-62135 tool_log: Implement privacy API 2018-05-02 17:17:46 +08:00
David Mudrák 4f7b3cb360 MDL-61905 workshop: Drop the old 1.x era tables
These tables may still contain relics of old personal data if the site
was installed before Moodle 2.0. We do not need these tables any more.
Following the "privacy by design" principles, we are dropping them now.
2018-05-02 11:17:41 +02:00
Sara Arjona 196d9c90f3 MDL-62202 privacy: Move Privacy and policies category to Users page 2018-05-02 08:46:28 +02:00
Jun Pataleta fbafd55731 Merge branch 'MDL-62253-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-02 13:52:51 +08:00
Jun Pataleta 103c72a03a Merge branch 'MDL-61898-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-05-02 13:46:31 +08:00
Frédéric Massart 4352cd98bf MDL-62214 tool_messageinbound: False negative due to time() usage
PHP Unit is so fast that my test couldn't cope with it!
2018-05-02 13:10:13 +08:00
Andrew Nicols ebe14385a9 Merge branch 'MDL-61920_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-05-02 13:07:05 +08:00
Andrew Nicols 5648cec536 Merge branch 'MDL-62266-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-05-02 12:34:58 +08:00
Andrew Nicols f80f15a178 Merge branch 'MDL-62214-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-02 12:29:50 +08:00
Andrew Nicols 6a763870e0 MDL-61800 task: Reset the OUTPUT and PAGE on execution 2018-05-02 11:57:38 +08:00
Andrew Nicols 70ebf686fd Merge branch 'MDL-62236-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-02 10:55:00 +08:00
Andrew Nicols 0153ce4fad MDL-59845 tool_lp: Add js tracking around UI refresh 2018-05-02 09:18:21 +08:00
Eloy Lafuente (stronk7) 4d1c53e490 weekly release 3.3.5+ 2018-05-01 23:04:14 +02:00
Eloy Lafuente (stronk7) 7e968c33f8 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-05-01 23:04:12 +02:00
Frédéric Massart cb1ec4e3c7 MDL-62167 core_badges: Remove usage of a reserved keyword of Oracle 2018-05-01 15:23:00 +02:00
Frédéric Massart 0318b526f9 MDL-62167 core_badges: Prevent SQL error with Oracle 2018-05-01 15:22:59 +02:00
Andrew Nicols 2cff7ff95f Merge branch 'wip-MDL-61308-33-testfix' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-05-01 12:41:47 +02:00
Adrian Greeve 4bd2ccd63b MDL-61308 assignsubmission_comments: Unit test ordering fix. 2018-05-01 12:41:37 +02:00
Andrew Nicols 40b9237b49 Merge branch 'MDL-62231-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-01 12:41:26 +02:00
Andrew Nicols 6d780cde01 MDL-61898 cache: Implement privacy API for all stores and locks 2018-05-01 12:53:37 +08:00
Shamim Rezaie d6b5be41d4 MDL-62231 block_recent_activity: Implement null provider for the block 2018-05-01 14:08:46 +10:00
Andrew Nicols 0ef3ff5b68 Merge branch 'wip-MDL-62138-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-05-01 11:57:54 +08:00
Andrew Nicols ff6db243c0 Merge branch 'MDL-61411-33' of git://github.com/Kathrin84/moodle into MOODLE_33_STABLE 2018-05-01 11:24:47 +08:00
Andrew Nicols 515f4ea924 Merge branch 'MDL-62167-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-05-01 11:15:12 +08:00
Andrew Nicols 17d02fc2a8 MDL-62280 xhprof: Support tideways_xhprof 2018-05-01 11:03:16 +08:00
Frédéric Massart c9a9c02374 MDL-62009 core_grades: Implement privacy API 2018-05-01 10:50:13 +08:00
Jun Pataleta 01ad8ce22f Merge branch 'MDL-62060-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-01 10:44:46 +08:00
Shamim Rezaie afa0d54934 MDL-62060 core_privacy: Make sure the exported json is human readable 2018-05-01 12:36:55 +10:00
Frédéric Massart 53f5e8a321 MDL-62214 tool_messageinbound: Implement privacy API 2018-05-01 09:23:01 +08:00
Frédéric Massart 886191944f MDL-62214 tool_messageinbound: Delete old messages pending verification 2018-05-01 09:22:45 +08:00
Frédéric Massart a7abfcef0e MDL-62253 core_auth: Implement privacy API 2018-05-01 09:14:39 +08:00
Jake Dallimore 2aa7deb2f0 Merge branch 'MDL-62005-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-05-01 09:10:56 +08:00
AMOS bot 6d67378c41 Automatically generated installer lang files 2018-05-01 00:07:17 +00:00
Jun Pataleta ed7e2d03f0 Merge branch 'MDL-62248-33-fix' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-30 21:25:22 +08:00
Andrew Nicols 835a653755 MDL-62248 core_privacy: Add getter for user context prefs 2018-04-30 20:37:38 +08:00
Mark Nelson 149f1ecabd MDL-61920 mod_lti: implement privacy provider 2018-04-30 19:59:54 +08:00
Mark Nelson eb16feff78 MDL-61920 ltiservice_toolsettings: implement privacy provider 2018-04-30 19:02:18 +08:00
Mark Nelson 4c65cc4464 MDL-61920 ltiservice_toolproxy: implement privacy provider 2018-04-30 19:01:59 +08:00
Mark Nelson 249a14082e MDL-61920 ltiservice_profile: implement privacy provider 2018-04-30 19:01:40 +08:00
Mark Nelson 1c38c18ca1 MDL-61920 ltiservice_memberships: implement privacy provider 2018-04-30 19:01:19 +08:00
Jun Pataleta 7c44363a80 Merge branch 'MDL-61012_v3.3.x' of https://github.com/troywilliams/moodle into MOODLE_33_STABLE 2018-04-30 17:28:51 +08:00
Sara Arjona 2cc51e4887 MDL-62266 core_availability: Implement privacy API 2018-04-30 11:22:32 +02:00
Shamim Rezaie baffbd6d6f MDL-62005 block_comments: Add implementation of Privacy API 2018-04-30 18:16:45 +10:00
Andrew Nicols f0d0414a9e MDL-62248 core_privacy: Unit test for get_user_preferences 2018-04-30 16:03:43 +08:00
Andrew Nicols 774835181e Merge branch 'MDL-62248-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-30 16:02:33 +08:00
Frédéric Massart d1caad9938 MDL-62248 core_block: Implement privacy API 2018-04-30 15:30:18 +08:00
Frédéric Massart c08b4f9466 MDL-62248 core_privacy: Test writer writes user prefs in right contexts 2018-04-30 15:29:37 +08:00
Andrew Nicols 5d22d5087a MDL-61898 core_cache: Implement Privacy API 2018-04-30 14:25:36 +08:00
Shamim Rezaie 835f7f20da MDL-62059 mod_book: Implement null provider for mod_book 2018-04-30 16:16:48 +10:00
Andrew Nicols 69943f974b Merge branch 'MDL-62235-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-30 14:01:51 +08:00
Andrew Nicols 37427de44e Merge branch 'MDL-62208-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-30 13:21:09 +08:00
Troy Williams 3d9d924be6 MDL-61012 course: Allow extending class to set 2018-04-30 16:26:09 +12:00
Andrew Nicols be2d84d913 Merge branch 'MDL-62241-33-typehint' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-04-30 11:45:41 +08:00
Andrew Nicols ee5530d552 Merge branch 'MDL-61959-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-30 10:26:04 +08:00
Andrew Nicols f303211548 MDL-61308 mod_assign: Whitespace fix 2018-04-30 09:27:25 +08:00
Andrew Nicols ca427f5389 Merge branch 'wip-MDL-61308-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-30 09:22:30 +08:00
AMOS bot b40e466d20 Automatically generated installer lang files 2018-04-30 00:06:42 +00:00
Frédéric Massart 5bfaff81e7 MDL-62235 core_files: Implement privacy API 2018-04-29 10:17:35 +08:00
Frédéric Massart 80934c2385 MDL-62236 core_webservice: Implement privacy API 2018-04-29 10:10:19 +08:00
David Mudrák 8460b91e31 MDL-62241 privacy: Do not use scalar type hinting on 3.3 branch
The tests do not actually do anything, they just make sure that the
method signature is correct on the given PHP version.
2018-04-27 15:20:03 +02:00
Eloy Lafuente (stronk7) 1e65154616 weekly release 3.3.5+ 2018-04-27 13:15:33 +02:00
Eloy Lafuente (stronk7) 0d85f27c6f MDL-61993 profilefield_checkbox: take rid of oracle reserved word 2018-04-27 10:43:20 +02:00
Frédéric Massart 8391635fd9 MDL-61877 core_competency: Handle comments in privacy API 2018-04-27 11:30:19 +08:00
Frédéric Massart acf68b58cd MDL-61877 core_competency: Implement privacy API 2018-04-27 11:30:19 +08:00
Frédéric Massart e29ec14535 MDL-62167 core_badges: Implement privacy API 2018-04-27 10:51:26 +08:00
Bas Brands 486b512bc4 MDL-62172 Theme boostrapbase: align advanced checkbox in mform 2018-04-27 09:57:55 +08:00
Eloy Lafuente (stronk7) 46895a7b3d Merge branch 'MDL-60882-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2018-04-27 01:39:05 +02:00
Eloy Lafuente (stronk7) 520cc4e661 Merge branch 'wip_MDL-62011_33_approval_of_course_request' of https://github.com/grabs/moodle into MOODLE_33_STABLE 2018-04-27 01:30:36 +02:00
Eloy Lafuente (stronk7) eaecfd8d79 Merge branch 'MDL-61993-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-27 01:01:36 +02:00
Eloy Lafuente (stronk7) 7dbc822131 Merge branch 'MDL-61863-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-26 22:32:06 +02:00
Eloy Lafuente (stronk7) 86f3c6b22f Merge branch 'MDL-61715-33' of https://github.com/lethevinh/moodle into MOODLE_33_STABLE 2018-04-26 22:23:24 +02:00
Sara Arjona 079b45c562 MDL-61959 mod_scorm: Implement privacy API 2018-04-26 19:56:53 +02:00
Sara Arjona 81f4e778e8 MDL-61959 scormreport_objectives: Implement privacy API 2018-04-26 19:07:44 +02:00
sarjona bc1e9f0914 MDL-61959 scormreport_interactions: Implement privacy API 2018-04-26 19:07:15 +02:00
Sara Arjona 28d3ae01a6 MDL-61959 scormreport_graphs: Implement privacy API 2018-04-26 19:06:41 +02:00
sarjona d5a7132a6a MDL-61959 scormreport_basic: Implement privacy API 2018-04-26 19:06:09 +02:00
Jun Pataleta 0972a5bb7c Merge branch 'MDL-61986_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-04-27 00:46:26 +08:00
Eloy Lafuente (stronk7) 04a9173ac4 MDL-61986 mod_lesson: oracle order by clob fix 2018-04-26 18:32:18 +02:00
Eloy Lafuente (stronk7) 6b003a5bc1 Merge branch 'MDL-62224_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-04-26 17:38:46 +02:00
Zig Tan 8849300bd8 MDL-61693 core_calendar: Implemented privacy providers 2018-04-26 23:00:11 +08:00
Mark Nelson 9db1054919 MDL-62224 core_rss: implement correct provider 2018-04-26 20:17:15 +08:00
Kathrin Osswald 470a789ac2 MDL-61411 theme Boost: Close navigation on all items (on small screens) 2018-04-26 13:21:28 +02:00
Juan Leyva a760d1a278 MDL-61521 course: Add missing text formatting for category name 2018-04-26 12:38:34 +02:00
Juan Leyva b4665dba28 MDL-60882 mod_choice: Avoid teacher delete all responses
Teachers should be able to delete all responses but when indicating the
response ids.
When the response ids are not passed, only their own responses should
be deleted (as the function documentation said).
2018-04-26 10:26:29 +02:00
Adrian Greeve 7fceae553c MDL-61308 assign_feedback: Privacy code for user rights. 2018-04-26 15:41:59 +08:00
Adrian Greeve 8ab65b68b0 MDL-61308 assign_submission: Privacy code for user rights. 2018-04-26 15:41:58 +08:00
Adrian Greeve e637c48678 MDL-61308 mod_assign: Adding privacy classes. 2018-04-26 15:41:58 +08:00
Andrew Nicols a20987ace8 Merge branch 'wip-MDL-62215-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-26 15:01:11 +08:00
Andrew Nicols 4444333a28 Merge branch 'MDL-61947-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-26 14:52:55 +08:00
Adrian Greeve 001b73720d MDL-62215 core_privacy: Update to methods to remove type hinting. 2018-04-26 14:49:16 +08:00
Frédéric Massart fdd07c306a MDL-62208 core_fileconverter: Implement privacy API 2018-04-26 12:55:52 +08:00
Zig Tan 05807656a2 MDL-61947 core_my: Implemented privacy providers 2018-04-26 12:51:54 +08:00
Mihail Geshoski 27fa56c9f8 MDL-61993 profilefield_checkbox: Add privacy files and unit tests 2018-04-26 10:51:25 +08:00
Eloy Lafuente (stronk7) eb960618a1 Merge branch 'MDL-61979-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-26 03:09:44 +02:00
Eloy Lafuente (stronk7) 87aaec6c82 Merge branch 'MDL-61998-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-26 02:40:18 +02:00
Andrew Nicols 08339c2799 Merge branch 'MDL-61944-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-26 08:35:21 +08:00
Eloy Lafuente (stronk7) 2b33a8b518 Merge branch 'MDL-62181-33-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-04-25 19:09:59 +02:00
David Monllao ff36037e13 Merge branch 'MDL-62175-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2018-04-25 17:37:41 +02:00
David Monllao d38c995dcd Merge branch 'MDL-61986-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-25 16:32:56 +02:00
cescobedo f26b3692c5 MDL-61944 tool_mobile: Implement Privacy API 2018-04-25 15:39:27 +02:00
David Mudrák 9701aa1a6f MDL-62181 lang: Fix changed admin node title in behat scenario 2018-04-24 22:27:16 +02:00
Helen Foster 8a936e7371 MDL-62181 lang: Merge English strings from the en_fix language pack
Significant string changes:

* sitepolicies, core_admin - 'Site policies' changed to 'Site security
  settings'
* sitepolicy_help and sitepolicyguest_help, core_admin - setting will
  only have an effect if the site policy handler is set to default
* sitepolicyhandler_desc,core_admin - improved wording
* pathtodot_help, core_admin - Windows and Mac paths
* debugstringids_desc, core_admin - improved explanation
2018-04-24 22:26:34 +02:00
Eloy Lafuente (stronk7) 48ab35f25d weekly release 3.3.5+ 2018-04-24 18:57:16 +02:00
Juan Leyva e69580756c MDL-62175 auth_email: Fix site policy enabled check 2018-04-24 15:07:09 +02:00
vinhle 3c75559a6a MDL-61715 question: qbank_chooser is not intelligent about headings 2018-04-24 16:07:54 +07:00
Zig Tan 111f4da8e4 MDL-61863 core_notes: Implemented privacy providers 2018-04-24 12:11:22 +08:00
Jun Pataleta d03959c524 Merge branch 'MDL-62079-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-24 11:55:44 +08:00
Andrew Nicols 902f812c72 MDL-62079 core_filters: Implement null provider 2018-04-24 11:49:59 +08:00
Mark Nelson 9ede824794 MDL-62140 core_privacy: only reset tests when necessary 2018-04-24 11:16:58 +08:00
Frédéric Massart 21f51cf2a6 MDL-61984 mod_chat: Do not assume context passed is one of chat 2018-04-24 11:04:19 +08:00
Andrew Nicols 1dacf6193f MDL-62140 core_privacy: Improve unit test 2018-04-24 10:20:13 +08:00
Andrew Nicols 06e1ec0cf4 Merge branch 'MDL-62140_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-04-24 10:19:49 +08:00
Jun Pataleta 2be0984d4f Merge branch 'MDL-61764_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-04-24 09:54:01 +08:00
Jun Pataleta 9826b43f94 Merge branch 'MDL-61882-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-24 09:38:04 +08:00
Andrew Nicols 660d630ad5 Merge branch 'MDL-61984-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-24 09:34:53 +08:00
Andrew Nicols f203772256 Merge branch 'MDL-61995-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-24 08:21:33 +08:00
cescobedo 6675f08970 MDL-61882 auth_oauth2: Implement Privacy API 2018-04-23 19:35:51 +02:00
David Monllao b039e36e7e Merge branch 'MDL-61915-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-23 16:26:30 +02:00
David Monllao 11379b3995 Merge branch 'MDL-62042-m33' of https://github.com/sammarshallou/moodle into MOODLE_33_STABLE 2018-04-23 16:08:27 +02:00
cescobedo 184c8ddb25 MDL-61915 enrol: Add privacy implementation for all enrol plugins
None of the Enrol plugins (except lti and paypal) have any user preference or database table.
They all implement the null provider.
2018-04-23 14:25:49 +02:00
Mark Nelson b628cab84f MDL-62140 core_privacy: add helper functions to add system/user context 2018-04-23 20:08:22 +08:00
David Monllao bc67687abf MDL-62047 core_userkey: No return types in php 5.x 2018-04-23 13:09:18 +02:00
Andrew Nicols f9bbcab782 Merge branch 'wip-MDL-61759-33' of https://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-04-23 18:32:45 +08:00
David Monllao fae6020b32 Merge branch 'MDL-62078-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-23 12:09:06 +02:00
David Monllao e0de954728 Merge branch 'MDL-62047-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-23 11:59:42 +02:00
David Monllao 59fc010ac9 Merge branch 'MDL-61891-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-23 11:55:40 +02:00
Sara Arjona 54f5ded420 MDL-61998 cohort: Implement privacy API 2018-04-23 11:44:35 +02:00
Zig Tan e93d70e1c9 MDL-61995 tool_assignmentupgrade: Implemented privacy providers 2018-04-23 16:55:19 +08:00
Marina Glancy 2d6bc5cd57 MDL-61759 admin: non-existing site policy handler means no policy 2018-04-23 16:47:27 +08:00
Andrew Nicols 501dec0271 Merge branch 'MDL-62055-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-23 16:05:23 +08:00
Jun Pataleta dd0c7b7329 Merge branch 'MDL-62049_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-04-23 13:54:24 +08:00
Marina Glancy b7f7b588a3 MDL-62138 core: remove core_register and core_publish
These components have no classes and no strings and have no purspose. Component core_hub is responsible
for storing data, defining classes and strings for site registration and course publishing

This also reverts MDL-61945
2018-04-23 13:23:32 +08:00
Jun Pataleta c592b7529c Merge branch 'wip-MDL-61966-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-23 13:11:14 +08:00
Mark Nelson 47bad57184 MDL-62049 core_privacy: use correct lang string for date 2018-04-23 13:03:47 +08:00
Andrew Nicols 9a17f41506 MDL-61891 core_portfolio: Use manager method caller 2018-04-23 10:13:43 +08:00
Andrew Nicols e435e42e29 MDL-61891 core_plagiarism: Use manager method caller 2018-04-23 10:13:14 +08:00
Andrew Nicols 63a4554474 MDL-61891 privacy: Add helper to call methods on interfaces 2018-04-23 10:11:20 +08:00
Andrew Nicols 368436baac Merge branch 'MDL-61759-33-nonexistinghandler' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-04-22 21:06:41 +08:00
Frédéric Massart d3a7b1ff87 MDL-61986 mod_lesson: Implement privacy API 2018-04-22 17:32:14 +08:00
sarjona 616559742e MDL-62078 rss: Link to core_userkey in the Privacy API implementation 2018-04-22 09:05:41 +02:00
Andreas Grabs 0b1c63416f MDL-62011 course: Approval of a course request fails 2018-04-21 20:55:36 +02:00
Eloy Lafuente (stronk7) 7bd8cd00de weekly release 3.3.5+ 2018-04-20 23:52:07 +02:00
sam marshall 37acf2d4be MDL-62042 core_search: Unicode non-characters cause indexing problems
Unicode characters such as U+FFEF can be entered into Moodle data and
cause indexing failures. This change strips them out of search fields.
2018-04-20 12:24:31 +01:00
Sara Arjona c82e60d0f3 MDL-62055 imscp: Implement privacy API 2018-04-20 09:04:53 +02:00
Adrian Greeve 062c83aae2 MDL-61966 block_myoverview: Update to provider for user preferences. 2018-04-20 14:51:56 +08:00
Andrew Nicols ac3bb88f6f MDL-61958 core_rss: Remove type-hint for PHP 5.6 2018-04-20 12:25:27 +08:00
Mark Nelson 5f02dbb5fd MDL-61764 message_popup: implement privacy provider 2018-04-20 12:10:57 +08:00
Jun Pataleta 349d0b6772 Merge branch 'MDL-62048_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-04-20 11:53:21 +08:00
Andrew Nicols a55d5c8292 Merge branch 'MDL-61892-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-20 11:49:59 +08:00
Zig Tan a85d8cffc1 MDL-61892 admin/tools: Implement null privacy providers 2018-04-20 11:46:30 +08:00
Andrew Nicols 4caf14d0dc Merge branch 'wip-MDL-62035-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-20 11:36:19 +08:00
Adrian Greeve 5b9837e832 MDL-62035 core_blog: Update to blog with comments.
This makes blog use the updated delete methods in the
comments provider.
2018-04-20 10:52:05 +08:00
Adrian Greeve ed7c8cf849 MDL-62035 core_comment: Update to deletion methods.
Also clarification with the export method to clarify that it
is only for one context.
2018-04-20 10:51:51 +08:00
Andrew Nicols 6a76fdfa40 Merge branch 'MDL-62003-33-privacyfiles' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-04-20 10:43:54 +08:00
Jun Pataleta 36f4e4c861 Merge branch 'MDL-61848-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-20 09:19:35 +08:00
Andrew Nicols 10093c3635 MDL-61836 blog: Fix random order failures 2018-04-20 08:57:11 +08:00
Łukasz Szeremeta c9ef8771ce MDL-61827 auth: Change Facebook Graph API v2.8 to v.2.12 in OAuth2
Use v2.12 Facebook Graph API instead of v2.8
2018-04-20 02:33:55 +02:00
Eloy Lafuente (stronk7) 5f2fe216f0 Merge branch 'MDL-61836-33-fix' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-20 02:29:04 +02:00
Eloy Lafuente (stronk7) bf91ad7c8c Merge branch 'MDL-61991-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-04-20 02:25:10 +02:00
Eloy Lafuente (stronk7) be960b40a0 Merge branch 'MDL-61975-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-20 02:18:14 +02:00
Andrew Nicols 48037ff7b0 MDL-61836 comment: Add missing require 2018-04-20 08:17:59 +08:00
Eloy Lafuente (stronk7) a5ca61930d Merge branch 'MDL-61348-take2_33' of git://github.com/timhunt/moodle into MOODLE_33_STABLE 2018-04-20 02:02:15 +02:00
cescobedo fa334d3119 MDL-61848 auth_manual: Implement Privacy API 2018-04-20 00:28:40 +02:00
Andrew Nicols b71fc4ce4b Merge branch 'MDL-61836-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-19 20:37:33 +08:00
Frédéric Massart 113e66d70b MDL-61984 mod_chat: Implement privacy API 2018-04-19 17:33:14 +08:00
Frédéric Massart 297661d754 MDL-61836 core_blog: Prevent randomness in comments order 2018-04-19 16:07:09 +08:00
Mark Nelson e8112121d5 MDL-62025 mod_choice: add missing join on modules table 2018-04-19 15:52:42 +08:00
Andrew Nicols 6480c4091e MDL-62047 core_userkey: Add privacy implementation 2018-04-19 15:30:39 +08:00
Andrew Nicols b81b826c4a MDL-62047 core_userkey: Define component path 2018-04-19 15:26:09 +08:00
Andrew Nicols af1c644712 Merge branch 'MDL-61568-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-19 15:01:37 +08:00
Andrew Nicols 3a84788acf Merge branch 'MDL-61970-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-19 14:54:02 +08:00
Andrew Nicols 78ecf75ead Merge branch 'MDL-61969-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-19 14:49:44 +08:00
Jun Pataleta 721fd1795f Merge branch 'MDL-61878-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-19 14:39:55 +08:00
Zig Tan c92feb872d MDL-61568 repository_flickr: Fix oauth secret export 2018-04-19 14:39:47 +08:00
Mihail Geshoski b7844952d7 MDL-61878 fileconverter_googledrive: Add privacy files and unit tests 2018-04-19 13:20:50 +08:00
Frédéric Massart 34d73b6faa MDL-61970 mod_survey: Do not assume context passed is one of survey 2018-04-19 13:12:48 +08:00
Mark Nelson cb4f59d780 MDL-62048 core_privacy: extend test to ensure table exists 2018-04-19 13:04:11 +08:00
Andrew Nicols 521751de69 Merge branch 'MDL-61945-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-19 11:56:32 +08:00
Andrew Nicols c813b07254 Merge branch 'MDL-61948-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-19 11:47:50 +08:00
Andrew Nicols 399252fd85 Merge branch 'MDL-61836-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-19 11:22:07 +08:00
Andrew Nicols bdbe55c831 Merge branch 'MDL-61970-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-19 11:13:53 +08:00
David Monllao 7ff43c2334 Merge branch 'MDL-61716-33' of git://github.com/mastnym/moodle into MOODLE_33_STABLE 2018-04-18 17:40:10 +02:00
David Monllao 35b09d5623 MDL-61958 rss: Add rss test suite 2018-04-18 17:38:28 +02:00
David Monllao 9073a4e708 Merge branch 'MDL-61958-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-18 17:22:40 +02:00
David Mudrák f3a972d97a MDL-62003 privacy: Consistently export files into _files folder
There were two major issues with the previous implementation:

* The exported folder name was localised so it was "Files" or "Soubory"
  etc depending on the current language. Yet URLs referring to the files
  in that folder were always rewritten with hard-coded English "files".
* Files from all fileareas and itemids were all exported to a single
  target directory. So if there were two files with the same name being
  exported from multiple areas (such as submission_content and
  submission_attachment in the workshop module), one would overwrite
  another.

The patch addresses these issues as follows:

* To unify the folder name and also to minimise the risk of conflict
  with a subcontext folder, we now always export stored files under
  "_files" folder.
* Under that folder, there is a subdirectory with the area name and then
  eventually another subdirectory with non-zero itemid. And there
  finally the stored_file is exported to under its own file path.
2018-04-18 17:08:16 +02:00
Martin Mastny 8b58e0535c MDL-61716 auth_oauth2: field names in mappings allow all characters 2018-04-18 16:54:45 +02:00
David Monllao dced5c43c8 Merge branch 'MDL-38099-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-04-18 14:14:55 +02:00
Sara Arjona 7ce30dda42 MDL-61958 core_rss: Implement privacy API 2018-04-18 13:38:00 +02:00
Eloy Lafuente (stronk7) 5c4ff2db85 Merge branch 'MDL-61621_33' of git://github.com/dmonllao/moodle into MOODLE_33_STABLE 2018-04-18 12:58:59 +02:00
Jun Pataleta 31d0fb4349 Merge branch 'MDL-62025_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-04-18 16:25:43 +08:00
Jun Pataleta a2155a12e4 Merge branch 'MDL-61928_33' of git://github.com/timhunt/moodle into MOODLE_33_STABLE 2018-04-18 16:00:21 +08:00
Mark Nelson 774108ca8a MDL-62025 mod_choice: only export in the CONTEXT_MODULE context 2018-04-18 15:12:37 +08:00
Frédéric Massart c9ca50d029 MDL-61970 mod_survey: Implement privacy API 2018-04-18 14:56:31 +08:00
Andrew Nicols 5298471d0f Merge branch 'MDL-61568-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-18 14:26:01 +08:00
Mihail Geshoski 22f6afdcd5 MDL-61969 datapreset_imagegallery: Implement null privacy provider 2018-04-18 13:51:35 +08:00
Zig Tan 0a617a7e20 MDL-61568 core_repository: Implement privacy providers 2018-04-18 13:49:33 +08:00
Zig Tan 73f8e3dc26 MDL-61568 repository_onedrive: Implement privacy providers 2018-04-18 13:49:33 +08:00
Zig Tan 709350d111 MDL-61568 repository_youtube: Implement privacy providers 2018-04-18 13:49:33 +08:00
Zig Tan 8186a5994d MDL-61568 repository_wikimedia: Implement privacy providers 2018-04-18 13:49:27 +08:00
Zig Tan 70698f7964 MDL-61568 repository_picasa: Implement privacy providers 2018-04-18 13:47:56 +08:00
Zig Tan ecebec32bc MDL-61568 repository_merlot: Implement privacy providers 2018-04-18 13:47:56 +08:00
Zig Tan 5b0ae8c97d MDL-61568 repository_googledocs: Implement privacy providers 2018-04-18 13:47:56 +08:00
Zig Tan ce52426d52 MDL-61568 repository_flickr_public: Implement privacy providers 2018-04-18 13:47:56 +08:00
Zig Tan a00de36d15 MDL-61568 repository_flickr: Implement privacy providers 2018-04-18 13:47:44 +08:00
Mihail Geshoski 0f4c592b5c MDL-61948 core_media: Implement null privacy provider 2018-04-18 13:44:30 +08:00
Jun Pataleta 07f6d8962c Merge branch 'MDL-61520-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2018-04-18 13:28:12 +08:00
Andrew Nicols 132ea1c052 Merge branch 'MDL-61957-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-18 13:10:34 +08:00
Zig Tan 9f2f2294d8 MDL-61979 tool_cohortroles: Implemented privacy providers 2018-04-18 10:55:05 +08:00
Eloy Lafuente (stronk7) c873339cc1 Merge branch 'm33_MDL-59857' of https://github.com/danmarsden/moodle into MOODLE_33_STABLE 2018-04-18 03:08:35 +02:00
Luca Bösch a5dddf9bff MDL-61991 theme_boost: Question correctness displayed as label. 2018-04-17 22:38:24 +02:00
Luca Bösch 9152286263 MDL-38099 comments: year in comments date 2018-04-17 22:37:33 +02:00
Eloy Lafuente (stronk7) 3e3a083ed1 weekly release 3.3.5+ 2018-04-17 19:54:34 +02:00
Eloy Lafuente (stronk7) a879012464 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-04-17 19:54:32 +02:00
Sara Arjona 18b98348a9 MDL-61957 gradereport_user: Implement privacy API 2018-04-17 14:48:04 +02:00
Sara Arjona caeb922dea MDL-61957 gradereport_singleview: Implement privacy API 2018-04-17 14:47:19 +02:00
Sara Arjona f79f0b5975 MDL-61957 gradereport_overview: Implement privacy API 2018-04-17 14:46:35 +02:00
Sara Arjona 6b8921a67b MDL-61957 gradereport_outcomes: Implement privacy API 2018-04-17 14:45:55 +02:00
Sara Arjona 01dd8aff46 MDL-61957 gradereport_history: Implement privacy API 2018-04-17 14:45:14 +02:00
Sara Arjona f4c5e78107 MDL-61957 gradereport_grader: Implement privacy API 2018-04-17 14:44:30 +02:00
Andrew Nicols 019a88a178 MDL-61663 phpunit: Add portfolio to the testsuite list 2018-04-17 14:45:04 +08:00
cescobedo ef66a33a94 MDL-61945 core_register: Implement Privacy API 2018-04-17 08:26:26 +02:00
Jun Pataleta 6411b74074 Merge branch 'MDL-61862-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-17 12:04:20 +08:00
Andrew Nicols 3b8ee4c3a0 Merge branch 'wip-MDL-61663-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-17 11:46:58 +08:00
Adrian Greeve a3a7a072e1 MDL-61663 portfolio: Update to the external system link names.
Changed the name of the link to something less like an English
string for each of the portfolios.
2018-04-17 11:44:10 +08:00
Andrew Nicols db1a3e6623 Merge branch 'MDL-61977-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-17 11:43:32 +08:00
Frédéric Massart 739507da50 MDL-61862 mod_feedback: Tweak query to support UNION on TEXT fields
Thanks Oracle.
2018-04-17 11:36:55 +08:00
Andrew Nicols ace39db60f Merge branch 'MDL-61980-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-17 11:35:37 +08:00
Andrew Nicols 4dd2d6a7e0 Merge branch 'MDL-61916-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-17 11:19:40 +08:00
Zig Tan 1414c0c83a MDL-61568 repository_dropbox: Implement privacy providers 2018-04-17 11:16:58 +08:00
Zig Tan 9fd2c9c529 MDL-61568 repository_boxnet: Implement privacy providers 2018-04-17 11:14:50 +08:00
Andrew Nicols d405b3b89a Merge branch 'MDL-61918-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-17 11:13:16 +08:00
Zig Tan 65f6e6ad89 MDL-61568 repository_webdav: Implement null privacy provider 2018-04-17 11:12:59 +08:00
Zig Tan 948d3f566f MDL-61568 repository_user: Implement null privacy provider 2018-04-17 11:11:22 +08:00
Andrew Nicols 8cd3227cd4 Merge branch 'MDL-61903-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-17 11:10:36 +08:00
Zig Tan a5947dc4cc MDL-61568 repository_url: Implement null privacy provider 2018-04-17 11:10:21 +08:00
Zig Tan b767d92456 MDL-61568 repository_upload: Implement null privacy provider 2018-04-17 11:08:37 +08:00
Zig Tan 208a7c059f MDL-61568 repository_skydrive: Implement null privacy provider 2018-04-17 11:07:09 +08:00
Zig Tan bbaea992ab MDL-61568 repository_s3: Implement null privacy provider 2018-04-17 11:06:07 +08:00
Zig Tan 6b318d7f2b MDL-61568 repository_recent: Implement null privacy provider 2018-04-17 11:04:44 +08:00
Zig Tan 3656528c45 MDL-61568 repository_local: Implement null privacy provider 2018-04-17 11:03:35 +08:00
Zig Tan 80ba17b0a5 MDL-61568 repository_filesystem: Implement null privacy provider 2018-04-17 11:02:21 +08:00
Zig Tan fe9954ef1f MDL-61568 repository_equella: Implement null privacy provider 2018-04-17 11:00:56 +08:00
Zig Tan b94fe0ece2 MDL-61568 repository_coursefiles: Implement null privacy provider 2018-04-17 10:59:52 +08:00
Zig Tan c585e4fc60 MDL-61568 repository_areafiles: Implement null privacy provider 2018-04-17 10:58:36 +08:00
Mihail Geshoski e217c239fd MDL-61903 webservice: Implement null privacy provider
Implement null privacy provider to rest, soap and xmlrpc webservice plugins.
2018-04-17 09:21:19 +08:00
Dan Marsden bdb5843290 MDL-59857 mod_scorm: use valid length for grade type field. 2018-04-17 08:44:50 +12:00
Jun Pataleta 2eb7414d52 Merge branch 'MDL-61862-33-56' of git://github.com/FMCorz/moodle into MOODLE_33_STABLE 2018-04-16 23:29:50 +08:00
Eloy Lafuente (stronk7) 225408d744 MDL-61819 editor: add testsuite to phpunit.xml 2018-04-16 16:38:58 +02:00
David Monllao 07fa93a0ec Merge branch 'MDL-61819-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-16 16:15:29 +02:00
Andrew Nicols 86feef9a01 MDL-61819 core_editor: Implement core provider 2018-04-16 21:54:32 +08:00
Andrew Nicols d885504581 MDL-61819 editor_atto: Implement null provider 2018-04-16 21:54:32 +08:00
Andrew Nicols 1e9ba15782 MDL-61819 editor: Implement editor null providers 2018-04-16 21:54:07 +08:00
Frédéric Massart e07927711e MDL-61862 mod_feedback: Implement core_privacy API 2018-04-16 18:47:14 +08:00
David Monllao 1ff3c3a64c Merge branch 'MDL-61741-33-paypal' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-04-16 10:59:04 +02:00
David Monllao 933afbd395 Merge branch 'wip-MDL-61808-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-16 10:04:09 +02:00
Jun Pataleta 0fc22245e1 Merge branch 'MDL-61708-MOODLE33-lti-fullnamedisplay' of https://github.com/wjroes/moodle into MOODLE_33_STABLE 2018-04-16 15:29:52 +08:00
Sara Arjona 81ea58cdf5 MDL-61958 rss: Create core_rss lang file and move rss string
At the moment will only be copied one of the rss strings ('rss').
The issue MDL-61997 has been created to move the rest of the core_rss lang
strings from moodle.php to rss.php.

AMOS BEGIN
 CPY [rss,core],[rss,core_rss]
AMOS END
2018-04-16 09:17:52 +02:00
Sara Arjona 0682576b8e MDL-61958 lang: Move privatefilesmanage string to correct place 2018-04-16 09:17:52 +02:00
Jun Pataleta 4a12d7a081 Merge branch 'MDL-61974-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-16 13:16:11 +08:00
Andrew Nicols 517baef479 MDL-61974 privacy: Rewrite the content writer storage 2018-04-16 11:11:47 +08:00
Andrew Nicols b88a6ac832 Merge branch 'MDL-61952-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-16 10:52:15 +08:00
Andrew Nicols 4ccebf873e Merge branch 'MDL-61954-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-04-16 10:47:35 +08:00
Andrew Nicols bc77389997 Merge branch 'MDL-61902-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-16 10:22:10 +08:00
Mihail Geshoski fbf8d40f98 MDL-61918 assignment: Implement null privacy provider
Implement null privacy provider to offline, online, upload and uploadsingle assignment plugins.
2018-04-16 10:03:25 +08:00
Mihail Geshoski 0c8d774cba MDL-61902 media: Implement null privacy provider 2018-04-16 09:48:32 +08:00
AMOS bot 51b7c14545 Automatically generated installer lang files 2018-04-16 00:07:30 +00:00
Adrian Greeve 396fe24044 MDL-61808 tool_monitor: Implemented privacy classes.
This plugin is now compatible with the new privacy system.
2018-04-14 10:57:28 +08:00
Mihail Geshoski 7b9251eb7f MDL-61980 booktool: Implement null privacy provider
Implement null privacy provider into booktool_exportimscp, booktool_importhtml, booktool_print plugin.
2018-04-13 16:20:49 +08:00
David Mudrák 5f9e43efaa MDL-61759 admin: Fix notice if attempting use nonexisting policy handler
The list of all known handlers may not contain the configured value,
raising the PHP undefined index notice.
2018-04-13 10:00:34 +02:00
Jake Dallimore 1568fc669c MDL-61663 portfolio_picasa: add privacy provider implementation 2018-04-13 14:49:57 +08:00
Jake Dallimore 3a3abbbbd8 MDL-61663 portfolio_googledocs: add privacy provider implementation 2018-04-13 14:49:56 +08:00
Jake Dallimore ca50317233 MDL-61663 portfolio_flickr: add privacy provider implementation 2018-04-13 14:49:56 +08:00
Jake Dallimore b8bea9d1b7 MDL-61663 portfolio_download: add privacy provider implementation 2018-04-13 14:49:56 +08:00
Jake Dallimore a4535a6511 MDL-61663 portfolio_boxnet: add privacy provider implementation 2018-04-13 14:49:56 +08:00
Jake Dallimore f5579a67d8 MDL-61663 portfolio_mahara: add privacy provider implementation 2018-04-13 14:49:55 +08:00
Jake Dallimore ff0e438780 MDL-61663 core_portfolio: add subsystem privacy provider
Added provider for portfolio plugins, and legacy polyfill for plugins.
2018-04-13 14:49:54 +08:00
Zig Tan f9d9e29861 MDL-61977 tool_profiling: Implemented null privacy provider 2018-04-13 14:40:42 +08:00
Zig Tan c4b7e6de55 MDL-61975 tool_recyclebin: Implemented null privacy provider 2018-04-13 13:59:42 +08:00
Frédéric Massart 6275657518 MDL-61836 core_blog: Implement privacy API 2018-04-13 13:31:22 +08:00
David Monllao e1ed5f7ae4 weekly release 3.3.5+ 2018-04-12 14:38:19 +02:00
David Monllao 5204900673 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-04-12 14:38:18 +02:00
Sara Arjona a2a91c1fcf MDL-61954 gradeimport_xml: Implement privacy API 2018-04-12 09:57:57 +02:00
Sara Arjona 5ae13d00c0 MDL-61954 gradeimport_direct: Implement privacy API 2018-04-12 09:57:27 +02:00
Sara Arjona 2c746ce80a MDL-61954 gradeimport_csv: Implement privacy API 2018-04-12 09:56:43 +02:00
Sara Arjona a79e82588d MDL-61952 gradeexport_xml: Implement privacy API 2018-04-12 08:32:30 +02:00
Sara Arjona 0405156624 MDL-61952 gradeexport_xls: Implement privacy API 2018-04-12 08:32:16 +02:00
Sara Arjona a8f19ad776 MDL-61952 gradeexport_txt: Implement privacy API 2018-04-12 08:31:35 +02:00
Sara Arjona 9de64f724e MDL-61952 gradeexport_ods: Implement privacy API 2018-04-12 08:31:07 +02:00
nlnrose cb411703b7 MDL-61802 Admin: Corrected typo in test file.
The file privcacy_provider_test.php was supposed to be
privacy_provider_test.php.
2018-04-12 00:24:09 +02:00
Eloy Lafuente (stronk7) 6477811c56 Merge branch 'MDL-61828-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-12 00:14:57 +02:00
Eloy Lafuente (stronk7) 0103da4a97 Merge branch 'MDL-61895-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-11 23:58:34 +02:00
Eloy Lafuente (stronk7) 1475e116df Merge branch 'MDL-61896-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-11 23:55:14 +02:00
David Monllao e0228935e4 MDL-61743 message: Add context level checking 2018-04-11 19:32:31 +02:00
David Monllao b43a5dd313 MDL-61743 core_privacy: Add context level checks for all users deletion 2018-04-11 19:32:26 +02:00
Andrew Nicols 9c68283112 MDL-61743 core_privacy: Reduce context specificty
Deletion is called for a context against all components, not just
modules.
2018-04-11 19:32:08 +02:00
David Monllao 8cb537ec1b Merge branch 'MDL-61873-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-11 18:42:09 +02:00
David Monllao 2e980b6b3a Merge branch 'MDL-61581-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-04-11 18:08:10 +02:00
Jake Dallimore 1c93fc9444 Merge branch 'MDL-59691-33' of https://github.com/lucisgit/moodle into MOODLE_33_STABLE 2018-04-11 16:02:31 +08:00
Simey Lameze 5155bf10bc MDL-61520 quiz: fix references for xhtml on stats report 2018-04-11 10:49:45 +08:00
Andrew Nicols 1a83ee366d Merge branch 'MDL-61881-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-11 10:16:24 +08:00
Zig Tan cd0173d077 MDL-61881 report: fix privacy lang strings 2018-04-11 10:12:23 +08:00
Andrew Nicols 9280d2ca0b Merge branch 'MDL-61731-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-11 09:12:51 +08:00
Mihail Geshoski ee49ade9c9 MDL-61731 message_email: Add privacy files and unit tests 2018-04-11 09:08:19 +08:00
Andrew Nicols 1eaf0be6ed Merge branch 'MDL-61867-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-11 08:52:42 +08:00
AMOS bot 7c46fbea90 Automatically generated installer lang files 2018-04-11 00:07:34 +00:00
Tim Hunt 5d307557cb MDL-61928 formslib: shortforms should work with non-editable forms 2018-04-10 17:40:25 +01:00
Tim Hunt 24d2357da7 MDL-61348 quiz reports: fix incorrect groups averages
the averages were wrong if a user had mulitple enrolments in a course,
which can happen with some enrolment plugins.
2018-04-10 17:12:09 +01:00
Eloy Lafuente (stronk7) 00cb9fe1e1 Merge branch 'wip-MDL-58697-33-assigngrading' of git://github.com/adamann2/moodle into MOODLE_33_STABLE 2018-04-10 15:54:26 +02:00
David Monllao fd772ad29a Merge branch 'MDL-61838-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-10 13:44:28 +02:00
David Monllao 84f821c5c8 Merge branch 'MDL-61843-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-10 13:42:57 +02:00
Eloy Lafuente (stronk7) dd5039e55d MDL-61875 tests: Use existing component & support $CFG->admin 2018-04-10 13:12:14 +02:00
Eloy Lafuente (stronk7) 6e5876ca57 Merge branch 'MDL-61875-33' of https://github.com/snake/moodle into MOODLE_33_STABLE 2018-04-10 13:06:53 +02:00
David Monllao 8392c88414 Merge branch 'MDL-61846-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-10 08:59:45 +02:00
David Monllao fddf02e152 Merge branch 'MDL-61129-fix-accessibility-on-tables-mod_survey_Moodle-33' of https://github.com/guillalva06/moodle into MOODLE_33_STABLE 2018-04-10 07:59:22 +02:00
Andrew Nicols 94714224d9 Merge branch 'MDL-61795-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-10 10:58:15 +08:00
Mihail Geshoski e17623068c MDL-61795 block_rss_client: Add privacy files and unit tests 2018-04-10 09:42:33 +08:00
Jake Dallimore 0ccecc5f49 MDL-61875 core_privacy: update the core_component_list in the manager 2018-04-10 08:52:01 +08:00
Jake Dallimore 3ad05e0471 MDL-61875 core_component: new method to get full components list 2018-04-10 08:51:59 +08:00
Eloy Lafuente (stronk7) bc3e7588b9 Merge branch 'MDL-61860-33' of https://github.com/mackensen/moodle into MOODLE_33_STABLE 2018-04-10 01:01:17 +02:00
Eloy Lafuente (stronk7) 61ab947bd1 Merge branch 'MDL-60196_33' of https://github.com/mfabriczy/moodle into MOODLE_33_STABLE 2018-04-10 00:57:46 +02:00
cescobedo 6757aa403e MDL-61916 format: Add privacy implementation for all format plugins
None of the Course format plugins have any user preference or database table.
They all implement the null provider.
2018-04-10 00:31:12 +02:00
Daniel Thies f9c68b4a4d MDL-61476 mod_glossary: Check XML arrays exist 2018-04-09 23:47:34 +02:00
Daniel Thies ff9019a16b MDL-61476 mod_glossary: Support tags in entries export 2018-04-09 23:47:26 +02:00
Eloy Lafuente (stronk7) 3857876a58 Merge branch 'MDL-61861-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-09 20:30:41 +02:00
Tony Butler 3eef55dda4 MDL-59691 assignfeedback_editpdf: Allow comment placement to all edges
Plus a couple of extra usability improvements:
- Collapse comment during move to allow precise placement
- Change cursor style to indicate that dragging is possible
2018-04-09 16:56:35 +01:00
Tony Butler 8531f802ec MDL-59691 assignfeedback_editpdf: Allow comments to collapse to top-left
Forcing them to collapse to the bottom-left corner seems less natural
and effectively changes the location of existing comments from pre-3.3
2018-04-09 16:56:35 +01:00
Guillermo Alvarez 77e0eaf2a6 MDL-61129 survey: Add colgroup attribute at survey question tables 2018-04-09 10:32:07 -05:00
Andrew Nicols d2979fb33f Merge branch 'MDL-61829-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-09 15:30:15 +08:00
Zig Tan ed3ab1da74 MDL-61829 block_community: Implement privacy provider 2018-04-09 14:12:12 +08:00
Mihail Geshoski 9f5aecebfe MDL-61867 fileconverter_unoconv: Add privacy files 2018-04-09 11:45:06 +08:00
Zig Tan 192e9b2e1e MDL-61881 report_usersessions: Implement null privacy provider 2018-04-09 10:48:37 +08:00
Zig Tan 737ab6eff8 MDL-61881 report_stats: Implement null privacy provider 2018-04-09 10:47:57 +08:00
Zig Tan 652ce0a4dd MDL-61881 report_security: Implement null privacy provider 2018-04-09 10:46:55 +08:00
Zig Tan 63de5af968 MDL-61881 report_questioninstances: Implement null privacy provider 2018-04-09 10:46:18 +08:00
Zig Tan 6bc3ca7a4c MDL-61881 report_performance: Implement null privacy provider 2018-04-09 10:41:15 +08:00
Helen Foster 5bb45aaa3c MDL-61033 mod_quiz: Update lang string 2018-04-09 10:41:04 +08:00
Andrew Nicols 34931397bc Merge branch 'MDL-61033-33' of https://github.com/nashtechdev01/moodle into MOODLE_33_STABLE 2018-04-09 10:40:56 +08:00
Zig Tan 747373c3f6 MDL-61881 report_participation: Implement null privacy provider 2018-04-09 10:40:20 +08:00
Zig Tan 31b0b02025 MDL-61881 report_outline: Implement null privacy provider 2018-04-09 10:39:22 +08:00
Zig Tan 168d335990 MDL-61881 report_loglive: Implement null privacy provider 2018-04-09 10:37:49 +08:00
Zig Tan 932689aa5e MDL-61881 report_log: Implement null privacy provider 2018-04-09 10:36:53 +08:00
Zig Tan 09913a019b MDL-61881 report_eventlist: Implement null privacy provider 2018-04-09 10:35:10 +08:00
Zig Tan dee60ecadb MDL-61881 report_courseoverview: Implement null privacy provider 2018-04-09 10:33:43 +08:00
Zig Tan 4017db1b69 MDL-61881 report_configlog: Implement null privacy provider 2018-04-09 10:32:27 +08:00
Zig Tan a2881f0511 MDL-61881 report_competency: Implement null privacy provider 2018-04-09 10:27:17 +08:00
Zig Tan da6c666441 MDL-61881 report_backup: Implement null privacy provider 2018-04-09 10:26:32 +08:00
Andrew Nicols 04de230de4 MDL-61896 filter: Implement privacy API for all filters 2018-04-08 15:54:34 +08:00
Andrew Nicols 89ed12aa50 MDL-61895 availability: Implement null provider for plugins 2018-04-08 14:23:23 +08:00
Andrew Nicols 767a4a4da5 MDL-61861 privacy: Add unit tests to check all providers. 2018-04-08 14:13:24 +08:00
Andrew Nicols 0014edcb6e MDL-61828 core_privacy: Support proper nesting in test trees 2018-04-08 13:31:31 +08:00
Charles Fulton 6a73402fdf MDL-61860 auth: standardise config inclusion 2018-04-07 12:20:30 -04:00
Willem Roes 67553b916f MDL-61708 mod_lti: use fullname for lis_person_name_full
Fullname passed on to LTI Provider was in format 'firstname lastname'
completely ignoring fullnamedisplay settings.
2018-04-07 09:33:14 +02:00
Luca Bösch dc57cba6be MDL-61581 lesson: style continue to last buttons 2018-04-06 16:41:46 +02:00
David Monllao 08cbe9b56c MDL-61621 blocks: New API function 2018-04-06 13:13:40 +02:00
cescobedo fd07089a41 MDL-61873 auth: Add privacy implementation for all auth plugins
None of the Auth plugins (except manual and oauth2) have any user preference or database table.
They all implement the null provider.
2018-04-06 13:13:27 +02:00
Andrew Nicols 77e236ca8f MDL-61861 core_tag: Correct langstring identifier 2018-04-06 14:21:59 +08:00
Mihail Geshoski f50f0978da MDL-61846 dataformat: Add privacy implementation for all plugins 2018-04-06 09:26:06 +08:00
Mihail Geshoski 30eced81da MDL-61843 report_completion: Add privacy files 2018-04-06 09:14:50 +08:00
Mihail Geshoski ea82e35775 MDL-61838 report_progress: Add privacy files 2018-04-06 09:01:26 +08:00
Eloy Lafuente (stronk7) 14fc7f597a weekly release 3.3.5+ 2018-04-05 15:38:08 +02:00
Eloy Lafuente (stronk7) 16c3e11c0d Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-04-05 15:38:06 +02:00
Jake Dallimore de3f8e2653 Merge branch 'MDL-61761-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-05 13:19:01 +08:00
Mihail Geshoski cc2454a92b MDL-61761 message_jabber: Add privacy files and unit tests 2018-04-05 11:59:38 +08:00
Jake Dallimore 01d52250a4 Merge branch 'wip-MDL-61163-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-04-05 10:37:46 +08:00
Andrew Nicols 2aa76eae1d Merge branch 'MDL-60726-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-04-05 08:39:39 +08:00
Eloy Lafuente (stronk7) 57d9e97c00 Merge branch 'MDL-61818-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-05 01:10:39 +02:00
Rohith e79517f1ee MDL-61746 PARAM_CLEANHTML: Fix documentation typos 2018-04-05 00:43:45 +02:00
Eloy Lafuente (stronk7) a000775fed Merge branch 'MDL-61781-33-fix' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-04-04 10:51:40 +02:00
Jun Pataleta 7bd0c3beba MDL-61781 admin_settings: Fix default settings value for docroot 2018-04-04 16:48:13 +08:00
Zig Tan 583281c7e6 MDL-60726 assign: Fix assign submission confirmation alignment 2018-04-04 16:35:30 +08:00
Andrew Nicols ed070b8d46 Merge branch 'MDL-61692-33-2' of https://github.com/snake/moodle into MOODLE_33_STABLE 2018-04-04 13:08:49 +08:00
Andrew Nicols 86b5c08a80 Merge branch 'wip-MDL-56635-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-04-04 11:32:42 +08:00
Jake Dallimore 6eb7886c9c MDL-61692 core_privacy: add privacyfields to link_ methods
Some subsystems are like conduits, passing data along to plugins which,
in turn, send the data externally. Only the component linking to (using)
the subsystem will know what data it is sending along to the eventual
external system, so should be able to specify this at the time of
linking. The same goes for plugintypes.
2018-04-04 10:04:07 +08:00
Andrew Nicols 80ca92cfc7 Merge branch 'MDL-61751-33-fix' of https://github.com/snake/moodle into MOODLE_33_STABLE 2018-04-04 09:12:08 +08:00
Jake Dallimore 958b46ad18 MDL-61751 core_plagiarism: fix fatal error with privacy legacy polyfill 2018-04-04 09:00:45 +08:00
Eloy Lafuente (stronk7) 742af6b337 Merge branch 'MDL-61451-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-04-04 01:40:57 +02:00
Eloy Lafuente (stronk7) 11e04e1bd4 Merge branch 'MDL-61817-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-04 01:23:22 +02:00
Eloy Lafuente (stronk7) 62a0907588 MDL-61751 core_plagiarism: add testsuite to phpunit.xml 2018-04-04 01:06:51 +02:00
Luca Bösch bbd4e0c745 MDL-61502 questions: add filter tests to gapselect question type. 2018-04-04 00:58:02 +02:00
Eloy Lafuente (stronk7) e3bcf576b1 Merge branch 'wip-MDL-61522-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-04-04 00:46:43 +02:00
Eloy Lafuente (stronk7) a98506c8e4 Merge branch 'MDL-61703-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-04 00:35:20 +02:00
Eloy Lafuente (stronk7) 4853023e80 Merge branch 'MDL-61751-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-04 00:24:08 +02:00
Eloy Lafuente (stronk7) 61ee905511 Merge branch 'MDL-61781-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-04-03 23:47:48 +02:00
Eloy Lafuente (stronk7) 04cfb8194a Merge branch 'MDL-61724-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-04-03 23:40:17 +02:00
Eloy Lafuente (stronk7) 623ee07cfe Merge branch 'MDL-60115-Book-cancel-button-redirect-bug-33' of https://github.com/Moodlers/moodle-1 into MOODLE_33_STABLE 2018-04-03 21:46:41 +02:00
Marcus Fabriczy a83ceb2be8 MDL-60196 core_course: Fix the display of custom LTI icons
Custom LTI icons attached to LTI tools did not display - a regression
caused by MDL-55796.

Change-Id: I9b956f4b4959a992fe763cdb05cf684cd92cc8de
2018-04-03 20:37:45 +09:30
Jake Dallimore 1b6f7526df Merge branch 'wip-MDL-61815-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-03 17:54:43 +08:00
Jake Dallimore 707e1c5527 Merge branch 'wip-MDL-61127-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-03 17:35:58 +08:00
Adrian Greeve cbca0b7c89 MDL-61127 filepicker: Selected repository now highlighted. 2018-04-03 16:44:38 +08:00
Adrian Greeve b2ee1cf532 MDL-61127 filepicker: Added aria-selected attribute to repos.
The repository list in the file picker now as aria-selected
added to denote which repository is selected.
2018-04-03 16:44:30 +08:00
Andrew Nicols 5e8a151aff Merge branch 'wip-MDL-61629-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-04-03 16:00:25 +08:00
Adrian Greeve fcedf5a69b MDL-61629 message_airnotifier: Add privacy files and unit tests. 2018-04-03 14:47:19 +08:00
Andrew Nicols abf6c76dbf Merge branch 'MDL-61020-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-04-03 14:21:58 +08:00
Adrian Greeve 1b842c1eed MDL-61815 core_privacy: Fix for metadata types and new method.
Minor fix for subsystem_link and plugintype_link.
Addition of get_null_provider_reason in the manager class.
2018-04-03 13:57:33 +08:00
Eloy Lafuente (stronk7) 036ab38556 Merge branch 'MDL-61689-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-03 01:17:35 +02:00
Eloy Lafuente (stronk7) 2baf76b657 MDL-61223 course: keep some tests using old values (January 1st 1970) 2018-04-03 00:14:01 +02:00
Andrew Nicols 01ac2dfe67 MDL-61223 course: Set default course start date 2018-04-02 12:04:21 +02:00
Eloy Lafuente (stronk7) 8dd32ca48b Merge branch 'MDL-61801-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-04-02 11:04:28 +02:00
Andrew Nicols 1b0e5bbcd3 MDL-61817 tinymce: Add privacy implementation for all plugins
None of the TinyMCE plugins have any user preference or database table.
They all implement the null provider.
2018-04-02 13:51:20 +08:00
Andrew Nicols c1034f8595 MDL-61818 antivirus: Implement core_privacy API 2018-04-02 13:46:42 +08:00
Michael Brown 06a28cd3e7 MDL-60115 mod_book: Book Resource Cancel Button Redirect Bug
When the user creates a book but adds no chapters, hitting cancel on
 the chapter creation page would redirect you right back to the same
 page with no explanation. This solution redirects to the course page
 when canceling chapter creation when no chapters are present.
2018-04-02 04:12:59 +00:00
Andrew Nicols c7640874bf MDL-61751 core_privacy: Correct test return 2018-04-01 13:36:57 +08:00
Jake Dallimore 458c700143 MDL-61751 core_plagiarism: add polyfill for plagiarism provider 2018-04-01 13:36:57 +08:00
AMOS bot 6a4148c734 Automatically generated installer lang files 2018-03-31 00:07:25 +00:00
Andrew Nicols e9dbec72f8 MDL-61801 core_privacy: Correct bug in unit test provider 2018-03-29 22:45:43 +08:00
Luca Bösch b555c2aee0 MDL-61781 installation: docs link should have https. 2018-03-29 12:12:39 +02:00
Andrew Nicols 147174ffbb MDL-61703 privacy: Allow writing of user preferences at any context 2018-03-29 15:29:45 +08:00
Jun Pataleta 6a643e96d6 weekly release 3.3.5+ 2018-03-29 12:55:55 +08:00
Jun Pataleta 0742adc1f8 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-03-29 12:55:54 +08:00
Marina Glancy 33e486cad6 MDL-61163 mod_wiki: guests should be able to view frontpage modules
When wiki is added to the frontpage and the guest role has capability to view
wiki, users should not be required to log in.
2018-03-29 11:12:41 +08:00
Marina Glancy 2c89620ad0 MDL-61163 mod_wiki: add default view capability to frontpage
It is inconsistent that guests are allowed to view frontpage wiki but once user is logged in they
loose this capability
2018-03-29 11:12:41 +08:00
Marina Glancy 96e983e488 MDL-61163 mod_wiki: correct capability check in modinfo
Wiki defines capability mod/wiki:viewpage instead of standard mod/wiki:view . This means that people
who do not have capability to view wiki still see it in the modules list.

Also corrected unittest that was testing situation when student has capability to create pages
but does not have capability to view pages. Such student should not see wiki module at all.
2018-03-29 11:12:40 +08:00
Jake Dallimore c2abd2c0f0 Merge branch 'MDL-61770-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-28 13:35:55 +08:00
Andrew Nicols 8256acd42e MDL-61770 iplookup: Check types rather than values 2018-03-28 10:58:49 +08:00
Shamim Rezaie 4b057b9d1a MDL-61020 media_videojs: Fix RTL display issues 2018-03-28 13:38:14 +11:00
Eloy Lafuente (stronk7) 085f325851 Merge branch 'MDL-39060-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-03-27 13:45:53 +02:00
Ankit Agarwal 4d26291ddc MDL-51362 libraries: Remove deprecated admin tool unittest 2018-03-27 13:39:38 +02:00
Eloy Lafuente (stronk7) 6dcb3a1692 Merge branch 'MDL-61321-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2018-03-27 12:45:20 +02:00
Jun Pataleta b2970055de Merge branch 'MDL-60762-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-03-27 15:47:07 +08:00
Adam Pawełczak 0ac58fc0d7 MDL-60762 tool_usertours: Respect $CFG->admin in manager.php 2018-03-27 15:23:07 +08:00
Jun Pataleta 558fc27a1d Merge branch 'wip-MDL-61328-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-03-27 13:50:01 +08:00
Jun Pataleta 7c6310c1c0 Merge branch 'MDL-61257-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-03-27 12:52:56 +08:00
dinhloc 5d70a00dd8 MDL-61033 quiz: Editing a quiz while a preview is open
Editing a quiz while a preview is open in another browser tab can leads to a cryptic error that is hard to recover from
2018-03-27 11:32:44 +07:00
Jun Pataleta e78265a235 Merge branch 'MDL-61656_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-03-27 12:11:22 +08:00
Eloy Lafuente (stronk7) 99c4c947fe Merge branch 'MDL-61248_m33' of https://github.com/ak4t0sh/moodle into MOODLE_33_STABLE 2018-03-27 01:43:11 +02:00
Eloy Lafuente (stronk7) 57f1a4adc7 Merge branch 'MDL-61576-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-03-26 23:26:30 +02:00
Eloy Lafuente (stronk7) 7c08cacca7 Merge branch 'MDL-61691-33' of https://github.com/snake/moodle into MOODLE_33_STABLE 2018-03-26 23:15:28 +02:00
Matteo Scaramuccia 23c1612fe1 MDL-59596 ddl: Support MariaDB 10.2.4+ SQL_MODE new default value. 2018-03-26 23:08:23 +02:00
Matteo Scaramuccia 7da1a29e3b MDL-59596 ddl: Added has_breaking_change_sqlmode() 2018-03-26 23:08:23 +02:00
Andrew Nicols 69b780e97a Merge branch 'MDL-55532-33' of git://github.com/lameze/moodle into MOODLE_33_STABLE 2018-03-26 15:36:27 +08:00
Andrew Nicols 9f271d765d Merge branch 'MDL-61733-33' of https://github.com/MartinGauk/moodle into MOODLE_33_STABLE 2018-03-26 15:02:41 +08:00
Jake Dallimore 8f8d4649b6 MDL-61691 core_plagiarism: fix namespace in privacy provider interface 2018-03-26 12:30:45 +08:00
Mihail Geshoski 543afc2850 MDL-61257 reports: Report logs link to unavailable completion report 2018-03-26 12:25:29 +08:00
Nick Phillips be17ced747 MDL-55532 gradebook: fix grade export to include category names 2018-03-26 11:50:13 +08:00
Mihail Geshoski 783eecec41 MDL-61724 resource: Unable to view or download file resource 2018-03-26 11:21:40 +08:00
Marina Glancy 71092f49c9 MDL-61328 tool_usertours: do not fix tour sortorder after step editing
otherwise it breaks when we try to modify the step sortorder
2018-03-26 09:52:59 +08:00
Zig Tan 1892dd565f MDL-39060 backup: fix typo backup destroy() function 2018-03-26 09:28:59 +08:00
AMOS bot a269833f80 Automatically generated installer lang files 2018-03-25 00:06:35 +00:00
David Mudrák 49f57eb19d MDL-61741 enrol_paypal: Prevent some edge-case false errors
While testing the plugin in various scenarios, I've noticed that there
are two situations which the current code does not handle quite well:

* Detecting for existing txn_id record was likely to throw "found more
  than one record" debugging message. Fixed by explicitly ignoring
  multiple records.
* The incoming IPN verification message does not always contain the
  recipient's email in the "business" field. When a payment has to be
  claimed manually at PayPal (e.g. as a result of currencies mismatch
  and other settings), the email is coming only in the "receiver_email"
  field. This led to PHP notice and caused the script to fail falsely.
2018-03-23 19:51:43 +01:00
David Mudrák 6f420dc5d0 MDL-61741 enrol_paypal: Fix the IPN verification endpoint URL
IPN protocol spec has different URL for sending the verification
request. Better to have it fixed even if the existing value still
seems to work - to avoid unexpected surprise in the future.

Source: https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNImplementation/#specs
2018-03-23 19:45:27 +01:00
Arnaud Trouvé a27e44f244 MDL-61248 admin: fix incorrectly initialized property 2018-03-23 16:23:21 +01:00
Martin Gauk 577410806c MDL-61733 atto_table: fix creating new table
If Atto is embedded in an HTML table (e.g. in the database activity
on the template pages), you could not create a new table.
2018-03-23 09:48:05 +00:00
Eloy Lafuente (stronk7) c6846832d5 weekly release 3.3.5+ 2018-03-22 16:57:11 +01:00
Eloy Lafuente (stronk7) 5bfbe050ee Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-03-22 16:57:09 +01:00
Jake Dallimore 9237d70fc8 Merge branch 'MDL-58179-33-fix' of https://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-22 12:06:50 +08:00
Andrew Nicols ff565b1f9c MDL-58179 mod_lesson: Add missing : in labels 2018-03-22 12:02:21 +08:00
Andrew Nicols f9bd55fae3 Merge branch 'MDL-61530-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-22 11:49:55 +08:00
Renaat Debleu a6b5e1366e MDL-61530 mod_glossary: import_entries.feature needs @_file_upload tag 2018-03-22 11:45:28 +08:00
Jun Pataleta f4733abf2a Merge branch 'MDL-52989-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-03-22 11:29:34 +08:00
Jun Pataleta 862439c883 MDL-52989 mod_lesson: Fix typo in feature description 2018-03-22 11:28:53 +08:00
Luca Bösch e9786dc883 MDL-52989 mod_lesson: Fix cluster_jump returning a cluster page id. 2018-03-22 11:28:52 +08:00
Eloy Lafuente (stronk7) 7c9b564f3f Merge branch 'MDL-61658-33-allcountrycodes' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-03-21 19:38:13 +01:00
David Mudrák 041072f63c MDL-61658 user: Fix displaying of user's country name
In these cases we want to use the method get_list_of_countries() to
obtain translated names of all potential country codes. The country code
is already there in the database. So it does not matter if the country
is among those whitelisted in $CFG->allcountrycodes - we want to see its
name anyway.
2018-03-21 18:07:13 +01:00
David Mudrák bc4e9f628c MDL-61658 user: Fix parsing of the agedigitalconsentmap setting
When parsing and validating the value of the Digital age of consent
(agedigitalconsentmap) field, we want to load all country codes. Not
just the ones whitelisted for drop down menus that users can choose
from.
2018-03-21 18:07:13 +01:00
AMOS bot 85b56ae4f7 Automatically generated installer lang files 2018-03-21 00:06:23 +00:00
Juan Leyva 48dfcbe27b MDL-61321 mod_feedback: Return all the items responses
The WS should receive all the item responses for all the attempts.
2018-03-20 10:37:41 +01:00
Luca Bösch 2f0b720d6c MDL-58179 lesson: Avoid using span with class "label" 2018-03-20 13:48:41 +08:00
Andrew Nicols 26a4ad65dc MDL-61597 calendartype: Implement the privacy API 2018-03-20 02:27:32 +01:00
Andrew Nicols 8269544f2f MDL-61689 phpunit: Be stricter about output during unit tests
This change also add fail-on-risky to travis to help pick these up, and
verbosity too.

We only fail on risky during Travis and not during normal output because
developers may want to debug tests.
2018-03-20 08:33:13 +08:00
AMOS bot 775b6d0d50 Automatically generated installer lang files 2018-03-20 00:06:22 +00:00
AMOS bot 25627e446f Automatically generated installer lang files 2018-03-20 00:06:22 +00:00
Andrew Nicols eb82d420f0 Merge branch 'MDL-61265-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-03-19 10:52:10 +08:00
Andrew Nicols bc360e9441 Merge branch 'MDL-58179-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-03-19 10:32:29 +08:00
Eloy Lafuente (stronk7) e786a591d5 Moodle release 3.3.5 2018-03-17 01:18:30 +01:00
Eloy Lafuente (stronk7) d9321f3342 Merge branch 'MDL-61672-33-abstractstaticmethod' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-03-16 23:26:10 +01:00
David Mudrák b2865ca1e4 MDL-61672 admin: Fix sitepolicy handler API
The base class had abstract static methods which raises strict standards
warning on PHP 5.6.
2018-03-16 17:22:45 +01:00
cescobedo c1ae0d9bc4 MDL-61451 message_area: core/auto_rows remove set height to 1px 2018-03-16 13:02:24 +01:00
Sara Arjona 7dc3c9b24e MDL-61265 enrol: Add default numsections for external db 2018-03-16 11:33:33 +01:00
cescobedo 170abe6a2b MDL-61576 mod_lti: remove allowinstructorcustom in lib/locallib.php 2018-03-16 10:41:35 +01:00
Luca Bösch a1e64b07b5 MDL-58179 lesson: Avoid using span with class "label" 2018-03-16 08:47:18 +01:00
Jake Dallimore 9973df93f4 weekly release 3.3.4+ 2018-03-16 10:08:50 +08:00
Eloy Lafuente (stronk7) a68417183c MDL-61656 report_security: fix role name 2018-03-16 02:26:24 +01:00
Eloy Lafuente (stronk7) 9e21adb5f7 Merge branch 'MDL-61570-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-16 01:15:35 +01:00
Andrew Nicols 65c23f097c MDL-61570 tool_usertours: Implement Privacy API 2018-03-16 08:13:04 +08:00
Eloy Lafuente (stronk7) 92be49df49 MDL-61566 theme: PHP 5.6 compatibility 2018-03-16 00:48:58 +01:00
Eloy Lafuente (stronk7) 7eab2af613 Merge branch 'MDL-61566-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-16 00:30:08 +01:00
Eloy Lafuente (stronk7) 5fb193152e Merge branch 'MDL-61571-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-15 23:51:09 +01:00
Jake Dallimore 44080d810b Merge branch 'wip-MDL-61477-33-behat' of https://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-03-15 16:44:57 +08:00
Marina Glancy c525fe3095 MDL-61477 auth_email: behat tests for sign up 2018-03-15 16:22:13 +08:00
Jake Dallimore 86fe3ca41b Merge branch 'wip-MDL-61477-33-manager' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-03-15 11:41:12 +08:00
Marina Glancy 20884e18e5 MDL-61477 admin: sitepolicy handler API
- Define sitepolicy handler manager class, base class and the core handler
- Allow to set a plugin as sitepolicyhandler that implements the sitepolicy API
- Modify web services to return information from the 3rd party handler instead of core if needed
2018-03-15 11:31:30 +08:00
David Mudrák b0b49c938b MDL-61477 admin: Allow plugins to act as alternate policy handlers
The patch introduces a new site setting 'sitepolicyhandler' that can be
either empty or contain a plugin component name. If it is empty, the
site policy feature keeps working as before and the core keeps the
control over it.

If a plugin is specified, it is expected to implement the callback
'site_policy_handler' in its lib.php file. The callback should return a
URL to a script where the user can accept the site policies. The plugin
itself is responsible for setting the 'policyagreed' flag in the users
table. The callback may return an empty value, in which case the user
can continue using the site without being redirected.

The patch adds support for a new pre-config flag NO_SITEPOLICY_CHECK.
This constant should be defined and set to true if we should not check
the user's policyagreed status during the require_login().

This is for pages where the user actually accepts the site policies and
helps to avoid the redirect loop.
2018-03-15 09:30:05 +08:00
Eloy Lafuente (stronk7) 2e6acd5f60 Merge branch 'MDL-61600-33' of git://github.com/dpalou/moodle into MOODLE_33_STABLE 2018-03-14 14:43:47 +01:00
Eloy Lafuente (stronk7) b0e4353ddd Merge branch 'MDL-61620_33' of git://github.com/dmonllao/moodle into MOODLE_33_STABLE 2018-03-14 13:38:59 +01:00
David Monllao 16edec0104 MDL-61620 output: New action_menu options 2018-03-14 11:38:32 +01:00
Eloy Lafuente (stronk7) 07c9c193b3 Merge branch 'MDL-61398-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-14 11:22:33 +01:00
Eloy Lafuente (stronk7) 0817548194 Merge branch 'MDL-61475-33-v3' of git://github.com/snake/moodle into MOODLE_33_STABLE 2018-03-14 11:01:18 +01:00
Dani Palou 3585740ced MDL-61600 recaptcha: Create a script to display recaptcha 2018-03-14 10:35:35 +01:00
Andrew Nicols 1cf00cde92 Merge branch 'MDL-60398-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-03-14 10:34:09 +08:00
Jake Dallimore 4ee7ad2377 Merge branch 'MDL-61307-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-14 09:46:06 +08:00
Jake Dallimore 9cdf3e4316 MDL-61475 mod_choice: perf improvement when exporting personal data
Instead of creating an array containing all record information and then
writing, we know write periodically during the recordset iteration, thus
alleviating any memory concerns associated with the array approach.
2018-03-14 09:37:57 +08:00
Jake Dallimore 60bf7bf6c2 MDL-61475 mod_choice: Update core_privacy implementation 2018-03-14 09:37:57 +08:00
Jun Pataleta d378b3a50e MDL-61475 mod_choice: Add implementation of Privacy API 2018-03-14 09:37:57 +08:00
Andrew Nicols 82c9aa61a8 MDL-61398 block_html: Implement privacy API 2018-03-14 09:33:16 +08:00
Andrew Nicols cb8197f594 MDL-61307 core_privacy: Add unit test to check installed providers 2018-03-14 09:32:32 +08:00
David Mudrák 9873a175a5 MDL-61392 enrol_paypal: Improve IPN input parameters checking 2018-03-14 09:12:09 +08:00
David Mudrák 89033d2d07 MDL-61392 enrol_paypal: Improve the IPN notifications handling
* Notify administrators once incoming IPN request is verified by PayPal.
* Fix the HTTP status as expected by the IPN protocol.
2018-03-14 09:12:09 +08:00
Eloy Lafuente (stronk7) 110e818da7 Merge branch 'MDL-61625_33' of git://github.com/dmonllao/moodle into MOODLE_33_STABLE 2018-03-14 00:59:29 +01:00
David Mudrák 5d06da4e41 MDL-60101 auth_oauth2: Don't allow suspended users to SSO in via OAuth2
Without this patch, users could still log in as a suspended account via
OAuth2 SSO feature.
2018-03-13 10:13:00 +01:00
Jake Dallimore 78ebc5d9e7 Merge branch 'm33_MDL-61626_PgSQL_Table_Name_Could_Be_Schema_Qualified' of https://github.com/scara/moodle into MOODLE_33_STABLE 2018-03-13 15:38:15 +08:00
Andrew Nicols d8952802e7 Merge branch 'MDL-59070-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-03-13 13:55:25 +08:00
Andrew Nicols 7a49ac3d79 Merge branch 'MDL-61397-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-03-13 12:59:47 +08:00
Andrew Nicols 1983c83957 Merge branch 'MDL-61567-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-03-13 12:21:36 +08:00
Eloy Lafuente (stronk7) 1b1b6313c0 Merge branch 'MDL-61307-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-13 03:27:53 +01:00
Zig Tan d2bc47577b MDL-61397 blocks: Fix null_provider namespace for blocks
Also added null provider for block_messages
2018-03-13 10:07:44 +08:00
Andrew Nicols 674a9c859d MDL-61307 core: Language changes 2018-03-13 09:42:23 +08:00
Andrew Nicols 56335cc001 MDL-61307 privacy: Rename deletion functions 2018-03-13 08:52:26 +08:00
Andrew Nicols 2e86cca9ca MDL-61307 core: Remove deletion_criteria 2018-03-13 08:50:27 +08:00
Eloy Lafuente (stronk7) 0913f3314f Merge branch 'MDL-48501-mdl33' of git://github.com/jswebster/moodle into MOODLE_33_STABLE 2018-03-12 23:51:06 +01:00
Matteo Scaramuccia cf7979c622 MDL-61626 core_dml: pgsql and schema qualification. 2018-03-12 22:52:37 +01:00
Eloy Lafuente (stronk7) cda6d082de Merge branch 'wip-MDL-60241-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-03-12 18:29:00 +01:00
Eloy Lafuente (stronk7) eb12fec156 Merge branch 'MDL-61397-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-12 17:31:35 +01:00
Eloy Lafuente (stronk7) d2c04300f3 Merge branch 'MDL-61622-33' of git://github.com/jleyva/moodle into MOODLE_33_STABLE 2018-03-12 11:37:16 +01:00
David Monllao ceb21de5e3 MDL-61625 persistent form: Add missing param to the constructor 2018-03-12 08:10:40 +01:00
Andrew Nicols 6aef716ec4 MDL-61566 theme: Add Privacy providers for all core themes 2018-03-12 13:28:08 +08:00
Andrew Nicols fc16e61230 MDL-61571 atto: Implement null provider for atto plugins 2018-03-12 13:22:58 +08:00
Andrew Nicols 0534fbc2aa Merge branch 'MDL-61513-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-03-12 12:26:48 +08:00
Andrew Nicols 5b9f872429 Merge branch 'MDL-61498-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-03-12 12:08:07 +08:00
Andrew Nicols dd67898152 Merge branch 'MDL-61261-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-03-12 11:52:31 +08:00
Zig Tan 2377dbd9d8 MDL-61567 mod_url: Implement null provider mod_url 2018-03-12 11:24:21 +08:00
Zig Tan 3810c3ad36 MDL-61567 mod_resource: Implement null provider mod_resource 2018-03-12 11:23:56 +08:00
Zig Tan ef9c44ad7e MDL-61567 mod_page: Implement null provider mod_page 2018-03-12 11:23:26 +08:00
Zig Tan 3eac779614 MDL-61567 mod_label: Implement null provider mod_label 2018-03-12 11:20:33 +08:00
Zig Tan 5223ceed6b MDL-61567 mod_folder: Implement null provider mod_folder 2018-03-12 11:19:57 +08:00
Zig Tan f27cf98517 MDL-61397 blocks: Add null_providers for blocks with no user data 2018-03-12 08:46:33 +08:00
Juan Leyva 7fe0a3b051 MDL-61622 auth: New WS is_age_digital_consent_verification_enabled 2018-03-09 18:13:59 +01:00
Jake Dallimore f03765aae7 Merge branch 'MDL-61307-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-03-09 13:37:40 +08:00
Andrew Nicols 9fa3922c77 MDL-61307 core_plagiarism: Add implementation of Privacy API 2018-03-09 12:24:39 +08:00
Andrew Nicols 4a9c1685bd MDL-61307 core_privacy: Add legacy polyfill for contrib plugins
This legacy polyfill allows plugin developers who release a single
branch to work with multiple versions of Moodle to support the API in
both Moodle 3.3 with PHP 5.6, and later versions.
2018-03-09 12:24:39 +08:00
Andrew Nicols fbb3918ebe MDL-61307 core_privacy: Implementation of itself 2018-03-09 12:24:39 +08:00
Adrian Greeve d17dc20947 MDL-61307 core_comment: Add implementation of privacy API 2018-03-09 12:24:39 +08:00
Andrew Nicols a63717d365 MDL-61307 core_rating: Add implementation of Privacy API 2018-03-09 12:24:38 +08:00
Zig Tan 0867abed26 MDL-61307 core_tag: Unit tests for privacy implementation 2018-03-09 12:24:38 +08:00
Andrew Nicols be94915636 MDL-61307 core_tag: Add implementation of privacy API 2018-03-09 12:24:38 +08:00
Jake Dallimore 5de4b14160 MDL-61307 core_privacy: Add the privacy manager 2018-03-09 12:24:38 +08:00
Marina Glancy 3e316b8713 MDL-60241 course: General section always visible (topics, weeks) 2018-03-09 12:11:31 +08:00
Andrew Nicols 267e1af112 MDL-61307 core_privacy: Define and test providers 2018-03-09 10:03:29 +08:00
Andrew Nicols 37db3b8561 MDL-61307 core: Add component_class_callback functionality 2018-03-09 10:03:29 +08:00
Andrew Nicols 5a146aa633 MDL-61307 core: Define a new privacy component 2018-03-09 10:03:28 +08:00
Jeff Webster 934220228a MDL-48501 auth/email: update external class to use reCAPTCHA v2 2018-03-08 14:22:39 -05:00
Jeff Webster 3c9a5ae1cc MDL-48501 mod_feedback: update feedback to use reCAPTCHA v2 2018-03-08 14:22:39 -05:00
Jeff Webster 8d7d722fb0 MDL-48501 login: update signup_form to use reCAPTCHA v2 2018-03-08 14:22:39 -05:00
Jeff Webster 2f0be313b3 MDL-48501 form/recaptcha: update to use reCAPTCHA v2 2018-03-08 14:22:39 -05:00
Jeff Webster 68e6299010 MDL-48501 recaptchalib_v2: add new lib to support reCAPTCHA v2 2018-03-08 14:22:39 -05:00
Jeff Webster e3a18e4458 MDL-48501 lang: update reCAPTCHA language strings 2018-03-08 14:22:39 -05:00
Luca Bösch 21d27e3f96 MDL-59070 enrol_database: Take enablecompletion from template 2018-03-08 17:22:52 +01:00
Luca Bösch a74a3f8ab8 MDL-61498 lesson: link to next activity in boost 2018-03-08 17:22:26 +01:00
Eloy Lafuente (stronk7) e95f91c90a weekly release 3.3.4+ 2018-03-08 13:29:10 +01:00
Eloy Lafuente (stronk7) 7a793db488 NOBUG: Fixed SVG browser compatibility 2018-03-08 13:29:09 +01:00
Eloy Lafuente (stronk7) 645b80ea72 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-03-08 13:29:08 +01:00
Andrew Nicols 5c07c79657 Merge branch 'MDL-61423-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-03-08 15:30:36 +08:00
Mihail Geshoski 5cb155ad9d MDL-61423 authentication: Add digital minor verification upon signup 2018-03-08 15:03:05 +08:00
Eloy Lafuente (stronk7) a8b5704fb4 Merge branch 'MDL-60445-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-03-07 19:20:21 +01:00
Jesse Ritchey 707d3a3aa3 MDL-60445 theme_boost: remove fieldset tag 2018-03-07 11:09:04 +01:00
Andrew Nicols 9f11f13ad8 Merge branch 'WIP-MDL-60658-33' of https://github.com/chkhanu/moodle into MOODLE_33_STABLE 2018-03-07 11:37:45 +08:00
Andrew Nicols b091c290bb Merge branch 'wip-MDL-61322-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-03-07 10:58:24 +08:00
Andrew Nicols c101a623d8 Merge branch 'MDL-61497-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-03-07 10:28:49 +08:00
AMOS bot 5815d6f01c Automatically generated installer lang files 2018-03-07 00:06:38 +00:00
Eloy Lafuente (stronk7) 2e17137c8b Merge branch 'MDL-36157-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-03-06 02:52:41 +01:00
Luca Bösch 28b6ae97e9 MDL-36157 block_rss_client: Don't double escape titles. 2018-03-06 00:20:33 +01:00
Luca Bösch d527a497ea MDL-36157 block_rss_client: Don't double escape titles. 2018-03-06 00:20:32 +01:00
Eloy Lafuente (stronk7) 64488fd069 Merge branch 'MDL-61211-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-03-05 23:33:44 +01:00
Eloy Lafuente (stronk7) 76148061d7 Merge branch 'MDL-55153-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-03-05 23:26:12 +01:00
Andrew Nicols 9214166d89 MDL-61268 core: Fix empty string DB cehck
(amended by stronk7 to use the helper better)
2018-03-02 16:32:36 +01:00
Andrew Nicols 253fcd9ce2 Merge branch 'wip-MDL-61268-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-03-02 10:03:58 +08:00
Adrian Greeve 218cbbed31 MDL-61268 blocks: Unit tests for deprecated object update.
Unit tests for testing that the upgrade functions to change
the now deprecated object to stdClass works.
2018-03-02 09:39:16 +08:00
Adrian Greeve b3dfb6eafa MDL-61268 blocks: Fix corrupt configdata in block instances.
Old configuration data in the block instances is base64 encoded with
the deprecated object class instead of stdClass.
2018-03-02 09:38:59 +08:00
Andrew Nicols 8fda9b0267 Merge branch 'MDL-61196_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-03-02 09:35:03 +08:00
Eloy Lafuente (stronk7) 5fafbd8a3c Merge branch 'MDL-61533-33-enfix' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-03-02 01:43:12 +01:00
Helen Foster 9a550cac49 MDL-61533 lang: Merge English strings from the en_fix language pack
Significant string change:

* typeoflogin_desc,tool_mobile - removing sentence about autologinguests
2018-03-01 15:35:05 +01:00
Luca Bösch ffd593db80 MDL-61497 repository_onedrive: Use post 2015 icon 2018-03-01 08:57:29 +01:00
Chernyavskiy Leonid 14618260c8 MDL-60658 course, gradebook: fix missing unformat_float for gradepass
Fix incorrect comparison of gradepass variable (with comma as decimal separator)
with grade variable when trying to save assignment settings.
Adds missing unformat_float($data['gradepass']).
2018-03-01 09:27:08 +07:00
Mihail Geshoski 7f1fcbda75 MDL-61211 lesson: Error when answer or response contains break tag 2018-03-01 09:52:22 +08:00
Andrew Nicols 5fc058c0b0 Merge branch 'MDL-61453-33-userpicturefiletype' of git://github.com/mudrd8mz/moodle into MOODLE_33_STABLE 2018-03-01 08:46:44 +08:00
Eloy Lafuente (stronk7) 2faddcdef5 weekly release 3.3.4+ 2018-02-28 12:58:18 +01:00
Jake Dallimore a49458943c Merge branch 'wip-MDL-61485-33' of git://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-02-27 09:40:40 +08:00
Jake Dallimore aaf815541b Merge branch 'MDL-61480-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-02-27 09:05:42 +08:00
David Mudrák eb618c1c71 MDL-61453 user: Fix accepted file type when uploading user pictures
Not all archives are supported, only ZIP files are.
2018-02-26 14:32:55 +01:00
Mihail Geshoski 4948a43536 MDL-60398 resource: Unable to download folder resource 2018-02-26 16:54:23 +08:00
Andrew Nicols b4a4b7ce70 Merge branch 'wip-MDL-61455-33' of https://github.com/marinaglancy/moodle into MOODLE_33_STABLE 2018-02-26 14:12:04 +08:00
Andrew Nicols 4f21e3a33f MDL-61480 core: Check plugin installed before returning 2018-02-26 12:12:08 +08:00
Andrew Nicols d6e63cb602 Merge branch 'MDL-60547-33' of git://github.com/cescobedo/moodle into MOODLE_33_STABLE 2018-02-26 10:27:56 +08:00
Andrew Nicols 504e36da8e Merge branch 'MDL-61462-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-26 10:19:00 +08:00
Jake Dallimore 9c796e028d weekly release 3.3.4+ 2018-02-23 11:51:32 +08:00
Jake Dallimore 3a7f56c779 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-02-23 11:51:31 +08:00
Marina Glancy c982d78c20 MDL-61522 mod_glossary: use full url in links 2018-02-23 10:56:22 +08:00
Carlos c4f22db315 MDL-60547 message_popup: adding preventDefault at notification popover 2018-02-22 10:53:51 +01:00
Jun Pataleta f926f376f8 MDL-61513 admin: Fix undefined $buttons variable 2018-02-22 10:22:38 +08:00
Eloy Lafuente (stronk7) 6972f8403f Merge branch 'MDL-61324_lti_sync_33' of git://github.com/davosmith/moodle into MOODLE_33_STABLE 2018-02-22 08:31:59 +08:00
Dan Marsden 457fcfe3d0 MDL-61005 core_cohort: Allow teachers to view site-wide cohorts 2018-02-22 08:31:59 +08:00
Luca Bösch bf085b7fc5 MDL-58845 mod_choice: Fix behat related tests 2018-02-22 08:31:58 +08:00
Andrew Nicols 2eb83b7678 Merge branch 'MDL-61421-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-02-22 08:31:57 +08:00
Andrew Nicols a3e647dc98 Merge branch 'MDL-61408-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-02-22 08:31:57 +08:00
Sara Arjona a5bac67326 MDL-55153 customlang: Remove local DB entries when deleting local file 2018-02-21 21:04:57 +01:00
Damyon Wiese 3117287072 MDL-61455 autocomplete: Return promise
Partial backport of MDL-59368
2018-02-21 09:40:07 +08:00
Mihail Geshoski f6121c0bd6 MDL-61485 authentication: Add callback 'pre_signup_requests' 2018-02-20 10:00:02 +08:00
Eloy Lafuente (stronk7) fd1ef60779 Merge branch 'MDL-58845-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-02-19 02:13:07 +01:00
Andrew Nicols ff1f239381 Merge branch 'MDL-61289-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-19 09:08:00 +08:00
Jun Pataleta 6c855610bf MDL-61289 mod_choice: Add extra user fields to response data 2018-02-19 08:54:39 +08:00
AMOS bot 8b1eb7742e Automatically generated installer lang files 2018-02-19 00:06:34 +00:00
AMOS bot 08e1bbd86b Automatically generated installer lang files 2018-02-17 00:06:37 +00:00
Luca Bösch b899bab0bc MDL-61408 qbehaviour: Correct "Check" button styling. 2018-02-16 08:43:45 +01:00
Luca Bösch 48352701a1 MDL-58845 mod_choice: In reports, respect "Show column for unanswered" 2018-02-16 08:43:42 +01:00
Jun Pataleta f23541f3fb MDL-61462 admin_roles: Point back to roles link to the correct URL 2018-02-16 10:33:25 +08:00
Damyon Wiese ab83a52583 MDL-61455 boost: Don't allow z-index on pagination MDL-59809
This causes parts of the pagination bar to show through overlays and modals.
2018-02-16 10:08:12 +08:00
Marina Glancy 7f3c09ae49 MDL-56635 tags: use recordset since component may not be unique 2018-02-16 09:51:21 +08:00
Eloy Lafuente (stronk7) 2e8f163f64 weekly release 3.3.4+ 2018-02-15 17:10:27 +01:00
Andrew Nicols 41275ea779 Merge branch 'wip-33-MDL-61344' of https://github.com/ndunand/moodle into MOODLE_33_STABLE 2018-02-13 09:04:45 +08:00
Andrew Nicols e129c4733b Merge branch 'MDL-61150_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-02-13 09:02:53 +08:00
David Monllao 8904b10b44 Merge branch 'MDL-61236-33' of git://github.com/farhan6318/moodle into MOODLE_33_STABLE 2018-02-12 12:14:28 +01:00
Nicolas Dunand 5e092e2540 MDL-61344 mod_assign: Show additional files when adding submission 2018-02-12 11:13:55 +01:00
David Monllao 235d4be426 Merge branch 'MDL-61153-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-02-12 10:56:14 +01:00
David Monllao 0ce2cf80ee Merge branch 'MDL-61375_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-02-12 09:41:04 +01:00
Nick Phillips 7d5efd643c MDL-56688 grade: fix ordering of grade items in grade_seq::flatten 2018-02-12 09:35:16 +01:00
Davo Smith 8566cace36 MDL-61324 enrol_lti: fix detection of changed grades during sync 2018-02-12 08:26:59 +00:00
David Monllao f71d4d4a97 Merge branch 'mod-lti-fix-test-with-hardcoded-url-mdl33' of https://github.com/peikk0/moodle into MOODLE_33_STABLE 2018-02-12 09:21:04 +01:00
David Monllao ccd495d806 Merge branch 'MDL-61425-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-02-12 09:13:20 +01:00
Sara Arjona 5613a37ab2 MDL-61421 cohort: Fix cohort_role_sync when a user is in two cohorts 2018-02-12 09:10:14 +01:00
Andrew Nicols 8e2eb1f335 Merge branch 'MDL-61366_33' of git://github.com/timhunt/moodle into MOODLE_33_STABLE 2018-02-12 15:26:39 +08:00
Shamim Rezaie 89660817f7 MDL-61425 theme_boost: Made question labels width full in question bank 2018-02-12 14:54:32 +11:00
Andrew Nicols ea61136232 Merge branch 'MDL-61305-33-fix' of https://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-02-12 11:32:10 +08:00
Andrew Nicols 9a36044425 MDL-61305 modinfo: Add back missing require for course 2018-02-12 10:40:17 +08:00
Andrew Nicols 6dc3fc7508 Merge branch 'MDL-61305-m33' of https://github.com/sammarshallou/moodle into MOODLE_33_STABLE 2018-02-12 09:09:08 +08:00
Pierre Guinoiseau 8ba2f949d0 MDL-61379 mod_lti: fix a test comparing a hardcoded URL from fixtures
The hardcoded URL from tests/fixtures/ims_cartridge_basic_lti_link.xml
didn't match if TEST_EXTERNAL_FILES_HTTPS_URL was defined, the test
needs to compare with the exact same URL instead of a generated one.
2018-02-12 13:46:48 +13:00
Andrew Nicols e53bde7de2 Merge branch 'MDL-61413_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-02-12 08:09:09 +08:00
Marina Glancy aee5a8666a MDL-61150 xmldb: correct path to schema in install.xml 2018-02-11 23:09:03 +01:00
Eloy Lafuente (stronk7) a163049a64 MDL-61150 xmldb: Fix wrong PATH attributes in core 2018-02-11 23:09:03 +01:00
Farhan Karmali 055010a34a MDL-61236 enrol: Course welcome message to be sent from correct contact 2018-02-11 20:49:31 +05:30
Eloy Lafuente (stronk7) abe4724b32 MDL-61413 mod_lti: Use sql_compare_text() for comparing TEXTs 2018-02-11 02:18:58 +01:00
Mark Nelson 163a9d21e5 MDL-61196 message_popup: clean params before returning via WS 2018-02-09 17:37:04 +08:00
Mark Nelson 234d16cfcb MDL-61375 mod_chat: specify the 'eventtype' to avoid duplicate rows 2018-02-09 14:47:17 +08:00
sam marshall e598dc49a7 MDL-61305 Performance: Modinfo cache can get built in parallel
In a busy site it is possible that one user will access the site
while another is building modinfo cache. This can result in the
cache being built several times at once, potentially causing a
performance issue.
2018-02-08 14:50:48 +00:00
David Monllao 1702e66574 weekly release 3.3.4+ 2018-02-08 09:29:12 +01:00
Andrew Nicols 9d8c7eaaa8 Merge branch 'MDL-61377-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-02-07 12:53:02 +08:00
Shamim Rezaie a77941b809 MDL-61377 Core: Fixed faulty warning when using progress_bar 2018-02-07 14:48:39 +11:00
Eloy Lafuente (stronk7) 7fe0d459d6 MDL-52832 quiz: sql fixing couple of incorrect group by uses 2018-02-07 07:09:37 +08:00
Tim Hunt bfe824dd3d MDL-61366 setuplib: safely construct the ajax renderer when needed 2018-02-06 12:12:58 +00:00
David Monllao ad0f68802a Merge branch 'MDL-52832-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-02-06 12:20:19 +01:00
Dan Marsden e3db31ac67 MDL-60421 tool_cohortroles: fix deprecated call. 2018-02-06 10:51:52 +01:00
Eloy Lafuente (stronk7) 00ab44ee52 Merge branch 'MDL-61168-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-05 20:40:36 +01:00
Eloy Lafuente (stronk7) bb89fdcf22 Merge branch 'MDL-61341-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-02-05 20:08:30 +01:00
David Monllao b813a2778b Merge branch 'MDL-61027-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-02-05 11:56:36 +01:00
David Monllao 7e9362481d Merge branch 'MDL-61251-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-02-05 11:50:54 +01:00
David Monllao 407a8d675e Merge branch 'MDL-42764_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-02-05 11:18:54 +01:00
Andrew Nicols 38055cdb22 Merge branch 'MDL-61269_33' of git://github.com/stronk7/moodle into MOODLE_33_STABLE 2018-02-05 17:53:30 +08:00
Andrew Nicols b3c71b12c7 Merge branch 'MDL-51189-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-02-05 15:58:30 +08:00
Eloy Lafuente (stronk7) 5ac4c7f2ba MDL-61269 composer: better license GPL-3.0-or-later
Source: https://spdx.org/licenses/
2018-02-04 19:40:33 +01:00
Sara Arjona 0c8d6093dc MDL-61261 badges: Add email validation during backpack configuration 2018-02-02 11:35:36 +01:00
Andrew Nicols 0ab8ddc56b MDL-61341 theme_boost: Fix usertour zindex calculations 2018-02-02 11:36:46 +08:00
Jun Pataleta 2cda43b3bd MDL-61168 mod_assign: Truncate only the online text submission 2018-02-02 09:21:41 +08:00
Luca Bösch efc06d64e7 MDL-52832 quiz: timeclose in activities block looks after overrides. 2018-02-02 00:00:04 +01:00
Luca Bösch a71eb555c2 MDL-61251 admin: configenablerssfeedsdisabled2 string more correct. 2018-02-01 22:57:20 +01:00
David Monllao 7517f9ea50 weekly release 3.3.4+ 2018-02-01 14:26:40 +01:00
David Monllao 73f8281a01 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-02-01 14:26:39 +01:00
Jake Dallimore 158586680d Merge branch 'MDL-60077-33-fix' of https://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-02-01 14:56:28 +08:00
Andrew Nicols c81ead0adb MDL-60077 tool_usertours: Pull v0.12.2 of usertours for triangle fix 2018-02-01 14:29:06 +08:00
David Mudrák 1ac64fbe83 MDL-61242 repository_equella: Fix missing class repository
The call to the class 'repository' introduced in the commit d05c2ac7cc
didn't fully work and threw: "Exception - Class 'repository' not found".
This fixes the missing library inclusion.
2018-02-01 10:34:39 +08:00
Eloy Lafuente (stronk7) 3111b937ef Merge branch 'MDL-61058-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-01 10:34:38 +08:00
Eloy Lafuente (stronk7) 58c586c3c4 Merge branch 'MDL-61023-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-01 10:34:38 +08:00
Andrew Nicols 9b2b1b5b12 Merge branch 'MDL-61313_33' of git://github.com/dmonllao/moodle into MOODLE_33_STABLE 2018-02-01 10:34:38 +08:00
Eloy Lafuente (stronk7) e9925ef601 Merge branch 'MDL-44612-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-01 10:34:37 +08:00
David Monllao d8aba73bb4 Merge branch 'MDL-60646-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-01 10:34:37 +08:00
David Monllao 4174bcc99c Merge branch 'MDL-60997-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-02-01 10:34:37 +08:00
David Monllao f89874634c Merge branch 'MDL-61260_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-02-01 10:34:36 +08:00
Jake Dallimore 66a13f93e4 Merge branch 'MDL-61253-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-02-01 10:34:36 +08:00
Andrew Nicols 859e9b3394 Merge branch 'MDL-60077-33' of https://github.com/HuongNV13/moodle into MOODLE_33_STABLE 2018-02-01 10:34:36 +08:00
Andrew Nicols 9aae08cc38 Merge branch 'MDL-61250-33' of https://github.com/lucaboesch/moodle into MOODLE_33_STABLE 2018-02-01 10:34:36 +08:00
Adrian Greeve 5608acd0d7 MDL-61322 reports: Reformated the display date to include the year. 2018-02-01 08:30:07 +08:00
AMOS bot 0b13c999e2 Automatically generated installer lang files 2018-02-01 00:06:56 +00:00
AMOS bot fa62cb4137 Automatically generated installer lang files 2018-01-31 00:06:44 +00:00
David Monllao db75ead6fe MDL-61313 behat: Move future events further 2018-01-30 18:17:33 +01:00
AMOS bot 5ae345bdeb Automatically generated installer lang files 2018-01-30 00:06:46 +00:00
Mark Nelson ac8bf02214 MDL-42764 core: added missing string definition
Also changed the string index so it was not
vague. The index 'emailempty' appears as if it
could belong to a validation method for a form.
2018-01-29 19:08:32 +08:00
Huong Nguyen a1a04839eb MDL-60077 User tours: pop-up triangle look bad next to the corners 2018-01-29 10:34:58 +07:00
Mark Nelson d8c58a53d3 MDL-61260 auth_ldap: require /user/profile/lib.php file 2018-01-29 11:31:36 +08:00
Eloy Lafuente (stronk7) 17384a4a8e Merge branch 'wip-MDL-61242-33' of git://github.com/abgreeve/moodle into MOODLE_33_STABLE 2018-01-29 01:41:23 +01:00
Luca Bösch 0a8e683595 MDL-61250 questions: Omit leading space in question preview link 2018-01-25 14:25:53 +01:00
Jun Pataleta 63da6656b9 MDL-60997 core_message: Add replytoname in unit test 2018-01-25 16:48:13 +08:00
Arnaud Trouvé 53556cf240 MDL-60997 messages: add property replytoname 2018-01-25 16:48:12 +08:00
Andrew Nicols a11dae7625 weekly release 3.3.4+ 2018-01-25 15:14:33 +08:00
Andrew Nicols 274d3ca6d5 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-01-25 15:14:29 +08:00
Jake Dallimore 492ddb2bf8 Merge branch 'MDL-60078-33-fix' of https://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-01-25 14:49:00 +08:00
Andrew Nicols 5bb4d629fc MDL-60078 tool_usertours: Adjust accessibility checks for all themes 2018-01-25 12:50:33 +08:00
Eloy Lafuente (stronk7) 9cb82a1530 MDL-61269 behat-extension: bump to fix some caps & defaults 2018-01-25 00:32:28 +01:00
Jun Pataleta a5e434b97e MDL-44612 mod_glossary: Test importing of glossary entries
* And check that the importing of entries is reflected in the recent
activity block.
2018-01-24 16:39:24 +08:00
Jun Pataleta cf9910912f MDL-44612 mod_forum: Confirm forum post listing in recent activity block 2018-01-24 16:39:23 +08:00
Damyon Wiese b2961aa526 MDL-61058 behat: Automate MDLQA-8146
Verify that the keyholder is displayed on the self enrolment page.
2018-01-24 16:37:05 +08:00
Damyon Wiese 48a5afe796 MDL-61023 behat: Automate MDLQA-8158
Verify the general section does not appear in the navigation when it is empty.
2018-01-24 16:35:56 +08:00
Andrew Nicols 83539ba7aa MDL-61234 tool_usertours: Rewrite feature to work with all themes 2018-01-24 10:20:08 +08:00
Andrew Nicols 01484f2289 MDL-61253 repository: Add referenced files to archives 2018-01-23 11:52:13 +08:00
Shamim Rezaie a167de121b MDL-51189 Quiz: Edit overrides when quiz is not available to students
The $active variable should simply be used to dim the text, nothing more.
2018-01-23 10:53:40 +11:00
Eloy Lafuente (stronk7) f058e911cd Merge branch 'MDL-60918-33' of git://github.com/ryanwyllie/moodle into MOODLE_33_STABLE 2018-01-22 20:17:43 +01:00
Eloy Lafuente (stronk7) 06cded2b76 Merge branch 'MDL-58006-33' of git://github.com/zig-moodle/moodle into MOODLE_33_STABLE 2018-01-22 20:00:20 +01:00
Eloy Lafuente (stronk7) df5debbfc4 Merge branch 'MDL-60181-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE 2018-01-22 12:51:38 +01:00
Shamim Rezaie 1c1c751560 MDL-61027 calendar: Fix datetime profile field issue with non-Gregorian 2018-01-22 19:06:08 +11:00
Mihail Geshoski e6645efea6 MDL-60181 glossary: Glossary rating is displayed wrongly 2018-01-22 13:59:52 +08:00
Zig Tan eedd1437c8 MDL-58006 assign: Reset blindmarking assignments to hidden
Fix to reset blindmarking assigments to hidden as part of Course reset with behat test
2018-01-22 11:37:21 +08:00
Andrew Nicols b1c1aa89ed Merge branch 'MDL-60078-33' of https://github.com/nashtechdev01/moodle into MOODLE_33_STABLE 2018-01-22 11:31:15 +08:00
Eloy Lafuente (stronk7) 8ede8c859e Merge branch 'MDL-61077_33' of git://github.com/timhunt/moodle into MOODLE_33_STABLE 2018-01-22 02:26:19 +01:00
Eloy Lafuente (stronk7) e288c6314f Merge branch 'MDL-61234-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-01-22 02:04:08 +01:00
Eloy Lafuente (stronk7) 4865f138c7 Merge branch 'wip-MDL-61175-MOODLE_33_STABLE' of https://github.com/kwiliarty/moodle into MOODLE_33_STABLE 2018-01-22 01:25:04 +01:00
Eloy Lafuente (stronk7) 9db5265f18 Merge branch 'MDL-61224_33' of git://github.com/markn86/moodle into MOODLE_33_STABLE 2018-01-22 01:23:26 +01:00
Adrian Greeve 5b7ee7d6b3 MDL-61242 repository_equella: Add source key when sending the source.
A thank you to Nelson Cheng for find this issue and suggesting a patch.
2018-01-20 11:02:04 +08:00
Andrew Nicols e1a489362c MDL-61234 tool_usertours: Wrap library calls in pendingjs 2018-01-19 15:55:12 +08:00
AMOS bot 2da5023cd2 Automatically generated installer lang files 2018-01-19 00:07:12 +00:00
Kevin Wiliarty b025f80743 MDL-61175 mod_assign: roll grade-by reminder on restore 2018-01-18 08:42:02 -05:00
Jun Pataleta b65a529086 MDL-60646 user_portfolio: Fix action icons in Show / hide column
* Refactor the code to make it look cleaner and easier to read.
* Fixed incorrect alt-text for the configure icon.
* Fixed missing alt-text for show/hide icon.
2018-01-18 15:27:03 +08:00
Andrew Nicols 68673fb78d weekly release 3.3.4+ 2018-01-18 12:47:57 +08:00
Andrew Nicols 0de71f9432 Merge branch 'install_33_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_33_STABLE 2018-01-18 12:47:54 +08:00
AMOS bot 82815a491e Automatically generated installer lang files 2018-01-17 00:06:38 +00:00
Jun Pataleta 5abcd64852 Merge branch 'MDL-61221-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-01-16 23:01:29 +08:00
KietLy da908a84c3 MDL-60078 User tours accessibility: Tab should go back into the pop-up 2018-01-16 17:36:57 +07:00
Mark Nelson fde9d39538 MDL-61224 core_role: prevent short name from exceeding 100 chars 2018-01-16 18:18:04 +08:00
David Monllao 97cf15c9ad Merge branch 'MDL-61010-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-01-16 09:25:49 +01:00
Adam Olley 6837f2f698 MDL-60918 core_message: update preferences of user behat test 2018-01-16 05:27:10 +00:00
Ryan Wyllie 83b01d7505 MDL-60918 message: use current user in message preference update 2018-01-16 05:27:10 +00:00
Andrew Nicols e9c315ff85 MDL-61221 badges: Ignore site availabilty for behat
Behat sites should not be available publically, and the check against
the backpack API for site availablity can time out in some situations.

We should be testing as though the site _is_ available, as this is the
standard expectation.
2018-01-16 13:23:28 +08:00
David Knuplesch fb4da0de30 MDL-60549 lti: support for moving embedded lti into separate tab 2018-01-16 10:12:24 +08:00
Eloy Lafuente (stronk7) 3cf3e20b77 Merge branch 'MDL-61204-33' of git://github.com/andrewnicols/moodle into MOODLE_33_STABLE 2018-01-16 02:17:08 +01:00
Andrew Nicols 2d6a9a6ef3 MDL-61204 user: Fix random failure in behat
We need to get into the habit of not using usernames like 'student1'
and 'student10' as our matches are non-strict, and the tests become
dependent upon DB sort order.

This change adds a character after the varying value to act as a
delimter for all of these tests.
2018-01-16 08:16:11 +08:00
Andrew Nicols 2a208a32cb MDL-61010 mod_forum: Add unread link to blog view 2018-01-16 08:07:43 +08:00
AMOS bot ba6233ae2c Automatically generated installer lang files 2018-01-16 00:06:49 +00:00
Eloy Lafuente (stronk7) ad2ed52966 Merge branch 'MDL-61081-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-01-16 00:28:01 +01:00
Eloy Lafuente (stronk7) 84bc03313b Merge branch 'MDL-37390-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-01-16 00:25:41 +01:00
Eloy Lafuente (stronk7) 043279b4d9 Merge branch 'MDL-61162-33' of git://github.com/junpataleta/moodle into MOODLE_33_STABLE 2018-01-15 22:58:12 +01:00
Tim Hunt 4a108f79a8 MDL-61077 question stats: make calculations more robust 2018-01-15 16:08:35 +00:00
David Monllao 0c496132cf Merge branch 'MDL-60776-33' of git://github.com/sarjona/moodle into MOODLE_33_STABLE 2018-01-15 10:58:58 +01:00
Eloy Lafuente (stronk7) d251a46588 Merge branch 'MDL-61166-33' of git://github.com/rezaies/moodle into MOODLE_33_STABLE 2018-01-15 10:57:57 +01:00
David Monllao 20c6e3628c Merge branch 'MDL-55382-33' of git://github.com/damyon/moodle into MOODLE_33_STABLE 2018-01-15 10:09:56 +01:00
Shamim Rezaie 6df9abc397 MDL-61166 Groups: Fixed a typo in PHPDoc 2018-01-14 09:23:00 +11:00
Farhan Karmali c16fd22bbc MDL-37390 course: Set startdate properly for approved course
Once a course is approved the startdate is not set properly
This patch sets current midnight date as startdate and leave
enddate to 0
2018-01-12 10:03:43 +01:00
Farhan Karmali b8cf9f06dc MDL-61081 enrol: Start date for courses created by external db
Course created by external db enrolment plugin should have start date as current midnight date
2018-01-12 09:59:28 +01:00
do-you-even-curl 879c847aed MDL-60776 enrol: Fix header for custom fullnamedisplay formats
In case you used a custom fullnamedisplay format that involved anything but spaces (e.g. commas) as delimiters the username header
would be displayed incorrectly and you wouldn't be able to click on the "Firstname" or "Surname" headers to sort according to them.
2018-01-12 09:52:01 +01:00
Jun Pataleta 1b091c789c MDL-61162 mod_forum: Remove unnecessary forum creation step 2018-01-08 10:58:20 +08:00
Mihail Geshoski 15646264c4 MDL-61153 lesson: Inconsistent column sizing in detailed statistics 2018-01-04 15:49:51 +08:00
Damyon Wiese d716aa1587 MDL-55382 assign: Sort editpdf quick list 2017-12-15 14:58:00 +08:00
Ann Adamcik 287089b1a2 MDL-58697: Only get group submission if enabled 2017-12-01 12:48:44 -07:00
1753 changed files with 138163 additions and 3610 deletions
+1
View File
@@ -3,6 +3,7 @@
*/**/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/
+1
View File
@@ -4,6 +4,7 @@ theme/clean/style/custom.css
theme/more/style/custom.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/
+4 -2
View File
@@ -55,7 +55,7 @@ matrix:
include:
# Run grunt/npm install on highest version ('node' is an alias for the latest node.js version.)
- php: 7.1
env: DB=none TASK=GRUNT NVM_VERSION='8.9'
env: DB=none TASK=GRUNT NVM_VERSION='lts/carbon'
exclude:
# MySQL - it's just too slow.
@@ -249,7 +249,7 @@ script:
- >
if [ "$TASK" = 'PHPUNIT' ];
then
vendor/bin/phpunit;
vendor/bin/phpunit --fail-on-risky --disallow-test-output --verbose;
fi
- >
@@ -264,7 +264,9 @@ 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
+4 -2
View File
@@ -75,7 +75,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,7 +129,9 @@ if ($savebutton) {
$visiblepathtosection = array_reverse($settingspage->visiblepath);
$PAGE->set_title("$SITE->shortname: " . implode(": ",$visiblepathtosection));
$PAGE->set_heading($SITE->fullname);
$PAGE->set_button($buttons);
if ($buttons) {
$PAGE->set_button($buttons);
}
echo $OUTPUT->header();
+41
View File
@@ -0,0 +1,41 @@
<?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() {
return 'privacy:metadata';
}
}
+183
View File
@@ -2097,6 +2097,7 @@
<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>
@@ -2273,6 +2274,7 @@
<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>
@@ -2435,4 +2437,185 @@
</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">
</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>
+2 -3
View File
@@ -37,7 +37,7 @@ require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
admin_externalpage_setup('registrationhubs');
$renderer = $PAGE->get_renderer('core', 'register');
$renderer = $PAGE->get_renderer('core', 'admin');
$unregistration = optional_param('unregistration', 0, PARAM_INT);
$cleanregdata = optional_param('cleanregdata', 0, PARAM_BOOL);
@@ -181,8 +181,7 @@ if (empty($cancel) and $unregistration and !$confirm) {
echo $OUTPUT->header();
//check if the site is registered on Moodle.org and display a message about registering on MOOCH
$adminrenderer = $PAGE->get_renderer('core', 'admin');
echo $adminrenderer->warn_if_not_registered();
echo $renderer->warn_if_not_registered();
//do not check sesskey if confirm = false because this script is linked into email message
if (!empty($errormessage)) {
+1 -1
View File
@@ -195,7 +195,7 @@ if ($huburl == HUB_MOODLEORGHUBURL) {
echo $OUTPUT->notification($registrationmessage, $notificationtype);
echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
$renderer = $PAGE->get_renderer('core', 'register');
$renderer = $PAGE->get_renderer('core', 'admin');
echo $renderer->moodleorg_registration_message();
}
-95
View File
@@ -1,95 +0,0 @@
<?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);
}
}
+65
View File
@@ -2033,4 +2033,69 @@ 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() {
$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
*
* @param stdClass[] $hubs
* @return string
*/
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);
}
}
+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="' . $PAGE->url . '">' . get_string('backtoallroles', 'core_role') . '</a></p>';
echo '<p><a href="' . $url . '">' . get_string('backtoallroles', 'core_role') . '</a></p>';
echo '</div>';
} else if (empty($assignableroles)) {
@@ -100,6 +100,8 @@ 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))) {
@@ -476,7 +478,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="254" value="' . s($this->role->shortname) . '"' .
return '<input type="text" id="' . $id . '" name="' . $id . '" maxlength="100" value="' . s($this->role->shortname) . '"' .
' class="form-control"/>';
}
+379
View File
@@ -0,0 +1,379 @@
<?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;
/**
* 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 {
/**
* 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) {
$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($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($userid) {
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;
}
/**
* 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($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 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;
foreach ($contextlist->get_contexts() as $context) {
// Only delete the roles assignments where the user is assigned in all contexts.
$DB->delete_records('role_assignments', ['userid' => $userid, 'contextid' => $context->id]);
}
}
/**
* 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($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;
}
}
+477
View File
@@ -0,0 +1,477 @@
<?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;
/**
* 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);
}
/**
* 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;
}
}
+1 -1
View File
@@ -199,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'), 'http://docs.moodle.org', PARAM_URL));
$temp->add(new admin_setting_configtext('docroot', new lang_string('docroot', 'admin'), new lang_string('configdocroot', 'admin'), 'https://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));
+3 -1
View File
@@ -28,7 +28,9 @@ 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('xhprof') || extension_loaded('tideways');
$xhprofenabled = extension_loaded('tideways_xhprof');
$xhprofenabled = $xhprofenabled || extension_loaded('tideways');
$xhprofenabled = $xhprofenabled || extension_loaded('xhprof');
$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));
+1 -2
View File
@@ -49,8 +49,7 @@ 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'));
+46
View File
@@ -4,6 +4,7 @@
$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)
@@ -212,3 +213,48 @@ 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);
}
@@ -0,0 +1,73 @@
<?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->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($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,3 +58,4 @@ $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.';
@@ -0,0 +1,75 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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);
}
}
@@ -0,0 +1,46 @@
<?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() {
return 'privacy:metadata';
}
}
@@ -24,3 +24,4 @@
$string['manageplugins'] = 'Manage restrictions';
$string['pluginname'] = 'Availability condition management';
$string['privacy:metadata'] = 'The Availability condition management plugin does not store any personal data.';
@@ -0,0 +1,46 @@
<?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() {
return 'privacy:metadata';
}
}
+1
View File
@@ -50,3 +50,4 @@ $string['wrongbehatsetup'] = 'Something is wrong with the behat setup and so ste
<li>$CFG->behat_dataroot, $CFG->behat_prefix and $CFG->behat_wwwroot are set in config.php with different values from $CFG->dataroot, $CFG->prefix and $CFG->wwwroot.</li>
<li>You ran "{$a->behatinit}" from your Moodle root directory.</li>
<li>Dependencies are installed in vendor/ and {$a->behatcommand} file has execution permissions.</li></ul>';
$string['privacy:metadata'] = 'The Acceptance testing plugin does not store any personal data.';
@@ -0,0 +1,46 @@
<?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_capability.
*
* @package tool_capability
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_capability\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_capability 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() {
return 'privacy:metadata';
}
}
@@ -34,3 +34,4 @@ $string['pluginname'] = 'Capability overview';
$string['reportforcapability'] = 'Report for capability \'{$a}\'';
$string['reportsettings'] = 'Report settings';
$string['roleslabel'] = 'Roles:';
$string['privacy:metadata'] = 'The Capability overview plugin does not store any personal data.';
+1 -1
View File
@@ -167,7 +167,7 @@ class api {
$params['roleid'] = $roleid;
$params['userid'] = $userid;
$sql = 'SELECT u.id AS userid, ra.id, ctx.id AS contextid
$sql = 'SELECT DISTINCT u.id AS userid, ra.id, ctx.id AS contextid
FROM {user} u
JOIN {cohort_members} cm ON u.id = cm.userid
JOIN {context} ctx ON u.id = ctx.instanceid AND ctx.contextlevel = :usercontext
@@ -98,7 +98,7 @@ class cohort_role_assignments_table extends table_sql {
);
$context = context_helper::instance_by_id($data->cohortcontextid);
$exporter = new \tool_lp\external\cohort_summary_exporter($record, array('context' => $context));
$exporter = new \core_cohort\external\cohort_summary_exporter($record, array('context' => $context));
$cohort = $exporter->export($OUTPUT);
$html = $OUTPUT->render_from_template('tool_cohortroles/cohort-in-list', $cohort);
@@ -0,0 +1,200 @@
<?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_cohortroles.
*
* @package tool_cohortroles
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_cohortroles\privacy;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\context;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\writer;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_cohortroles implementing metadata and plugin 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\plugin\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) {
// The tool_cohortroles plugin utilises the mdl_tool_cohortroles table.
$collection->add_database_table(
'tool_cohortroles',
[
'id' => 'privacy:metadata:tool_cohortroles:id',
'cohortid' => 'privacy:metadata:tool_cohortroles:cohortid',
'roleid' => 'privacy:metadata:tool_cohortroles:roleid',
'userid' => 'privacy:metadata:tool_cohortroles:userid',
'timecreated' => 'privacy:metadata:tool_cohortroles:timecreated',
'timemodified' => 'privacy:metadata:tool_cohortroles:timemodified',
'usermodified' => 'privacy:metadata:tool_cohortroles:usermodified'
],
'privacy:metadata:tool_cohortroles'
);
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid($userid) {
$contextlist = new contextlist();
// Retrieve the User context associated with tool_cohortroles records.
$sql = "SELECT DISTINCT c.id
FROM {context} c
JOIN {tool_cohortroles} cr ON cr.userid = c.instanceid AND c.contextlevel = :contextuser
WHERE cr.userid = :userid";
$params = [
'contextuser' => CONTEXT_USER,
'userid' => $userid
];
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
global $DB;
// If the user has tool_cohortroles data, then only the User context should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}
$context = reset($contexts);
// Sanity check that context is at the User context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
return;
}
$userid = $context->instanceid;
// Retrieve the tool_cohortroles records created for the user.
$sql = 'SELECT cr.id as cohortroleid,
c.name as cohortname,
c.idnumber as cohortidnumber,
c.description as cohortdescription,
r.shortname as roleshortname,
cr.userid as userid,
cr.timecreated as timecreated,
cr.timemodified as timemodified
FROM {tool_cohortroles} cr
JOIN {cohort} c ON c.id = cr.cohortid
JOIN {role} r ON r.id = cr.roleid
WHERE cr.userid = :userid';
$params = [
'userid' => $userid
];
$cohortroles = $DB->get_records_sql($sql, $params);
foreach ($cohortroles as $cohortrole) {
// The tool_cohortroles data export is organised in:
// {User Context}/Cohort roles management/{cohort name}/{role shortname}/data.json.
$subcontext = [
get_string('pluginname', 'tool_cohortroles'),
$cohortrole->cohortname,
$cohortrole->roleshortname
];
$data = (object) [
'cohortname' => $cohortrole->cohortname,
'cohortidnumber' => $cohortrole->cohortidnumber,
'cohortdescription' => $cohortrole->cohortdescription,
'roleshortname' => $cohortrole->roleshortname,
'userid' => transform::user($cohortrole->userid),
'timecreated' => transform::datetime($cohortrole->timecreated),
'timemodified' => transform::datetime($cohortrole->timemodified)
];
writer::with_context($context)->export_data($subcontext, $data);
}
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
global $DB;
// Sanity check that context is at the User context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
return;
}
$userid = $context->instanceid;
// Delete the tool_cohortroles records created for the userid.
$DB->delete_records('tool_cohortroles', ['userid' => $userid]);
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
global $DB;
// If the user has tool_cohortroles data, then only the User context should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}
$context = reset($contexts);
// Sanity check that context is at the User context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
return;
}
$userid = $context->instanceid;
// Delete the tool_cohortroles records created for the userid.
$DB->delete_records('tool_cohortroles', ['userid' => $userid]);
}
}
@@ -42,3 +42,11 @@ $string['selectrole'] = 'Select role';
$string['selectusers'] = 'Select users to assign role';
$string['taskname'] = 'Sync cohort role assignments';
$string['thisuserroles'] = 'Roles assigned relative to this user';
$string['privacy:metadata:tool_cohortroles'] = 'The Cohort roles management plugin stores user cohort role mappings.';
$string['privacy:metadata:tool_cohortroles:id'] = 'The ID of the cohort role mapping record.';
$string['privacy:metadata:tool_cohortroles:cohortid'] = 'The ID of the cohort.';
$string['privacy:metadata:tool_cohortroles:roleid'] = 'The ID of the role.';
$string['privacy:metadata:tool_cohortroles:userid'] = 'The ID of the user.';
$string['privacy:metadata:tool_cohortroles:timecreated'] = 'The date/time of when the cohort role mapping was created.';
$string['privacy:metadata:tool_cohortroles:timemodified'] = 'The date/time of when the cohort role mapping was modified.';
$string['privacy:metadata:tool_cohortroles:usermodified'] = 'The ID of the user who last modified the cohort role mapping.';
@@ -0,0 +1,206 @@
<?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/>.
/**
* Unit tests for the tool_cohortroles implementation of the privacy API.
*
* @package tool_cohortroles
* @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();
global $CFG;
use \core_privacy\local\request\writer;
use \core_privacy\local\request\approved_contextlist;
use \tool_cohortroles\api;
use \tool_cohortroles\privacy\provider;
/**
* Unit tests for the tool_cohortroles implementation of the privacy API.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class tool_cohortroles_privacy_testcase extends \core_privacy\tests\provider_testcase {
/**
* Overriding setUp() function to always reset after tests.
*/
public function setUp() {
$this->resetAfterTest(true);
}
/**
* Test for provider::get_contexts_for_userid().
*/
public function test_get_contexts_for_userid() {
global $DB;
// Test setup.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->setAdminUser();
$nocohortroles = 3;
$this->setup_test_scenario_data($user->id, $nocohortroles);
// Test the User's assigned cohortroles matches 3.
$cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]);
$this->assertCount($nocohortroles, $cohortroles);
// Test the User's retrieved contextlist contains only one context.
$contextlist = provider::get_contexts_for_userid($user->id);
$contexts = $contextlist->get_contexts();
$this->assertCount(1, $contexts);
// Test the User's contexts equal the User's own context.
$context = reset($contexts);
$this->assertEquals(CONTEXT_USER, $context->contextlevel);
$this->assertEquals($user->id, $context->instanceid);
}
/**
* Test for provider::export_user_data().
*/
public function test_export_user_data() {
// Test setup.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->setAdminUser();
$nocohortroles = 3;
$this->setup_test_scenario_data($user->id, $nocohortroles);
// Test the User's retrieved contextlist contains only one context.
$contextlist = provider::get_contexts_for_userid($user->id);
$contexts = $contextlist->get_contexts();
$this->assertCount(1, $contexts);
// Test the User's contexts equal the User's own context.
$context = reset($contexts);
$this->assertEquals(CONTEXT_USER, $context->contextlevel);
$this->assertEquals($user->id, $context->instanceid);
// Retrieve the User's tool_cohortroles data.
$approvedcontextlist = new approved_contextlist($user, 'tool_cohortroles', $contextlist->get_contextids());
provider::export_user_data($approvedcontextlist);
// Test the tool_cohortroles data is exported at the User context level.
$writer = writer::with_context($context);
$this->assertTrue($writer->has_any_data());
}
/**
* Test for provider::delete_data_for_all_users_in_context().
*/
public function test_delete_data_for_all_users_in_context() {
global $DB;
// Test setup.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->setAdminUser();
$nocohortroles = 4;
$this->setup_test_scenario_data($user->id, $nocohortroles);
// Test the User's assigned cohortroles matches 4.
$cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]);
$this->assertCount($nocohortroles, $cohortroles);
// Test the User's retrieved contextlist contains only one context.
$contextlist = provider::get_contexts_for_userid($user->id);
$contexts = $contextlist->get_contexts();
$this->assertCount(1, $contexts);
// Test the User's contexts equal the User's own context.
$context = reset($contexts);
$this->assertEquals(CONTEXT_USER, $context->contextlevel);
$this->assertEquals($user->id, $context->instanceid);
// Delete all the User's records in mdl_tool_cohortroles table by the specified User context.
provider::delete_data_for_all_users_in_context($context);
// Test the cohort roles records in mdl_tool_cohortroles table is equals zero.
$cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]);
$this->assertCount(0, $cohortroles);
}
/**
* Test for provider::delete_data_for_user().
*/
public function test_delete_data_for_user() {
global $DB;
// Test setup.
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->setAdminUser();
$nocohortroles = 4;
$this->setup_test_scenario_data($user->id, $nocohortroles);
// Test the User's assigned cohortroles matches 4.
$cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]);
$this->assertCount($nocohortroles, $cohortroles);
// Test the User's retrieved contextlist contains only one context.
$contextlist = provider::get_contexts_for_userid($user->id);
$contexts = $contextlist->get_contexts();
$this->assertCount(1, $contexts);
// Test the User's contexts equal the User's own context.
$context = reset($contexts);
$this->assertEquals(CONTEXT_USER, $context->contextlevel);
$this->assertEquals($user->id, $context->instanceid);
// Delete all the User's records in mdl_tool_cohortroles table by the specified User approved context list.
$approvedcontextlist = new approved_contextlist($user, 'tool_cohortroles', $contextlist->get_contextids());
provider::delete_data_for_user($approvedcontextlist);
// Test the records in mdl_tool_cohortroles table is equals zero.
$cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]);
$this->assertCount(0, $cohortroles);
}
/**
* Helper function to setup tool_cohortroles records for testing a specific user.
*
* @param int $userid The ID of the user used for testing.
* @param int $nocohortroles The number of tool_cohortroles to create for the user.
* @throws \core_competency\invalid_persistent_exception
* @throws coding_exception
*/
protected function setup_test_scenario_data($userid, $nocohortroles) {
$roleid = create_role('Sausage Roll', 'sausageroll', 'mmmm');
for ($c = 0; $c < $nocohortroles; $c++) {
$cohort = $this->getDataGenerator()->create_cohort();
$params = (object)array(
'userid' => $userid,
'roleid' => $roleid,
'cohortid' => $cohort->id
);
api::create_cohort_role_assignment($params);
}
}
}
@@ -0,0 +1,46 @@
<?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_customlang.
*
* @package tool_customlang
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_customlang\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for tool_customlang 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() {
return 'privacy:metadata';
}
}
@@ -59,3 +59,4 @@ $string['placeholderwarning'] = 'string contains a placeholder';
$string['pluginname'] = 'Language customisation';
$string['savecheckin'] = 'Save changes to the language pack';
$string['savecontinue'] = 'Apply changes and continue editing';
$string['privacy:metadata'] = 'The Language customisation plugin does not store any personal data.';
+5
View File
@@ -159,6 +159,11 @@ class tool_customlang_utils {
$needsupdate = true;
$current[$stringid]->local = $stringlocal;
$current[$stringid]->timecustomized = $now;
} else if (isset($currentlocal) && $stringlocal !== $currentlocal) {
// If local string has been removed, we need to remove also the old local value from DB.
$needsupdate = true;
$current[$stringid]->local = null;
$current[$stringid]->timecustomized = $now;
}
if ($needsupdate) {
+1
View File
@@ -0,0 +1 @@
define(["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g){var h={CATEGORY_LINK:'[data-add-element="category"]'},i=function(a){this.contextId=a;var c=[{key:"addcategory",component:"tool_dataprivacy"},{key:"save",component:"admin"}];this.strings=b.get_strings(c),this.registerEventListeners()};return i.prototype.contextId=0,i.prototype.strings=0,i.prototype.registerEventListeners=function(){var b=a(h.CATEGORY_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))},i.prototype.getBody=function(a){var b=null;return"undefined"!=typeof a&&(b={jsonformdata:JSON.stringify(a)}),g.loadFragment("tool_dataprivacy","addcategory_form",this.contextId,b)},i.prototype.setupFormModal=function(a,b){a.setLarge(),a.setSaveButtonText(b),a.getRoot().on(f.hidden,this.destroy.bind(this)),a.setBody(this.getBody()),a.getRoot().on(f.save,this.submitForm.bind(this)),a.getRoot().on("submit","form",this.submitFormAjax.bind(this)),this.modal=a,a.show()},i.prototype.submitForm=function(a){a.preventDefault(),this.modal.getRoot().find("form").submit()},i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_category_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){a.validationerrors?this.modal.setBody(this.getBody(b)):this.close()}.bind(this),fail:d.exception}])},i.prototype.close=function(){this.destroy(),document.location.reload()},i.prototype.destroy=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()}),this.modal.destroy()},i.prototype.removeListeners=function(){a(h.CATEGORY_LINK).off("click")},{getInstance:function(a){return new i(a)}}});
+1
View File
@@ -0,0 +1 @@
define(["jquery","core/str","core/ajax","core/notification","core/modal_factory","core/modal_events","core/fragment"],function(a,b,c,d,e,f,g){var h={PURPOSE_LINK:'[data-add-element="purpose"]'},i=function(a){this.contextId=a;var c=[{key:"addpurpose",component:"tool_dataprivacy"},{key:"save",component:"admin"}];this.strings=b.get_strings(c),this.registerEventListeners()};return i.prototype.contextId=0,i.prototype.strings=0,i.prototype.registerEventListeners=function(){var b=a(h.PURPOSE_LINK);b.on("click",function(){return this.strings.then(function(a){e.create({type:e.types.SAVE_CANCEL,title:a[0],body:""},b).done(function(b){this.setupFormModal(b,a[1])}.bind(this))}.bind(this)).fail(d.exception)}.bind(this))},i.prototype.getBody=function(a){var b=null;return"undefined"!=typeof a&&(b={jsonformdata:JSON.stringify(a)}),g.loadFragment("tool_dataprivacy","addpurpose_form",this.contextId,b)},i.prototype.setupFormModal=function(a,b){a.setLarge(),a.setSaveButtonText(b),a.getRoot().on(f.hidden,this.destroy.bind(this)),a.setBody(this.getBody()),a.getRoot().on(f.save,this.submitForm.bind(this)),a.getRoot().on("submit","form",this.submitFormAjax.bind(this)),this.modal=a,a.show()},i.prototype.submitForm=function(a){a.preventDefault(),this.modal.getRoot().find("form").submit()},i.prototype.submitFormAjax=function(a){a.preventDefault();var b=this.modal.getRoot().find("form").serialize();c.call([{methodname:"tool_dataprivacy_create_purpose_form",args:{jsonformdata:JSON.stringify(b)},done:function(a){a.validationerrors?this.modal.setBody(this.getBody(b)):this.close()}.bind(this),fail:d.exception}])},i.prototype.close=function(){this.destroy(),document.location.reload()},i.prototype.destroy=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()}),this.modal.destroy()},i.prototype.removeListeners=function(){a(h.PURPOSE_LINK).off("click")},{getInstance:function(a){return new i(a)}}});
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f){var g={DELETE:'[data-action="deletecategory"]'},h=function(){this.registerEvents()};return h.prototype.registerEvents=function(){a(g.DELETE).click(function(g){g.preventDefault();var h=a(this).data("id"),i=a(this).data("name"),j=[{key:"deletecategory",component:"tool_dataprivacy"},{key:"deletecategorytext",component:"tool_dataprivacy",param:i},{key:"delete"}];d.get_strings(j).then(function(d){var g=d[0],i=d[1],j=d[2];return e.create({title:g,body:i,type:e.types.SAVE_CANCEL}).then(function(d){return d.setSaveButtonText(j),d.getRoot().on(f.save,function(){var d={methodname:"tool_dataprivacy_delete_category",args:{id:h}};b.call([d])[0].done(function(b){b.result?a('tr[data-categoryid="'+h+'"]').remove():c.addNotification({message:b.warnings[0].message,type:"error"})}).fail(c.exception)}),d.getRoot().on(f.hidden,function(){d.destroy()}),d})}).done(function(a){a.show()}).fail(c.exception)})},{init:function(){return new h}}});
+1
View File
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f){function g(a){var g=[{key:"confirm",component:"moodle"},{key:"confirmcontextdeletion",component:"tool_dataprivacy"}],h="tool_dataprivacy_confirm_contexts_for_deletion",i="";d.get_strings(g).then(function(a){i=a[0];var b=a[1];return e.create({title:i,body:b,type:e.types.SAVE_CANCEL})}).then(function(d){return d.setSaveButtonText(i),d.getRoot().on(f.save,function(){var d={ids:a},e={methodname:h,args:d};b.call([e])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}),d.getRoot().on(f.hidden,function(){d.destroy()}),d}).done(function(a){a.show()}).fail(c.exception)}var h={MARK_FOR_DELETION:'[data-action="markfordeletion"]',SELECT_ALL:'[data-action="selectall"]'},i={SELECTCONTEXT:".selectcontext"},j=function(){this.registerEvents()};return j.prototype.registerEvents=function(){a(h.MARK_FOR_DELETION).click(function(b){b.preventDefault();var c=[];a(i.SELECTCONTEXT).each(function(){var b=a(this);b.is(":checked")&&c.push(b.val())}),g(c)}),a(h.SELECT_ALL).change(function(b){b.preventDefault();var c=a(this);c.is(":checked")?a(i.SELECTCONTEXT).attr("checked","checked"):a(i.SELECTCONTEXT).removeAttr("checked")})},j});
+1
View File
@@ -0,0 +1 @@
define(["jquery","core/str","core/ajax","core/notification","core/templates","core/modal_factory","core/modal_events","core/fragment","tool_dataprivacy/add_purpose","tool_dataprivacy/add_category"],function(a,b,c,d,e,f,g,h,i,j){var k={TREE_NODES:"[data-context-tree-node=1]",FORM_CONTAINER:"#context-form-container"},l=function(a,b,c){this.systemContextId=a,this.currentContextLevel=b,this.currentContextId=c,this.init()};return l.prototype.systemContextId=0,l.prototype.currentContextLevel=0,l.prototype.currentContextId=0,l.prototype.addpurpose=null,l.prototype.addcategory=null,l.prototype.init=function(){this.addpurpose=i.getInstance(this.systemContextId),this.addcategory=j.getInstance(this.systemContextId);var a=[{key:"changessaved",component:"moodle"},{key:"contextpurposecategorysaved",component:"tool_dataprivacy"},{key:"noblockstoload",component:"tool_dataprivacy"},{key:"noactivitiestoload",component:"tool_dataprivacy"},{key:"nocoursestoload",component:"tool_dataprivacy"}];this.strings=b.get_strings(a),this.registerEventListeners(),this.currentContextId?this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this)):this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this))},l.prototype.registerEventListeners=function(){a(k.TREE_NODES).on("click",function(b){b.preventDefault();var c=a(b.currentTarget);a(k.TREE_NODES).removeClass("active"),c.addClass("active");var d=c.data("contextlevel"),e=c.data("contextid");if(d)window.history.pushState({},null,"?contextlevel="+d),this.addpurpose.removeListeners(),this.addcategory.removeListeners(),this.currentContextLevel=d,this.loadForm("contextlevel_form",[this.currentContextLevel],this.submitContextLevelFormAjax.bind(this));else if(e)window.history.pushState({},null,"?contextid="+e),this.addpurpose.removeListeners(),this.addcategory.removeListeners(),this.currentContextId=e,this.loadForm("context_form",[this.currentContextId],this.submitContextFormAjax.bind(this));else{var f=c.data("expandcontextid"),g=c.data("expandelement"),h=c.data("expanded");g&&(h?this.collapse(c):!c.data("loaded")&&f&&g?(c.find("> i").removeClass("fa-plus"),c.find("> i").addClass("fa-circle-o-notch fa-spin"),this.loadExtra(c,f,g)):this.expand(c))}}.bind(this))},l.prototype.removeListeners=function(){a(k.TREE_NODES).off("click")},l.prototype.loadForm=function(b,c,f){this.clearForm();var g=h.loadFragment("tool_dataprivacy",b,this.systemContextId,c);g.done(function(b,c){a(k.FORM_CONTAINER).html(b),e.runTemplateJS(c),this.addpurpose.registerEventListeners(),this.addcategory.registerEventListeners(),a(k.FORM_CONTAINER).on("submit","form",f)}.bind(this)).fail(d.exception)},l.prototype.clearForm=function(){Y.use("moodle-core-formchangechecker",function(){M.core_formchangechecker.reset_form_dirty_state()}),a(k.FORM_CONTAINER).off("submit","form")},l.prototype.submitForm=function(b){b.preventDefault(),a(k.FORM_CONTAINER).find("form").submit()},l.prototype.submitContextLevelFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_contextlevel_form")},l.prototype.submitContextFormAjax=function(a){this.submitFormAjax(a,"tool_dataprivacy_set_context_form")},l.prototype.submitFormAjax=function(b,e){b.preventDefault();var f=a(k.FORM_CONTAINER).find("form").serialize();return this.strings.then(function(a){c.call([{methodname:e,args:{jsonformdata:JSON.stringify(f)},done:function(){d.alert(a[0],a[1])},fail:d.exception}])})["catch"](d.exception)},l.prototype.loadExtra=function(a,b,f){c.call([{methodname:"tool_dataprivacy_tree_extra_branches",args:{contextid:b,element:f},done:function(b){return 0==b.branches.length?void this.noElements(a,f):void e.render("tool_dataprivacy/context_tree_branches",b).then(function(b){a.after(b),this.removeListeners(),this.registerEventListeners(),this.expand(a),a.data("loaded",1)}.bind(this)).fail(d.exception)}.bind(this),fail:d.exception}])},l.prototype.noElements=function(a,b){a.data("expandcontextid",""),a.data("expandelement",""),this.strings.then(function(c){var d=2;"module"==b?d=3:"course"==b&&(d=4),a.text(c[d])}).fail(d.exception)},l.prototype.collapse=function(a){a.data("expanded",0),a.siblings("nav").addClass("hidden"),a.find("> i").removeClass("fa-minus"),a.find("> i").addClass("fa-plus")},l.prototype.expand=function(a){a.data("expanded",1),a.siblings("nav").removeClass("hidden"),a.find("> i").removeClass("fa-plus"),a.find("> i").removeClass("fa-circle-o-notch fa-spin"),a.find("> i").addClass("fa-minus")},{init:function(a,b,c){return new l(a,b,c)}}});
@@ -0,0 +1 @@
define(["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_registry","tool_dataprivacy/events"],function(a,b,c,d,e,f){var g=!1,h={APPROVE_BUTTON:'[data-action="approve"]',DENY_BUTTON:'[data-action="deny"]',COMPLETE_BUTTON:'[data-action="complete"]'},i=function(a){d.call(this,a)};return i.TYPE="tool_dataprivacy-data_request",i.TYPE_ENQUIRY="tool_dataprivacy-complete_request",i.prototype=Object.create(d.prototype),i.prototype.constructor=i,i.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this),this.getModal().on(c.events.activate,h.APPROVE_BUTTON,function(b,c){var d=a.Event(f.approve);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,h.DENY_BUTTON,function(b,c){var d=a.Event(f.deny);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this)),this.getModal().on(c.events.activate,h.COMPLETE_BUTTON,function(b,c){var d=a.Event(f.complete);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this))},g||(e.register(i.TYPE,i,"tool_dataprivacy/data_request_modal"),e.register(i.TYPE_ENQUIRY,i,"tool_dataprivacy/mark_request_complete_modal"),g=!0),i});
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates"],function(a,b,c,d,e,f,g){function h(b,d,h,j,k,l,m,n){null!==h&&l.forEach(function(a){a.id===h&&(a.selected=!0)}),null!==j&&m.forEach(function(a){a.id===j&&(a.selected=!0)});var o={contextlevel:d,categoryoptions:l,purposeoptions:m};null!==n&&n.length&&(null===k?o.newactivitydefaults=!0:n.forEach(function(a){k===a.name&&(a.selected=!0)}),o.modemodule=!0,o.activityoptions=n),e.create({title:b,body:g.render("tool_dataprivacy/category_purpose_form",o),type:e.types.SAVE_CANCEL,large:!0}).then(function(b){return b.getRoot().on(f.save,function(){var b=a("#activity"),c="undefined"!=typeof b?b.val():null,d=a("#override"),e="undefined"!=typeof d&&d.is(":checked");i(a("#contextlevel").val(),a("#category").val(),a("#purpose").val(),c,e)}),b.getRoot().on(f.hidden,function(){b.destroy()}),b.show(),b})["catch"](c.exception)}function i(a,c,d,e,f){var g={methodname:"tool_dataprivacy_set_context_defaults",args:{contextlevel:a,category:c,purpose:d,override:f,activity:e}};b.call([g])[0].done(function(a){a.result&&window.location.reload()})}var j={EDIT_LEVEL_DEFAULTS:'[data-action="edit-level-defaults"]',NEW_ACTIVITY_DEFAULTS:'[data-action="new-activity-defaults"]',EDIT_ACTIVITY_DEFAULTS:'[data-action="edit-activity-defaults"]',DELETE_ACTIVITY_DEFAULTS:'[data-action="delete-activity-defaults"]'},k=-1,l=function(){this.registerEvents()};return l.prototype.registerEvents=function(){a(j.EDIT_LEVEL_DEFAULTS).click(function(e){e.preventDefault();var f=a(this),g=f.data("contextlevel"),i=f.data("category"),j=f.data("purpose"),k=[{methodname:"tool_dataprivacy_get_category_options",args:{}},{methodname:"tool_dataprivacy_get_purpose_options",args:{}}],l=b.call(k),m=d.get_string("editdefaults","tool_dataprivacy",a("#defaults-header").text());a.when(l[0],l[1],m).then(function(a,b,c){var d=a.options,e=b.options;return h(c,g,i,j,null,d,e,null),!0})["catch"](c.exception)}),a(j.NEW_ACTIVITY_DEFAULTS).click(function(e){e.preventDefault();var f=a(this),g=f.data("contextlevel"),i=[{methodname:"tool_dataprivacy_get_category_options",args:{}},{methodname:"tool_dataprivacy_get_purpose_options",args:{}},{methodname:"tool_dataprivacy_get_activity_options",args:{nodefaults:!0}}],j=b.call(i),k=d.get_string("addnewdefaults","tool_dataprivacy");a.when(j[0],j[1],j[2],k).then(function(a,b,c,d){var e=a.options,f=b.options,i=c.options;return h(d,g,null,null,null,e,f,i),!0})["catch"](c.exception)}),a(j.EDIT_ACTIVITY_DEFAULTS).click(function(e){e.preventDefault();var f=a(this),g=f.data("contextlevel"),i=f.data("category"),j=f.data("purpose"),k=f.data("activityname"),l=[{methodname:"tool_dataprivacy_get_category_options",args:{}},{methodname:"tool_dataprivacy_get_purpose_options",args:{}},{methodname:"tool_dataprivacy_get_activity_options",args:{}}],m=b.call(l),n=d.get_string("editmoduledefaults","tool_dataprivacy");a.when(m[0],m[1],m[2],n).then(function(a,b,c,d){var e=a.options,f=b.options,l=c.options;return h(d,g,i,j,k,e,f,l),!0})["catch"](c.exception)}),a(j.DELETE_ACTIVITY_DEFAULTS).click(function(b){b.preventDefault();var h=a(this),j=h.data("contextlevel"),l=h.data("activityname"),m=h.data("activitydisplayname"),n=k,o=k;e.create({title:d.get_string("deletedefaults","tool_dataprivacy",m),body:g.render("tool_dataprivacy/delete_activity_defaults",{activityname:m}),type:e.types.SAVE_CANCEL,large:!0}).then(function(a){return a.setSaveButtonText(d.get_string("delete")),a.getRoot().on(f.save,function(){i(j,n,o,l,!1)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a.show(),!0})["catch"](c.exception)})},{init:function(){return new l}}});
@@ -0,0 +1 @@
define(["jquery"],function(a){var b={PURPOSE_SELECT:"#id_purposeid",RETENTION_FIELD_BOOST:"#id_error_retention_current",RETENTION_FIELD_CLEAN:"#fitem_id_retention_current [data-fieldtype=static]"},c=function(a){this.purposeRetentionPeriods=a,this.registerEventListeners()},d=function(){a(b.PURPOSE_SELECT).off("change")};return c.prototype.purposeRetentionPeriods=[],c.prototype.registerEventListeners=function(){a(b.PURPOSE_SELECT).on("change",function(c){var d=a(c.currentTarget).val(),e=this.purposeRetentionPeriods[d],f=a(b.RETENTION_FIELD_CLEAN);if(f.length>0)f.text(e);else{var g=a(b.RETENTION_FIELD_BOOST),h=g.siblings();h.length>0&&h.text(e)}}.bind(this))},{init:function(a){return d(),new c(a)}}});
+1
View File
@@ -0,0 +1 @@
define([],function(){return{approve:"tool_dataprivacy-data_request:approve",bulkApprove:"tool_dataprivacy-data_request:bulk_approve",deny:"tool_dataprivacy-data_request:deny",bulkDeny:"tool_dataprivacy-data_request:bulk_deny",complete:"tool_dataprivacy-data_request:complete"}});
@@ -0,0 +1 @@
define(["jquery","core/url","core/str"],function(a,b,c){var d=a('<img alt="" src="'+b.imageUrl("t/expanded")+'"/>'),e=a('<img alt="" src="'+b.imageUrl("t/collapsed")+'"/>');return{expandCollapse:function(a,b){a.hasClass("hide")?(a.removeClass("hide"),a.addClass("visible"),a.attr("aria-expanded",!0),b.find(":header i.fa").removeClass("fa-plus-square"),b.find(":header i.fa").addClass("fa-minus-square"),b.find(":header img.icon").attr("src",d.attr("src"))):(a.removeClass("visible"),a.addClass("hide"),a.attr("aria-expanded",!1),b.find(":header i.fa").removeClass("fa-minus-square"),b.find(":header i.fa").addClass("fa-plus-square"),b.find(":header img.icon").attr("src",e.attr("src")))},expandCollapseAll:function(b){var f="visible"==b?"hide":"visible",g="visible"==b,h="visible"==b?"fa-plus-square":"fa-minus-square",i="visible"==b?"fa-minus-square":"fa-plus-square",j="visible"==b?d.attr("src"):e.attr("src");a("."+f).each(function(){a(this).removeClass(f),a(this).addClass(b),a(this).attr("aria-expanded",g)}),a(".tool_dataprivacy-expand-all").data("visibilityState",f),c.get_string(f,"tool_dataprivacy").then(function(b){a(".tool_dataprivacy-expand-all").html(b)})["catch"](Notification.exception),a(":header i.fa").each(function(){a(this).removeClass(h),a(this).addClass(i)}),a(":header img.icon").each(function(){a(this).attr("src",j)})}}});
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/templates"],function(a,b,c){return{processResults:function(b,c){var d=[];return a.each(c,function(a,b){d.push({value:b.id,label:b._label})}),d},transport:function(d,e,f,g){var h;h=b.call([{methodname:"tool_dataprivacy_get_users",args:{query:e}}]),h[0].then(function(b){var d=[],e=0;return a.each(b,function(a,b){d.push(c.render("tool_dataprivacy/form-user-selector-suggestion",b))}),a.when.apply(a.when,d).then(function(){var c=arguments;a.each(b,function(a,b){b._label=c[e],e++}),f(b)})}).fail(g)}}});
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates"],function(a,b,c,d,e,f,g){function h(a){var e={methodname:"tool_dataprivacy_contact_dpo",args:{message:a}},f="success";b.call([e])[0].then(function(a){return a.result?d.get_string("requestsubmitted","tool_dataprivacy"):(f="error",a.warnings.join("<br>"))}).done(function(a){c.addNotification({message:a,type:f})}).fail(c.exception)}var i={CANCEL_REQUEST:'[data-action="cancel"]',CONTACT_DPO:'[data-action="contactdpo"]'},j=function(){this.registerEvents()};return j.prototype.registerEvents=function(){a(i.CANCEL_REQUEST).click(function(g){g.preventDefault();var h=a(this).data("requestid"),i=[{key:"cancelrequest",component:"tool_dataprivacy"},{key:"cancelrequestconfirmation",component:"tool_dataprivacy"}];d.get_strings(i).then(function(a){var d=a[0],g=a[1];return e.create({title:d,body:g,type:e.types.SAVE_CANCEL}).then(function(a){return a.setSaveButtonText(d),a.getRoot().on(f.save,function(){var a={requestid:h},d={methodname:"tool_dataprivacy_cancel_data_request",args:a};b.call([d])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a})}).done(function(a){a.show()}).fail(c.exception)}),a(i.CONTACT_DPO).click(function(b){b.preventDefault();var i=a(this).data("replytoemail"),j=[{key:"contactdataprotectionofficer",component:"tool_dataprivacy"},{key:"send",component:"tool_dataprivacy"}],k="";d.get_strings(j).then(function(a){var b=a[0];k=a[1];var c={replytoemail:i};return e.create({title:b,body:g.render("tool_dataprivacy/contact_dpo",c),type:e.types.SAVE_CANCEL,large:!0})}).done(function(b){b.setSaveButtonText(k),b.getRoot().on(f.save,function(b){var c=a("#message").val().trim();0===c.length?(b.preventDefault(),a('[data-region="messageinput"]').addClass("has-danger notifyproblem"),a("#id_error_message").removeAttr("hidden")):h(c)}),b.getRoot().on(f.hidden,function(){b.destroy()}),b.show()}).fail(c.exception)})},{init:function(){return new j}}});
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f){var g={DELETE:'[data-action="deletepurpose"]'},h=function(){this.registerEvents()};return h.prototype.registerEvents=function(){a(g.DELETE).click(function(g){g.preventDefault();var h=a(this).data("id"),i=a(this).data("name"),j=[{key:"deletepurpose",component:"tool_dataprivacy"},{key:"deletepurposetext",component:"tool_dataprivacy",param:i},{key:"delete"}];d.get_strings(j).then(function(d){var g=d[0],i=d[1],j=d[2];return e.create({title:g,body:i,type:e.types.SAVE_CANCEL}).then(function(d){return d.setSaveButtonText(j),d.getRoot().on(f.save,function(){var d={methodname:"tool_dataprivacy_delete_purpose",args:{id:h}};b.call([d])[0].done(function(b){b.result?a('tr[data-purposeid="'+h+'"]').remove():c.addNotification({message:b.warnings[0].message,type:"error"})}).fail(c.exception)}),d.getRoot().on(f.hidden,function(){d.destroy()}),d})}).done(function(a){a.show()}).fail(c.exception)})},{init:function(){return new h}}});
@@ -0,0 +1 @@
define(["jquery","core/form-autocomplete","core/str","core/notification"],function(a,b,c,d){var e={REQUEST_FILTERS:"#request-filters"},f=function(){var f=[{key:"filter",component:"moodle"},{key:"nofiltersapplied",component:"tool_dataprivacy"}];c.get_strings(f).then(function(a){var c=a[0],d=a[1];return b.enhance(e.REQUEST_FILTERS,!1,"",c,!1,!0,d,!0)}).fail(d.exception);var g=a(e.REQUEST_FILTERS).val();a(e.REQUEST_FILTERS).on("change",function(){var b=a(this).val();g.join(",")!==b.join(",")&&(0===b.length&&a("#filters-cleared").val(1),a(this.form).submit())})};return{init:function(){f()}}});
@@ -0,0 +1 @@
define(["jquery","core/ajax","core/notification","core/str","core/modal_factory","core/modal_events","core/templates","tool_dataprivacy/data_request_modal","tool_dataprivacy/events"],function(a,b,c,d,e,f,g,h,i){function j(a){return{wsfunction:"tool_dataprivacy_approve_data_request",wsparams:{requestid:a}}}function k(a){return{wsfunction:"tool_dataprivacy_bulk_approve_data_requests",wsparams:{requestids:a}}}function l(a){return{wsfunction:"tool_dataprivacy_deny_data_request",wsparams:{requestid:a}}}function m(a){return{wsfunction:"tool_dataprivacy_bulk_deny_data_requests",wsparams:{requestids:a}}}function n(a){return{wsfunction:"tool_dataprivacy_mark_complete",wsparams:{requestid:a}}}function o(a,b){var g=[];switch(a){case i.approve:g=[{key:"approverequest",component:"tool_dataprivacy"},{key:"confirmapproval",component:"tool_dataprivacy"}];break;case i.bulkApprove:g=[{key:"bulkapproverequests",component:"tool_dataprivacy"},{key:"confirmbulkapproval",component:"tool_dataprivacy"}];break;case i.deny:g=[{key:"denyrequest",component:"tool_dataprivacy"},{key:"confirmdenial",component:"tool_dataprivacy"}];break;case i.bulkDeny:g=[{key:"bulkdenyrequests",component:"tool_dataprivacy"},{key:"confirmbulkdenial",component:"tool_dataprivacy"}];break;case i.complete:g=[{key:"markcomplete",component:"tool_dataprivacy"},{key:"confirmcompletion",component:"tool_dataprivacy"}]}var h="";d.get_strings(g).then(function(a){h=a[0];var b=a[1];return e.create({title:h,body:b,type:e.types.SAVE_CANCEL})}).then(function(a){a.setSaveButtonText(h),a.getRoot().on(f.save,function(){p(b.wsfunction,b.wsparams)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a.show()})["catch"](c.exception)}function p(a,d){var e={methodname:a,args:d};b.call([e])[0].done(function(a){a.result?window.location.reload():c.addNotification({message:a.warnings[0].message,type:"error"})}).fail(c.exception)}var q={APPROVE_REQUEST:'[data-action="approve"]',DENY_REQUEST:'[data-action="deny"]',VIEW_REQUEST:'[data-action="view"]',MARK_COMPLETE:'[data-action="complete"]',CHANGE_BULK_ACTION:'[id="bulk-action"]',CONFIRM_BULK_ACTION:'[id="confirm-bulk-action"]',SELECT_ALL:'[data-action="selectall"]'},r={APPROVE:1,DENY:2},s={SELECT_REQUEST:".selectrequests"},t=function(){this.registerEvents()};return t.prototype.registerEvents=function(){a(q.VIEW_REQUEST).click(function(d){d.preventDefault();var k=a(this).data("requestid"),m={requestid:k},n={methodname:"tool_dataprivacy_get_data_request",args:m},q=b.call([n]);a.when(q[0]).then(function(a){return a.result?a.result:(c.addNotification({message:a.warnings[0].message,type:"error"}),!1)}).then(function(a){var b=e.types.DEFAULT;a.approvedeny?b=h.TYPE:a.canmarkcomplete&&(b=h.TYPE_ENQUIRY);var c=g.render("tool_dataprivacy/request_details",a);return e.create({title:a.typename,body:c,type:b,large:!0})}).then(function(a){a.getRoot().on(i.approve,function(){o(i.approve,j(k))}),a.getRoot().on(i.deny,function(){o(i.deny,l(k))}),a.getRoot().on(i.complete,function(){var a={requestid:k};p("tool_dataprivacy_mark_complete",a)}),a.getRoot().on(f.hidden,function(){a.destroy()}),a.show()})["catch"](c.exception)}),a(q.APPROVE_REQUEST).click(function(b){b.preventDefault();var c=a(this).data("requestid");o(i.approve,j(c))}),a(q.DENY_REQUEST).click(function(b){b.preventDefault();var c=a(this).data("requestid");o(i.deny,l(c))}),a(q.MARK_COMPLETE).click(function(b){b.preventDefault();var c=a(this).data("requestid");o(i.complete,n(c))}),a(q.CONFIRM_BULK_ACTION).click(function(){var b=[],e="",f={},g=[{key:"selectbulkaction",component:"tool_dataprivacy"},{key:"selectdatarequests",component:"tool_dataprivacy"},{key:"ok"}],h=parseInt(a("#bulk-action").val());if(h!=r.APPROVE&&h!=r.DENY)return void d.get_strings(g).done(function(a){c.alert("",a[0],a[2])}).fail(c.exception);if(a(".selectrequests:checked").each(function(){b.push(a(this).val())}),b.length<1)return void d.get_strings(g).done(function(a){c.alert("",a[1],a[2])}).fail(c.exception);switch(h){case r.APPROVE:e=i.bulkApprove,f=k(b);break;case r.DENY:e=i.bulkDeny,f=m(b)}o(e,f)}),a(q.SELECT_ALL).change(function(b){b.preventDefault();var c=a(this).is(":checked");a(s.SELECT_REQUEST).prop("checked",c)})},t});
@@ -0,0 +1,172 @@
// 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/>.
/**
* Module to add categories.
*
* @module tool_dataprivacy/add_category
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],
function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {
var SELECTORS = {
CATEGORY_LINK: '[data-add-element="category"]',
};
var AddCategory = function(contextId) {
this.contextId = contextId;
var stringKeys = [
{
key: 'addcategory',
component: 'tool_dataprivacy'
},
{
key: 'save',
component: 'admin'
}
];
this.strings = Str.get_strings(stringKeys);
this.registerEventListeners();
};
/**
* @var {int} contextId
* @private
*/
AddCategory.prototype.contextId = 0;
/**
* @var {Promise}
* @private
*/
AddCategory.prototype.strings = 0;
AddCategory.prototype.registerEventListeners = function() {
var trigger = $(SELECTORS.CATEGORY_LINK);
trigger.on('click', function() {
return this.strings.then(function(strings) {
ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: strings[0],
body: '',
}, trigger).done(function(modal) {
this.setupFormModal(modal, strings[1]);
}.bind(this));
}.bind(this))
.fail(Notification.exception);
}.bind(this));
};
/**
* @method getBody
* @param {Object} formdata
* @private
* @return {Promise}
*/
AddCategory.prototype.getBody = function(formdata) {
var params = null;
if (typeof formdata !== "undefined") {
params = {jsonformdata: JSON.stringify(formdata)};
}
// Get the content of the modal.
return Fragment.loadFragment('tool_dataprivacy', 'addcategory_form', this.contextId, params);
};
AddCategory.prototype.setupFormModal = function(modal, saveText) {
modal.setLarge();
modal.setSaveButtonText(saveText);
// We want to reset the form every time it is opened.
modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));
modal.setBody(this.getBody());
// We catch the modal save event, and use it to submit the form inside the modal.
// Triggering a form submission will give JS validation scripts a chance to check for errors.
modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));
// We also catch the form submit event and use it to submit the form with ajax.
modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));
this.modal = modal;
modal.show();
};
/**
* This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.
*
* @method submitForm
* @param {Event} e Form submission event.
* @private
*/
AddCategory.prototype.submitForm = function(e) {
e.preventDefault();
this.modal.getRoot().find('form').submit();
};
AddCategory.prototype.submitFormAjax = function(e) {
// We don't want to do a real form submission.
e.preventDefault();
// Convert all the form elements values to a serialised string.
var formData = this.modal.getRoot().find('form').serialize();
Ajax.call([{
methodname: 'tool_dataprivacy_create_category_form',
args: {jsonformdata: JSON.stringify(formData)},
done: function(data) {
if (data.validationerrors) {
this.modal.setBody(this.getBody(formData));
} else {
this.close();
}
}.bind(this),
fail: Notification.exception
}]);
};
AddCategory.prototype.close = function() {
this.destroy();
document.location.reload();
};
AddCategory.prototype.destroy = function() {
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
this.modal.destroy();
};
AddCategory.prototype.removeListeners = function() {
$(SELECTORS.CATEGORY_LINK).off('click');
};
return /** @alias module:tool_dataprivacy/add_category */ {
getInstance: function(contextId) {
return new AddCategory(contextId);
}
};
}
);
@@ -0,0 +1,173 @@
// 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/>.
/**
* Module to add purposes.
*
* @module tool_dataprivacy/add_purpose
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/modal_factory', 'core/modal_events', 'core/fragment'],
function($, Str, Ajax, Notification, ModalFactory, ModalEvents, Fragment) {
var SELECTORS = {
PURPOSE_LINK: '[data-add-element="purpose"]',
};
var AddPurpose = function(contextId) {
this.contextId = contextId;
var stringKeys = [
{
key: 'addpurpose',
component: 'tool_dataprivacy'
},
{
key: 'save',
component: 'admin'
}
];
this.strings = Str.get_strings(stringKeys);
this.registerEventListeners();
};
/**
* @var {int} contextId
* @private
*/
AddPurpose.prototype.contextId = 0;
/**
* @var {Promise}
* @private
*/
AddPurpose.prototype.strings = 0;
AddPurpose.prototype.registerEventListeners = function() {
var trigger = $(SELECTORS.PURPOSE_LINK);
trigger.on('click', function() {
return this.strings.then(function(strings) {
ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: strings[0],
body: '',
}, trigger).done(function(modal) {
this.setupFormModal(modal, strings[1]);
}.bind(this));
}.bind(this))
.fail(Notification.exception);
}.bind(this));
};
/**
* @method getBody
* @param {Object} formdata
* @private
* @return {Promise}
*/
AddPurpose.prototype.getBody = function(formdata) {
var params = null;
if (typeof formdata !== "undefined") {
params = {jsonformdata: JSON.stringify(formdata)};
}
// Get the content of the modal.
return Fragment.loadFragment('tool_dataprivacy', 'addpurpose_form', this.contextId, params);
};
AddPurpose.prototype.setupFormModal = function(modal, saveText) {
modal.setLarge();
modal.setSaveButtonText(saveText);
// We want to reset the form every time it is opened.
modal.getRoot().on(ModalEvents.hidden, this.destroy.bind(this));
modal.setBody(this.getBody());
// We catch the modal save event, and use it to submit the form inside the modal.
// Triggering a form submission will give JS validation scripts a chance to check for errors.
modal.getRoot().on(ModalEvents.save, this.submitForm.bind(this));
// We also catch the form submit event and use it to submit the form with ajax.
modal.getRoot().on('submit', 'form', this.submitFormAjax.bind(this));
this.modal = modal;
modal.show();
};
/**
* This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.
*
* @method submitForm
* @param {Event} e Form submission event.
* @private
*/
AddPurpose.prototype.submitForm = function(e) {
e.preventDefault();
this.modal.getRoot().find('form').submit();
};
AddPurpose.prototype.submitFormAjax = function(e) {
// We don't want to do a real form submission.
e.preventDefault();
// Convert all the form elements values to a serialised string.
var formData = this.modal.getRoot().find('form').serialize();
Ajax.call([{
methodname: 'tool_dataprivacy_create_purpose_form',
args: {jsonformdata: JSON.stringify(formData)},
done: function(data) {
if (data.validationerrors) {
this.modal.setBody(this.getBody(formData));
} else {
this.close();
}
}.bind(this),
fail: Notification.exception
}]);
};
AddPurpose.prototype.close = function() {
this.destroy();
document.location.reload();
};
AddPurpose.prototype.destroy = function() {
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
this.modal.destroy();
};
AddPurpose.prototype.removeListeners = function() {
$(SELECTORS.PURPOSE_LINK).off('click');
};
return /** @alias module:tool_dataprivacy/add_purpose */ {
getInstance: function(contextId) {
return new AddPurpose(contextId);
}
};
}
);
@@ -0,0 +1,132 @@
// 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 categories actions.
*
* @module tool_dataprivacy/categoriesactions
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/modal_factory',
'core/modal_events'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents) {
/**
* List of action selectors.
*
* @type {{DELETE: string}}
*/
var ACTIONS = {
DELETE: '[data-action="deletecategory"]',
};
/**
* CategoriesActions class.
*/
var CategoriesActions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
CategoriesActions.prototype.registerEvents = function() {
$(ACTIONS.DELETE).click(function(e) {
e.preventDefault();
var id = $(this).data('id');
var categoryname = $(this).data('name');
var stringkeys = [
{
key: 'deletecategory',
component: 'tool_dataprivacy'
},
{
key: 'deletecategorytext',
component: 'tool_dataprivacy',
param: categoryname
},
{
key: 'delete'
}
];
Str.get_strings(stringkeys).then(function(langStrings) {
var title = langStrings[0];
var confirmMessage = langStrings[1];
var buttonText = langStrings[2];
return ModalFactory.create({
title: title,
body: confirmMessage,
type: ModalFactory.types.SAVE_CANCEL
}).then(function(modal) {
modal.setSaveButtonText(buttonText);
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
var request = {
methodname: 'tool_dataprivacy_delete_category',
args: {'id': id}
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
$('tr[data-categoryid="' + id + '"]').remove();
} else {
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
return modal;
});
}).done(function(modal) {
modal.show();
}).fail(Notification.exception);
});
};
return /** @alias module:tool_dataprivacy/categoriesactions */ {
// Public variables and functions.
/**
* Initialise the module.
*
* @method init
* @return {CategoriesActions}
*/
'init': function() {
return new CategoriesActions();
}
};
});
@@ -0,0 +1,156 @@
// 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/>.
/**
* Request actions.
*
* @module tool_dataprivacy/data_deletion
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/modal_factory',
'core/modal_events'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents) {
/**
* List of action selectors.
*
* @type {{MARK_FOR_DELETION: string}}
* @type {{SELECT_ALL: string}}
*/
var ACTIONS = {
MARK_FOR_DELETION: '[data-action="markfordeletion"]',
SELECT_ALL: '[data-action="selectall"]',
};
/**
* List of selectors.
*
* @type {{SELECTCONTEXT: string}}
*/
var SELECTORS = {
SELECTCONTEXT: '.selectcontext',
};
/**
* DataDeletionActions class.
*/
var DataDeletionActions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
DataDeletionActions.prototype.registerEvents = function() {
$(ACTIONS.MARK_FOR_DELETION).click(function(e) {
e.preventDefault();
var selectedIds = [];
$(SELECTORS.SELECTCONTEXT).each(function() {
var checkbox = $(this);
if (checkbox.is(':checked')) {
selectedIds.push(checkbox.val());
}
});
showConfirmation(selectedIds);
});
$(ACTIONS.SELECT_ALL).change(function(e) {
e.preventDefault();
var selectallnone = $(this);
if (selectallnone.is(':checked')) {
$(SELECTORS.SELECTCONTEXT).attr('checked', 'checked');
} else {
$(SELECTORS.SELECTCONTEXT).removeAttr('checked');
}
});
};
/**
* Show the confirmation dialogue.
*
* @param {Array} ids The array of expired context record IDs.
*/
function showConfirmation(ids) {
var keys = [
{
key: 'confirm',
component: 'moodle'
},
{
key: 'confirmcontextdeletion',
component: 'tool_dataprivacy'
}
];
var wsfunction = 'tool_dataprivacy_confirm_contexts_for_deletion';
var modalTitle = '';
Str.get_strings(keys).then(function(langStrings) {
modalTitle = langStrings[0];
var confirmMessage = langStrings[1];
return ModalFactory.create({
title: modalTitle,
body: confirmMessage,
type: ModalFactory.types.SAVE_CANCEL
});
}).then(function(modal) {
modal.setSaveButtonText(modalTitle);
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
// Confirm the request.
var params = {
'ids': ids
};
var request = {
methodname: wsfunction,
args: params
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
window.location.reload();
} else {
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
return modal;
}).done(function(modal) {
modal.show();
}).fail(Notification.exception);
}
return DataDeletionActions;
});
@@ -0,0 +1,318 @@
// 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/>.
/**
* Request actions.
*
* @module tool_dataprivacy/data_registry
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/str', 'core/ajax', 'core/notification', 'core/templates', 'core/modal_factory',
'core/modal_events', 'core/fragment', 'tool_dataprivacy/add_purpose', 'tool_dataprivacy/add_category'],
function($, Str, Ajax, Notification, Templates, ModalFactory, ModalEvents, Fragment, AddPurpose, AddCategory) {
var SELECTORS = {
TREE_NODES: '[data-context-tree-node=1]',
FORM_CONTAINER: '#context-form-container',
};
var DataRegistry = function(systemContextId, initContextLevel, initContextId) {
this.systemContextId = systemContextId;
this.currentContextLevel = initContextLevel;
this.currentContextId = initContextId;
this.init();
};
/**
* @var {int} systemContextId
* @private
*/
DataRegistry.prototype.systemContextId = 0;
/**
* @var {int} currentContextLevel
* @private
*/
DataRegistry.prototype.currentContextLevel = 0;
/**
* @var {int} currentContextId
* @private
*/
DataRegistry.prototype.currentContextId = 0;
/**
* @var {AddPurpose} addpurpose
* @private
*/
DataRegistry.prototype.addpurpose = null;
/**
* @var {AddCategory} addcategory
* @private
*/
DataRegistry.prototype.addcategory = null;
DataRegistry.prototype.init = function() {
// Add purpose and category modals always at system context.
this.addpurpose = AddPurpose.getInstance(this.systemContextId);
this.addcategory = AddCategory.getInstance(this.systemContextId);
var stringKeys = [
{
key: 'changessaved',
component: 'moodle'
}, {
key: 'contextpurposecategorysaved',
component: 'tool_dataprivacy'
}, {
key: 'noblockstoload',
component: 'tool_dataprivacy'
}, {
key: 'noactivitiestoload',
component: 'tool_dataprivacy'
}, {
key: 'nocoursestoload',
component: 'tool_dataprivacy'
}
];
this.strings = Str.get_strings(stringKeys);
this.registerEventListeners();
// Load the default context level form.
if (this.currentContextId) {
this.loadForm('context_form', [this.currentContextId], this.submitContextFormAjax.bind(this));
} else {
this.loadForm('contextlevel_form', [this.currentContextLevel], this.submitContextLevelFormAjax.bind(this));
}
};
DataRegistry.prototype.registerEventListeners = function() {
$(SELECTORS.TREE_NODES).on('click', function(ev) {
ev.preventDefault();
var trigger = $(ev.currentTarget);
// Active node.
$(SELECTORS.TREE_NODES).removeClass('active');
trigger.addClass('active');
var contextLevel = trigger.data('contextlevel');
var contextId = trigger.data('contextid');
if (contextLevel) {
// Context level level.
window.history.pushState({}, null, '?contextlevel=' + contextLevel);
// Remove previous add purpose and category listeners to avoid memory leaks.
this.addpurpose.removeListeners();
this.addcategory.removeListeners();
// Load the context level form.
this.currentContextLevel = contextLevel;
this.loadForm('contextlevel_form', [this.currentContextLevel], this.submitContextLevelFormAjax.bind(this));
} else if (contextId) {
// Context instance level.
window.history.pushState({}, null, '?contextid=' + contextId);
// Remove previous add purpose and category listeners to avoid memory leaks.
this.addpurpose.removeListeners();
this.addcategory.removeListeners();
// Load the context level form.
this.currentContextId = contextId;
this.loadForm('context_form', [this.currentContextId], this.submitContextFormAjax.bind(this));
} else {
// Expandable nodes.
var expandContextId = trigger.data('expandcontextid');
var expandElement = trigger.data('expandelement');
var expanded = trigger.data('expanded');
// Extra checking that there is an expandElement because we remove it after loading 0 branches.
if (expandElement) {
if (!expanded) {
if (trigger.data('loaded') || !expandContextId || !expandElement) {
this.expand(trigger);
} else {
trigger.find('> i').removeClass('fa-plus');
trigger.find('> i').addClass('fa-circle-o-notch fa-spin');
this.loadExtra(trigger, expandContextId, expandElement);
}
} else {
this.collapse(trigger);
}
}
}
}.bind(this));
};
DataRegistry.prototype.removeListeners = function() {
$(SELECTORS.TREE_NODES).off('click');
};
DataRegistry.prototype.loadForm = function(fragmentName, fragmentArgs, formSubmitCallback) {
this.clearForm();
var fragment = Fragment.loadFragment('tool_dataprivacy', fragmentName, this.systemContextId, fragmentArgs);
fragment.done(function(html, js) {
$(SELECTORS.FORM_CONTAINER).html(html);
Templates.runTemplateJS(js);
this.addpurpose.registerEventListeners();
this.addcategory.registerEventListeners();
// We also catch the form submit event and use it to submit the form with ajax.
$(SELECTORS.FORM_CONTAINER).on('submit', 'form', formSubmitCallback);
}.bind(this)).fail(Notification.exception);
};
DataRegistry.prototype.clearForm = function() {
// For the previously loaded form.
Y.use('moodle-core-formchangechecker', function() {
M.core_formchangechecker.reset_form_dirty_state();
});
// Remove previous listeners.
$(SELECTORS.FORM_CONTAINER).off('submit', 'form');
};
/**
* This triggers a form submission, so that any mform elements can do final tricks before the form submission is processed.
*
* @method submitForm
* @param {Event} e Form submission event.
* @private
*/
DataRegistry.prototype.submitForm = function(e) {
e.preventDefault();
$(SELECTORS.FORM_CONTAINER).find('form').submit();
};
DataRegistry.prototype.submitContextLevelFormAjax = function(e) {
this.submitFormAjax(e, 'tool_dataprivacy_set_contextlevel_form');
};
DataRegistry.prototype.submitContextFormAjax = function(e) {
this.submitFormAjax(e, 'tool_dataprivacy_set_context_form');
};
DataRegistry.prototype.submitFormAjax = function(e, saveMethodName) {
// We don't want to do a real form submission.
e.preventDefault();
// Convert all the form elements values to a serialised string.
var formData = $(SELECTORS.FORM_CONTAINER).find('form').serialize();
return this.strings.then(function(strings) {
Ajax.call([{
methodname: saveMethodName,
args: {jsonformdata: JSON.stringify(formData)},
done: function() {
Notification.alert(strings[0], strings[1]);
},
fail: Notification.exception
}]);
return;
}).catch(Notification.exception);
};
DataRegistry.prototype.loadExtra = function(parentNode, expandContextId, expandElement) {
Ajax.call([{
methodname: 'tool_dataprivacy_tree_extra_branches',
args: {
contextid: expandContextId,
element: expandElement,
},
done: function(data) {
if (data.branches.length == 0) {
this.noElements(parentNode, expandElement);
return;
}
Templates.render('tool_dataprivacy/context_tree_branches', data)
.then(function(html) {
parentNode.after(html);
this.removeListeners();
this.registerEventListeners();
this.expand(parentNode);
parentNode.data('loaded', 1);
return;
}.bind(this))
.fail(Notification.exception);
}.bind(this),
fail: Notification.exception
}]);
};
DataRegistry.prototype.noElements = function(node, expandElement) {
node.data('expandcontextid', '');
node.data('expandelement', '');
this.strings.then(function(strings) {
// 2 = blocks, 3 = activities, 4 = courses (although courses is not likely really).
var key = 2;
if (expandElement == 'module') {
key = 3;
} else if (expandElement == 'course') {
key = 4;
}
node.text(strings[key]);
return;
}).fail(Notification.exception);
};
DataRegistry.prototype.collapse = function(node) {
node.data('expanded', 0);
node.siblings('nav').addClass('hidden');
node.find('> i').removeClass('fa-minus');
node.find('> i').addClass('fa-plus');
};
DataRegistry.prototype.expand = function(node) {
node.data('expanded', 1);
node.siblings('nav').removeClass('hidden');
node.find('> i').removeClass('fa-plus');
// Also remove the spinning one if data was just loaded.
node.find('> i').removeClass('fa-circle-o-notch fa-spin');
node.find('> i').addClass('fa-minus');
};
return /** @alias module:tool_dataprivacy/data_registry */ {
/**
* Initialise the page.
*
* @param {Number} systemContextId
* @param {Number} initContextLevel
* @param {Number} initContextId
* @return {DataRegistry}
*/
init: function(systemContextId, initContextLevel, initContextId) {
return new DataRegistry(systemContextId, initContextLevel, initContextId);
}
};
}
);
@@ -0,0 +1,98 @@
// 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/>.
/**
* Request actions.
*
* @module tool_dataprivacy/data_request_modal
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/modal', 'core/modal_registry',
'tool_dataprivacy/events'],
function($, Notification, CustomEvents, Modal, ModalRegistry, DataPrivacyEvents) {
var registered = false;
var SELECTORS = {
APPROVE_BUTTON: '[data-action="approve"]',
DENY_BUTTON: '[data-action="deny"]',
COMPLETE_BUTTON: '[data-action="complete"]'
};
/**
* Constructor for the Modal.
*
* @param {object} root The root jQuery element for the modal
*/
var ModalDataRequest = function(root) {
Modal.call(this, root);
};
ModalDataRequest.TYPE = 'tool_dataprivacy-data_request';
ModalDataRequest.TYPE_ENQUIRY = 'tool_dataprivacy-complete_request';
ModalDataRequest.prototype = Object.create(Modal.prototype);
ModalDataRequest.prototype.constructor = ModalDataRequest;
/**
* Set up all of the event handling for the modal.
*
* @method registerEventListeners
*/
ModalDataRequest.prototype.registerEventListeners = function() {
// Apply parent event listeners.
Modal.prototype.registerEventListeners.call(this);
this.getModal().on(CustomEvents.events.activate, SELECTORS.APPROVE_BUTTON, function(e, data) {
var approveEvent = $.Event(DataPrivacyEvents.approve);
this.getRoot().trigger(approveEvent, this);
if (!approveEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
this.getModal().on(CustomEvents.events.activate, SELECTORS.DENY_BUTTON, function(e, data) {
var denyEvent = $.Event(DataPrivacyEvents.deny);
this.getRoot().trigger(denyEvent, this);
if (!denyEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
this.getModal().on(CustomEvents.events.activate, SELECTORS.COMPLETE_BUTTON, function(e, data) {
var completeEvent = $.Event(DataPrivacyEvents.complete);
this.getRoot().trigger(completeEvent, this);
if (!completeEvent.isDefaultPrevented()) {
this.hide();
data.originalEvent.preventDefault();
}
}.bind(this));
};
// Automatically register with the modal registry the first time this module is imported so that you can create modals
// of this type using the modal factory.
if (!registered) {
ModalRegistry.register(ModalDataRequest.TYPE, ModalDataRequest, 'tool_dataprivacy/data_request_modal');
ModalRegistry.register(ModalDataRequest.TYPE_ENQUIRY, ModalDataRequest, 'tool_dataprivacy/mark_request_complete_modal');
registered = true;
}
return ModalDataRequest;
});
@@ -0,0 +1,315 @@
// 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 data registry defaults actions.
*
* @module tool_dataprivacy/defaultsactions
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/modal_factory',
'core/modal_events',
'core/templates'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
/**
* List of action selectors.
*
* @type {{EDIT_LEVEL_DEFAULTS: string}}
* @type {{NEW_ACTIVITY_DEFAULTS: string}}
* @type {{EDIT_ACTIVITY_DEFAULTS: string}}
* @type {{DELETE_ACTIVITY_DEFAULTS: string}}
*/
var ACTIONS = {
EDIT_LEVEL_DEFAULTS: '[data-action="edit-level-defaults"]',
NEW_ACTIVITY_DEFAULTS: '[data-action="new-activity-defaults"]',
EDIT_ACTIVITY_DEFAULTS: '[data-action="edit-activity-defaults"]',
DELETE_ACTIVITY_DEFAULTS: '[data-action="delete-activity-defaults"]'
};
/** @type {{INHERIT: Number}} **/
var INHERIT = -1;
/**
* DefaultsActions class.
*/
var DefaultsActions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
DefaultsActions.prototype.registerEvents = function() {
$(ACTIONS.EDIT_LEVEL_DEFAULTS).click(function(e) {
e.preventDefault();
var button = $(this);
var contextLevel = button.data('contextlevel');
var category = button.data('category');
var purpose = button.data('purpose');
// Get options.
var requests = [
{methodname: 'tool_dataprivacy_get_category_options', args: {}},
{methodname: 'tool_dataprivacy_get_purpose_options', args: {}}
];
var promises = Ajax.call(requests);
var titlePromise = Str.get_string('editdefaults', 'tool_dataprivacy', $('#defaults-header').text());
$.when(promises[0], promises[1], titlePromise).then(function(categoryResponse, purposeResponse, title) {
var categories = categoryResponse.options;
var purposes = purposeResponse.options;
showDefaultsFormModal(title, contextLevel, category, purpose, null, categories, purposes, null);
return true;
}).catch(Notification.exception);
});
$(ACTIONS.NEW_ACTIVITY_DEFAULTS).click(function(e) {
e.preventDefault();
var button = $(this);
var contextLevel = button.data('contextlevel');
// Get options.
var requests = [
{methodname: 'tool_dataprivacy_get_category_options', args: {}},
{methodname: 'tool_dataprivacy_get_purpose_options', args: {}},
{methodname: 'tool_dataprivacy_get_activity_options', args: {'nodefaults': true}}
];
var promises = Ajax.call(requests);
var titlePromise = Str.get_string('addnewdefaults', 'tool_dataprivacy');
$.when(promises[0], promises[1], promises[2], titlePromise).then(
function(categoryResponse, purposeResponse, activityResponse, title) {
var categories = categoryResponse.options;
var purposes = purposeResponse.options;
var activities = activityResponse.options;
showDefaultsFormModal(title, contextLevel, null, null, null, categories, purposes, activities);
return true;
}).catch(Notification.exception);
}
);
$(ACTIONS.EDIT_ACTIVITY_DEFAULTS).click(function(e) {
e.preventDefault();
var button = $(this);
var contextLevel = button.data('contextlevel');
var category = button.data('category');
var purpose = button.data('purpose');
var activity = button.data('activityname');
// Get options.
var requests = [
{methodname: 'tool_dataprivacy_get_category_options', args: {}},
{methodname: 'tool_dataprivacy_get_purpose_options', args: {}},
{methodname: 'tool_dataprivacy_get_activity_options', args: {}}
];
var promises = Ajax.call(requests);
var titlePromise = Str.get_string('editmoduledefaults', 'tool_dataprivacy');
$.when(promises[0], promises[1], promises[2], titlePromise).then(
function(categoryResponse, purposeResponse, activityResponse, title) {
var categories = categoryResponse.options;
var purposes = purposeResponse.options;
var activities = activityResponse.options;
showDefaultsFormModal(title, contextLevel, category, purpose, activity, categories, purposes, activities);
return true;
}).catch(Notification.exception);
}
);
$(ACTIONS.DELETE_ACTIVITY_DEFAULTS).click(function(e) {
e.preventDefault();
var button = $(this);
var contextLevel = button.data('contextlevel');
var activity = button.data('activityname');
var activityDisplayName = button.data('activitydisplayname');
// Set category and purpose to inherit (-1).
var category = INHERIT;
var purpose = INHERIT;
ModalFactory.create({
title: Str.get_string('deletedefaults', 'tool_dataprivacy', activityDisplayName),
body: Templates.render('tool_dataprivacy/delete_activity_defaults', {"activityname": activityDisplayName}),
type: ModalFactory.types.SAVE_CANCEL,
large: true
}).then(function(modal) {
modal.setSaveButtonText(Str.get_string('delete'));
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
setContextDefaults(contextLevel, category, purpose, activity, false);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
modal.show();
return true;
}).catch(Notification.exception);
});
};
/**
* Prepares and renders the modal for setting the defaults for the given context level/plugin.
*
* @param {String} title The modal's title.
* @param {Number} contextLevel The context level to set defaults for.
* @param {Number} category The current category ID.
* @param {Number} purpose The current purpose ID.
* @param {String} activity The plugin name of the activity. Optional.
* @param {Array} categoryOptions The list of category options.
* @param {Array} purposeOptions The list of purpose options.
* @param {Array} activityOptions The list of activity options. Optional.
*/
function showDefaultsFormModal(title, contextLevel, category, purpose, activity,
categoryOptions, purposeOptions, activityOptions) {
if (category !== null) {
categoryOptions.forEach(function(currentValue) {
if (currentValue.id === category) {
currentValue.selected = true;
}
});
}
if (purpose !== null) {
purposeOptions.forEach(function(currentValue) {
if (currentValue.id === purpose) {
currentValue.selected = true;
}
});
}
var templateContext = {
"contextlevel": contextLevel,
"categoryoptions": categoryOptions,
"purposeoptions": purposeOptions
};
// Check the activityOptions parameter that was passed.
if (activityOptions !== null && activityOptions.length) {
// Check the activity parameter that was passed.
if (activity === null) {
// We're setting a new defaults for a module.
templateContext.newactivitydefaults = true;
} else {
// Edit mode. Set selection.
activityOptions.forEach(function(currentValue) {
if (activity === currentValue.name) {
currentValue.selected = true;
}
});
}
templateContext.modemodule = true;
templateContext.activityoptions = activityOptions;
}
ModalFactory.create({
title: title,
body: Templates.render('tool_dataprivacy/category_purpose_form', templateContext),
type: ModalFactory.types.SAVE_CANCEL,
large: true
}).then(function(modal) {
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
var activity = $('#activity');
var activityVal = typeof activity !== 'undefined' ? activity.val() : null;
var override = $('#override');
var overrideVal = typeof override !== 'undefined' ? override.is(':checked') : false;
setContextDefaults($('#contextlevel').val(), $('#category').val(), $('#purpose').val(), activityVal, overrideVal);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
modal.show();
return modal;
}).catch(Notification.exception);
}
/**
* Calls a the tool_dataprivacy_set_context_defaults WS function.
*
* @param {Number} contextLevel The context level.
* @param {Number} category The category ID.
* @param {Number} purpose The purpose ID.
* @param {String} activity The plugin name of the activity module.
* @param {Boolean} override Whether to override custom instances.
*/
function setContextDefaults(contextLevel, category, purpose, activity, override) {
var request = {
methodname: 'tool_dataprivacy_set_context_defaults',
args: {
'contextlevel': contextLevel,
'category': category,
'purpose': purpose,
'override': override,
'activity': activity
}
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
window.location.reload();
}
});
}
return /** @alias module:tool_dataprivacy/defaultsactions */ {
// Public variables and functions.
/**
* Initialise the module.
*
* @method init
* @return {DefaultsActions}
*/
'init': function() {
return new DefaultsActions();
}
};
});
@@ -0,0 +1,92 @@
// 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/>.
/**
* Module to update the displayed retention period.
*
* @module tool_dataprivacy/effective_retention_period
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery'],
function($) {
var SELECTORS = {
PURPOSE_SELECT: '#id_purposeid',
RETENTION_FIELD_BOOST: '#id_error_retention_current',
RETENTION_FIELD_CLEAN: '#fitem_id_retention_current [data-fieldtype=static]',
};
/**
* Constructor for the retention period display.
*
* @param {Array} purposeRetentionPeriods Associative array of purposeids with effective retention period at this context
*/
var EffectiveRetentionPeriod = function(purposeRetentionPeriods) {
this.purposeRetentionPeriods = purposeRetentionPeriods;
this.registerEventListeners();
};
/**
* Removes the current 'change' listeners.
*
* Useful when a new form is loaded.
*/
var removeListeners = function() {
$(SELECTORS.PURPOSE_SELECT).off('change');
};
/**
* @var {Array} purposeRetentionPeriods
* @private
*/
EffectiveRetentionPeriod.prototype.purposeRetentionPeriods = [];
/**
* Add purpose change listeners.
*
* @method registerEventListeners
*/
EffectiveRetentionPeriod.prototype.registerEventListeners = function() {
$(SELECTORS.PURPOSE_SELECT).on('change', function(ev) {
var selected = $(ev.currentTarget).val();
var selectedPurpose = this.purposeRetentionPeriods[selected];
var cleanSelector = $(SELECTORS.RETENTION_FIELD_CLEAN);
if (cleanSelector.length > 0) {
cleanSelector.text(selectedPurpose);
} else {
var boostSelector = $(SELECTORS.RETENTION_FIELD_BOOST);
var retentionField = boostSelector.siblings();
if (retentionField.length > 0) {
retentionField.text(selectedPurpose);
}
}
}.bind(this));
};
return /** @alias module:tool_dataprivacy/effective_retention_period */ {
init: function(purposeRetentionPeriods) {
// Remove previously attached listeners.
removeListeners();
return new EffectiveRetentionPeriod(purposeRetentionPeriods);
}
};
}
);
+33
View File
@@ -0,0 +1,33 @@
// 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/>.
/**
* Contain the events the data privacy tool can fire.
*
* @module tool_dataprivacy/events
* @class events
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([], function() {
return {
approve: 'tool_dataprivacy-data_request:approve',
bulkApprove: 'tool_dataprivacy-data_request:bulk_approve',
deny: 'tool_dataprivacy-data_request:deny',
bulkDeny: 'tool_dataprivacy-data_request:bulk_deny',
complete: 'tool_dataprivacy-data_request:complete'
};
});
@@ -0,0 +1,88 @@
// 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/>.
/**
* Potential user selector module.
*
* @module tool_dataprivacy/expand_contract
* @class page-expand-contract
* @package tool_dataprivacy
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/url', 'core/str'], function($, url, str) {
var expandedImage = $('<img alt="" src="' + url.imageUrl('t/expanded') + '"/>');
var collapsedImage = $('<img alt="" src="' + url.imageUrl('t/collapsed') + '"/>');
return /** @alias module:tool_dataprivacy/expand-collapse */ {
/**
* Expand or collapse a selected node.
*
* @param {object} targetnode The node that we want to expand / collapse
* @param {object} thisnode The node that was clicked.
*/
expandCollapse: function(targetnode, thisnode) {
if (targetnode.hasClass('hide')) {
targetnode.removeClass('hide');
targetnode.addClass('visible');
targetnode.attr('aria-expanded', true);
thisnode.find(':header i.fa').removeClass('fa-plus-square');
thisnode.find(':header i.fa').addClass('fa-minus-square');
thisnode.find(':header img.icon').attr('src', expandedImage.attr('src'));
} else {
targetnode.removeClass('visible');
targetnode.addClass('hide');
targetnode.attr('aria-expanded', false);
thisnode.find(':header i.fa').removeClass('fa-minus-square');
thisnode.find(':header i.fa').addClass('fa-plus-square');
thisnode.find(':header img.icon').attr('src', collapsedImage.attr('src'));
}
},
/**
* Expand or collapse all nodes on this page.
*
* @param {string} nextstate The next state to change to.
*/
expandCollapseAll: function(nextstate) {
var currentstate = (nextstate == 'visible') ? 'hide' : 'visible';
var ariaexpandedstate = (nextstate == 'visible') ? true : false;
var iconclassnow = (nextstate == 'visible') ? 'fa-plus-square' : 'fa-minus-square';
var iconclassnext = (nextstate == 'visible') ? 'fa-minus-square' : 'fa-plus-square';
var imagenow = (nextstate == 'visible') ? expandedImage.attr('src') : collapsedImage.attr('src');
$('.' + currentstate).each(function() {
$(this).removeClass(currentstate);
$(this).addClass(nextstate);
$(this).attr('aria-expanded', ariaexpandedstate);
});
$('.tool_dataprivacy-expand-all').data('visibilityState', currentstate);
str.get_string(currentstate, 'tool_dataprivacy').then(function(langString) {
$('.tool_dataprivacy-expand-all').html(langString);
return;
}).catch(Notification.exception);
$(':header i.fa').each(function() {
$(this).removeClass(iconclassnow);
$(this).addClass(iconclassnext);
});
$(':header img.icon').each(function() {
$(this).attr('src', imagenow);
});
}
};
});
@@ -0,0 +1,76 @@
// 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/>.
/**
* Potential user selector module.
*
* @module tool_dataprivacy/form-user-selector
* @class form-user-selector
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax', 'core/templates'], function($, Ajax, Templates) {
return /** @alias module:tool_dataprivacy/form-user-selector */ {
processResults: function(selector, results) {
var users = [];
$.each(results, function(index, user) {
users.push({
value: user.id,
label: user._label
});
});
return users;
},
transport: function(selector, query, success, failure) {
var promise;
promise = Ajax.call([{
methodname: 'tool_dataprivacy_get_users',
args: {
query: query
}
}]);
promise[0].then(function(results) {
var promises = [],
i = 0;
// Render the label.
$.each(results, function(index, user) {
promises.push(Templates.render('tool_dataprivacy/form-user-selector-suggestion', user));
});
// Apply the label to the results.
return $.when.apply($.when, promises).then(function() {
var args = arguments;
$.each(results, function(index, user) {
user._label = args[i];
i++;
});
success(results);
return;
});
}).fail(failure);
}
};
});
@@ -0,0 +1,221 @@
// 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 to enable users to manage their own data requests.
*
* @module tool_dataprivacy/myrequestactions
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/modal_factory',
'core/modal_events',
'core/templates'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates) {
/**
* List of action selectors.
*
* @type {{CANCEL_REQUEST: string}}
* @type {{CONTACT_DPO: string}}
*/
var ACTIONS = {
CANCEL_REQUEST: '[data-action="cancel"]',
CONTACT_DPO: '[data-action="contactdpo"]',
};
/**
* MyRequestActions class.
*/
var MyRequestActions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
MyRequestActions.prototype.registerEvents = function() {
$(ACTIONS.CANCEL_REQUEST).click(function(e) {
e.preventDefault();
var requestId = $(this).data('requestid');
var stringkeys = [
{
key: 'cancelrequest',
component: 'tool_dataprivacy'
},
{
key: 'cancelrequestconfirmation',
component: 'tool_dataprivacy'
}
];
Str.get_strings(stringkeys).then(function(langStrings) {
var title = langStrings[0];
var confirmMessage = langStrings[1];
return ModalFactory.create({
title: title,
body: confirmMessage,
type: ModalFactory.types.SAVE_CANCEL
}).then(function(modal) {
modal.setSaveButtonText(title);
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
// Cancel the request.
var params = {
'requestid': requestId
};
var request = {
methodname: 'tool_dataprivacy_cancel_data_request',
args: params
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
window.location.reload();
} else {
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
return modal;
});
}).done(function(modal) {
// Show the modal!
modal.show();
}).fail(Notification.exception);
});
$(ACTIONS.CONTACT_DPO).click(function(e) {
e.preventDefault();
var replyToEmail = $(this).data('replytoemail');
var keys = [
{
key: 'contactdataprotectionofficer',
component: 'tool_dataprivacy'
},
{
key: 'send',
component: 'tool_dataprivacy'
},
];
var sendButtonText = '';
Str.get_strings(keys).then(function(langStrings) {
var modalTitle = langStrings[0];
sendButtonText = langStrings[1];
var context = {
'replytoemail': replyToEmail
};
return ModalFactory.create({
title: modalTitle,
body: Templates.render('tool_dataprivacy/contact_dpo', context),
type: ModalFactory.types.SAVE_CANCEL,
large: true
});
}).done(function(modal) {
modal.setSaveButtonText(sendButtonText);
// Handle send event.
modal.getRoot().on(ModalEvents.save, function(e) {
var message = $('#message').val().trim();
if (message.length === 0) {
e.preventDefault();
// Show validation error when the message is empty.
$('[data-region="messageinput"]').addClass('has-danger notifyproblem');
$('#id_error_message').removeAttr('hidden');
} else {
// Send the message.
sendMessageToDPO(message);
}
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
// Show the modal!
modal.show();
}).fail(Notification.exception);
});
};
/**
* Send message to the Data Protection Officer.
*
* @param {String} message The message to send.
*/
function sendMessageToDPO(message) {
var request = {
methodname: 'tool_dataprivacy_contact_dpo',
args: {
message: message
}
};
var requestType = 'success';
Ajax.call([request])[0].then(function(data) {
if (data.result) {
return Str.get_string('requestsubmitted', 'tool_dataprivacy');
}
requestType = 'error';
return data.warnings.join('<br>');
}).done(function(message) {
Notification.addNotification({
message: message,
type: requestType
});
}).fail(Notification.exception);
}
return /** @alias module:tool_dataprivacy/myrequestactions */ {
// Public variables and functions.
/**
* Initialise the unified user filter.
*
* @method init
* @return {MyRequestActions}
*/
'init': function() {
return new MyRequestActions();
}
};
});
@@ -0,0 +1,132 @@
// 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 purposes actions.
*
* @module tool_dataprivacy/purposesactions
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/modal_factory',
'core/modal_events'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents) {
/**
* List of action selectors.
*
* @type {{DELETE: string}}
*/
var ACTIONS = {
DELETE: '[data-action="deletepurpose"]',
};
/**
* PurposesActions class.
*/
var PurposesActions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
PurposesActions.prototype.registerEvents = function() {
$(ACTIONS.DELETE).click(function(e) {
e.preventDefault();
var id = $(this).data('id');
var purposename = $(this).data('name');
var stringkeys = [
{
key: 'deletepurpose',
component: 'tool_dataprivacy'
},
{
key: 'deletepurposetext',
component: 'tool_dataprivacy',
param: purposename
},
{
key: 'delete'
}
];
Str.get_strings(stringkeys).then(function(langStrings) {
var title = langStrings[0];
var confirmMessage = langStrings[1];
var buttonText = langStrings[2];
return ModalFactory.create({
title: title,
body: confirmMessage,
type: ModalFactory.types.SAVE_CANCEL
}).then(function(modal) {
modal.setSaveButtonText(buttonText);
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
var request = {
methodname: 'tool_dataprivacy_delete_purpose',
args: {'id': id}
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
$('tr[data-purposeid="' + id + '"]').remove();
} else {
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
return modal;
});
}).done(function(modal) {
modal.show();
}).fail(Notification.exception);
});
};
return /** @alias module:tool_dataprivacy/purposesactions */ {
// Public variables and functions.
/**
* Initialise the module.
*
* @method init
* @return {PurposesActions}
*/
'init': function() {
return new PurposesActions();
}
};
});
@@ -0,0 +1,84 @@
// 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/>.
/**
* JS module for the data requests filter.
*
* @module tool_dataprivacy/request_filter
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/form-autocomplete', 'core/str', 'core/notification'], function($, Autocomplete, Str, Notification) {
/**
* Selectors.
*
* @access private
* @type {{REQUEST_FILTERS: string}}
*/
var SELECTORS = {
REQUEST_FILTERS: '#request-filters'
};
/**
* Init function.
*
* @method init
* @private
*/
var init = function() {
var stringkeys = [
{
key: 'filter',
component: 'moodle'
},
{
key: 'nofiltersapplied',
component: 'tool_dataprivacy'
}
];
Str.get_strings(stringkeys).then(function(langstrings) {
var placeholder = langstrings[0];
var noSelectionString = langstrings[1];
return Autocomplete.enhance(SELECTORS.REQUEST_FILTERS, false, '', placeholder, false, true, noSelectionString, true);
}).fail(Notification.exception);
var last = $(SELECTORS.REQUEST_FILTERS).val();
$(SELECTORS.REQUEST_FILTERS).on('change', function() {
var current = $(this).val();
// Prevent form from submitting unnecessarily, eg. on blur when no filter is selected.
if (last.join(',') !== current.join(',')) {
// If we're submitting without filters, set the hidden input 'filters-cleared' to 1.
if (current.length === 0) {
$('#filters-cleared').val(1);
}
$(this.form).submit();
}
});
};
return /** @alias module:core/form-autocomplete */ {
/**
* Initialise the unified user filter.
*
* @method init
*/
init: function() {
init();
}
};
});
@@ -0,0 +1,443 @@
// 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/>.
/**
* Request actions.
*
* @module tool_dataprivacy/requestactions
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([
'jquery',
'core/ajax',
'core/notification',
'core/str',
'core/modal_factory',
'core/modal_events',
'core/templates',
'tool_dataprivacy/data_request_modal',
'tool_dataprivacy/events'],
function($, Ajax, Notification, Str, ModalFactory, ModalEvents, Templates, ModalDataRequest, DataPrivacyEvents) {
/**
* List of action selectors.
*
* @type {{APPROVE_REQUEST: string}}
* @type {{DENY_REQUEST: string}}
* @type {{VIEW_REQUEST: string}}
* @type {{MARK_COMPLETE: string}}
* @type {{CHANGE_BULK_ACTION: string}}
* @type {{CONFIRM_BULK_ACTION: string}}
* @type {{SELECT_ALL: string}}
*/
var ACTIONS = {
APPROVE_REQUEST: '[data-action="approve"]',
DENY_REQUEST: '[data-action="deny"]',
VIEW_REQUEST: '[data-action="view"]',
MARK_COMPLETE: '[data-action="complete"]',
CHANGE_BULK_ACTION: '[id="bulk-action"]',
CONFIRM_BULK_ACTION: '[id="confirm-bulk-action"]',
SELECT_ALL: '[data-action="selectall"]'
};
/**
* List of available bulk actions.
*
* @type {{APPROVE: number}}
* @type {{DENY: number}}
*/
var BULK_ACTIONS = {
APPROVE: 1,
DENY: 2
};
/**
* List of selectors.
*
* @type {{SELECT_REQUEST: string}}
*/
var SELECTORS = {
SELECT_REQUEST: '.selectrequests'
};
/**
* RequestActions class.
*/
var RequestActions = function() {
this.registerEvents();
};
/**
* Register event listeners.
*/
RequestActions.prototype.registerEvents = function() {
$(ACTIONS.VIEW_REQUEST).click(function(e) {
e.preventDefault();
var requestId = $(this).data('requestid');
// Cancel the request.
var params = {
'requestid': requestId
};
var request = {
methodname: 'tool_dataprivacy_get_data_request',
args: params
};
var promises = Ajax.call([request]);
$.when(promises[0]).then(function(data) {
if (data.result) {
return data.result;
}
// Fail.
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
return false;
}).then(function(data) {
// Determine the type of modal to show.
var modalType = ModalFactory.types.DEFAULT;
if (data.approvedeny) {
modalType = ModalDataRequest.TYPE;
} else if (data.canmarkcomplete) {
modalType = ModalDataRequest.TYPE_ENQUIRY;
}
var body = Templates.render('tool_dataprivacy/request_details', data);
return ModalFactory.create({
title: data.typename,
body: body,
type: modalType,
large: true
});
}).then(function(modal) {
// Handle approve event.
modal.getRoot().on(DataPrivacyEvents.approve, function() {
showConfirmation(DataPrivacyEvents.approve, approveEventWsData(requestId));
});
// Handle deny event.
modal.getRoot().on(DataPrivacyEvents.deny, function() {
showConfirmation(DataPrivacyEvents.deny, denyEventWsData(requestId));
});
// Handle send event.
modal.getRoot().on(DataPrivacyEvents.complete, function() {
var params = {
'requestid': requestId
};
handleSave('tool_dataprivacy_mark_complete', params);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
// Show the modal!
modal.show();
return;
}).catch(Notification.exception);
});
$(ACTIONS.APPROVE_REQUEST).click(function(e) {
e.preventDefault();
var requestId = $(this).data('requestid');
showConfirmation(DataPrivacyEvents.approve, approveEventWsData(requestId));
});
$(ACTIONS.DENY_REQUEST).click(function(e) {
e.preventDefault();
var requestId = $(this).data('requestid');
showConfirmation(DataPrivacyEvents.deny, denyEventWsData(requestId));
});
$(ACTIONS.MARK_COMPLETE).click(function(e) {
e.preventDefault();
var requestId = $(this).data('requestid');
showConfirmation(DataPrivacyEvents.complete, completeEventWsData(requestId));
});
$(ACTIONS.CONFIRM_BULK_ACTION).click(function() {
var requestIds = [];
var actionEvent = '';
var wsdata = {};
var bulkActionKeys = [
{
key: 'selectbulkaction',
component: 'tool_dataprivacy'
},
{
key: 'selectdatarequests',
component: 'tool_dataprivacy'
},
{
key: 'ok'
}
];
var bulkaction = parseInt($('#bulk-action').val());
if (bulkaction != BULK_ACTIONS.APPROVE && bulkaction != BULK_ACTIONS.DENY) {
Str.get_strings(bulkActionKeys).done(function(langStrings) {
Notification.alert('', langStrings[0], langStrings[2]);
}).fail(Notification.exception);
return;
}
$(".selectrequests:checked").each(function() {
requestIds.push($(this).val());
});
if (requestIds.length < 1) {
Str.get_strings(bulkActionKeys).done(function(langStrings) {
Notification.alert('', langStrings[1], langStrings[2]);
}).fail(Notification.exception);
return;
}
switch (bulkaction) {
case BULK_ACTIONS.APPROVE:
actionEvent = DataPrivacyEvents.bulkApprove;
wsdata = bulkApproveEventWsData(requestIds);
break;
case BULK_ACTIONS.DENY:
actionEvent = DataPrivacyEvents.bulkDeny;
wsdata = bulkDenyEventWsData(requestIds);
}
showConfirmation(actionEvent, wsdata);
});
$(ACTIONS.SELECT_ALL).change(function(e) {
e.preventDefault();
var selectAll = $(this).is(':checked');
$(SELECTORS.SELECT_REQUEST).prop('checked', selectAll);
});
};
/**
* Return the webservice data for the approve request action.
*
* @param {Number} requestId The ID of the request.
* @return {Object}
*/
function approveEventWsData(requestId) {
return {
'wsfunction': 'tool_dataprivacy_approve_data_request',
'wsparams': {'requestid': requestId}
};
}
/**
* Return the webservice data for the bulk approve request action.
*
* @param {Array} requestIds The array of request ID's.
* @return {Object}
*/
function bulkApproveEventWsData(requestIds) {
return {
'wsfunction': 'tool_dataprivacy_bulk_approve_data_requests',
'wsparams': {'requestids': requestIds}
};
}
/**
* Return the webservice data for the deny request action.
*
* @param {Number} requestId The ID of the request.
* @return {Object}
*/
function denyEventWsData(requestId) {
return {
'wsfunction': 'tool_dataprivacy_deny_data_request',
'wsparams': {'requestid': requestId}
};
}
/**
* Return the webservice data for the bulk deny request action.
*
* @param {Array} requestIds The array of request ID's.
* @return {Object}
*/
function bulkDenyEventWsData(requestIds) {
return {
'wsfunction': 'tool_dataprivacy_bulk_deny_data_requests',
'wsparams': {'requestids': requestIds}
};
}
/**
* Return the webservice data for the complete request action.
*
* @param {Number} requestId The ID of the request.
* @return {Object}
*/
function completeEventWsData(requestId) {
return {
'wsfunction': 'tool_dataprivacy_mark_complete',
'wsparams': {'requestid': requestId}
};
}
/**
* Show the confirmation dialogue.
*
* @param {String} action The action name.
* @param {Object} wsdata Object containing ws data.
*/
function showConfirmation(action, wsdata) {
var keys = [];
switch (action) {
case DataPrivacyEvents.approve:
keys = [
{
key: 'approverequest',
component: 'tool_dataprivacy'
},
{
key: 'confirmapproval',
component: 'tool_dataprivacy'
}
];
break;
case DataPrivacyEvents.bulkApprove:
keys = [
{
key: 'bulkapproverequests',
component: 'tool_dataprivacy'
},
{
key: 'confirmbulkapproval',
component: 'tool_dataprivacy'
}
];
break;
case DataPrivacyEvents.deny:
keys = [
{
key: 'denyrequest',
component: 'tool_dataprivacy'
},
{
key: 'confirmdenial',
component: 'tool_dataprivacy'
}
];
break;
case DataPrivacyEvents.bulkDeny:
keys = [
{
key: 'bulkdenyrequests',
component: 'tool_dataprivacy'
},
{
key: 'confirmbulkdenial',
component: 'tool_dataprivacy'
}
];
break;
case DataPrivacyEvents.complete:
keys = [
{
key: 'markcomplete',
component: 'tool_dataprivacy'
},
{
key: 'confirmcompletion',
component: 'tool_dataprivacy'
}
];
break;
}
var modalTitle = '';
Str.get_strings(keys).then(function(langStrings) {
modalTitle = langStrings[0];
var confirmMessage = langStrings[1];
return ModalFactory.create({
title: modalTitle,
body: confirmMessage,
type: ModalFactory.types.SAVE_CANCEL
});
}).then(function(modal) {
modal.setSaveButtonText(modalTitle);
// Handle save event.
modal.getRoot().on(ModalEvents.save, function() {
handleSave(wsdata.wsfunction, wsdata.wsparams);
});
// Handle hidden event.
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
});
modal.show();
return;
}).catch(Notification.exception);
}
/**
* Calls a web service function and reloads the page on success and shows a notification.
* Displays an error notification, otherwise.
*
* @param {String} wsfunction The web service function to call.
* @param {Object} params The parameters for the web service functoon.
*/
function handleSave(wsfunction, params) {
// Confirm the request.
var request = {
methodname: wsfunction,
args: params
};
Ajax.call([request])[0].done(function(data) {
if (data.result) {
// On success, reload the page so that the data request table will be updated.
// TODO: Probably in the future, better to reload the table or the target data request via AJAX.
window.location.reload();
} else {
// Add the notification.
Notification.addNotification({
message: data.warnings[0].message,
type: 'error'
});
}
}).fail(Notification.exception);
}
return RequestActions;
});
+42
View File
@@ -0,0 +1,42 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This page lets users manage categories.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../../config.php');
require_login(null, false);
$url = new moodle_url("/admin/tool/dataprivacy/categories.php");
$title = get_string('editcategories', 'tool_dataprivacy');
\tool_dataprivacy\page_helper::setup($url, $title, 'dataregistry');
$output = $PAGE->get_renderer('tool_dataprivacy');
echo $output->header();
echo $output->heading($title);
$categories = \tool_dataprivacy\api::get_categories();
$renderable = new \tool_dataprivacy\output\categories($categories);
echo $output->render($renderable);
echo $output->footer();
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,91 @@
<?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/>.
/**
* Class for loading/storing data categories from the DB.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');
/**
* Class for loading/storing data categories from the DB.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class category extends \core\persistent {
/**
* Database table.
*/
const TABLE = 'tool_dataprivacy_category';
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return array(
'name' => array(
'type' => PARAM_TEXT,
'description' => 'The category name.',
),
'description' => array(
'type' => PARAM_RAW,
'description' => 'The category description.',
'null' => NULL_ALLOWED,
'default' => '',
),
'descriptionformat' => array(
'choices' => array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN),
'type' => PARAM_INT,
'default' => FORMAT_HTML
),
);
}
/**
* Is this category used?.
*
* @return null
*/
public function is_used() {
if (\tool_dataprivacy\contextlevel::is_category_used($this->get('id')) ||
\tool_dataprivacy\context_instance::is_category_used($this->get('id'))) {
return true;
}
$pluginconfig = get_config('tool_dataprivacy');
$levels = \context_helper::get_all_levels();
foreach ($levels as $level => $classname) {
list($unused, $categoryvar) = \tool_dataprivacy\data_registry::var_names_from_context($classname);
if (!empty($pluginconfig->{$categoryvar}) && $pluginconfig->{$categoryvar} == $this->get('id')) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,116 @@
<?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/>.
/**
* Class for loading/storing context instances data from the DB.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
/**
* Class for loading/storing context instances data from the DB.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class context_instance extends \core\persistent {
/**
* Database table.
*/
const TABLE = 'tool_dataprivacy_ctxinstance';
/**
* Not set value.
*/
const NOTSET = 0;
/**
* Inherit value.
*/
const INHERIT = -1;
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return array(
'contextid' => array(
'type' => PARAM_INT,
'description' => 'The context id.',
),
'purposeid' => array(
'type' => PARAM_INT,
'description' => 'The purpose id.',
'null' => NULL_ALLOWED,
),
'categoryid' => array(
'type' => PARAM_INT,
'description' => 'The category id.',
'null' => NULL_ALLOWED,
),
);
}
/**
* Returns an instance by contextid.
*
* @param mixed $contextid
* @param mixed $exception
* @return null
*/
public static function get_record_by_contextid($contextid, $exception = true) {
global $DB;
if (!$record = $DB->get_record(self::TABLE, array('contextid' => $contextid))) {
if (!$exception) {
return false;
} else {
throw new \dml_missing_record_exception(self::TABLE);
}
}
return new static(0, $record);
}
/**
* Is the provided purpose used by any context instance?
*
* @param int $purposeid
* @return bool
*/
public static function is_purpose_used($purposeid) {
global $DB;
return $DB->record_exists(self::TABLE, array('purposeid' => $purposeid));
}
/**
* Is the provided category used by any context instance?
*
* @param int $categoryid
* @return bool
*/
public static function is_category_used($categoryid) {
global $DB;
return $DB->record_exists(self::TABLE, array('categoryid' => $categoryid));
}
}
@@ -0,0 +1,140 @@
<?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/>.
/**
* Class for loading/storing context level data from the DB.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
/**
* Class for loading/storing context level data from the DB.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlevel extends \core\persistent {
/**
* Database table.
*/
const TABLE = 'tool_dataprivacy_ctxlevel';
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return array(
'contextlevel' => array(
'type' => PARAM_INT,
'description' => 'The context level.',
),
'purposeid' => array(
'type' => PARAM_INT,
'description' => 'The purpose id.',
),
'categoryid' => array(
'type' => PARAM_INT,
'description' => 'The category id.',
),
);
}
/**
* Returns an instance by contextlevel.
*
* @param mixed $contextlevel
* @param mixed $exception
* @return null
*/
public static function get_record_by_contextlevel($contextlevel, $exception = true) {
global $DB;
$cache = \cache::make('tool_dataprivacy', 'contextlevel');
if ($data = $cache->get($contextlevel)) {
return new static(0, $data);
}
if (!$record = $DB->get_record(self::TABLE, array('contextlevel' => $contextlevel))) {
if (!$exception) {
return false;
} else {
throw new \dml_missing_record_exception(self::TABLE);
}
}
return new static(0, $record);
}
/**
* Is the provided purpose used by any contextlevel?
*
* @param int $purposeid
* @return bool
*/
public static function is_purpose_used($purposeid) {
global $DB;
return $DB->record_exists(self::TABLE, array('purposeid' => $purposeid));
}
/**
* Is the provided category used by any contextlevel?
*
* @param int $categoryid
* @return bool
*/
public static function is_category_used($categoryid) {
global $DB;
return $DB->record_exists(self::TABLE, array('categoryid' => $categoryid));
}
/**
* Adds the new record to the cache.
*
* @return null
*/
protected function after_create() {
$cache = \cache::make('tool_dataprivacy', 'contextlevel');
$cache->set($this->get('contextlevel'), $this->to_record());
}
/**
* Updates the cache record.
*
* @param bool $result
* @return null
*/
protected function after_update($result) {
$cache = \cache::make('tool_dataprivacy', 'contextlevel');
$cache->set($this->get('contextlevel'), $this->to_record());
}
/**
* Removes unnecessary stuff from db.
*
* @return null
*/
protected function before_delete() {
$cache = \cache::make('tool_dataprivacy', 'contextlevel');
$cache->delete($this->get('contextlevel'));
}
}
@@ -0,0 +1,64 @@
<?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/>.
/**
* Contains the contextlist persistent.
*
* @package tool_dataprivacy
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
use core\persistent;
/**
* The contextlist persistent.
*
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist extends persistent {
/** The table name this persistent object maps to. */
const TABLE = 'tool_dataprivacy_contextlist';
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return [
'component' => [
'type' => PARAM_TEXT
]
];
}
/**
* Create a new contextlist persistent from an instance of \core_privacy\local\request\contextlist.
*
* @param \core_privacy\local\request\contextlist $contextlist the core privacy contextlist.
* @return contextlist a contextlist persistent.
*/
public static function from_contextlist(\core_privacy\local\request\contextlist $contextlist) {
$contextlistpersistent = new contextlist();
return $contextlistpersistent->set('component', $contextlist->get_component());
}
}
@@ -0,0 +1,74 @@
<?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/>.
/**
* Contains the contextlist_context persistent.
*
* @package tool_dataprivacy
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
use core\persistent;
/**
* The contextlist_context persistent.
*
* @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlist_context extends persistent {
/** The table name this persistent object maps to. */
const TABLE = 'tool_dataprivacy_ctxlst_ctx';
/** This context is pending approval. */
const STATUS_PENDING = 0;
/** This context has been approved. */
const STATUS_APPROVED = 1;
/** This context has been rejected. */
const STATUS_REJECTED = 2;
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return [
'contextid' => [
'type' => PARAM_INT
],
'contextlistid' => [
'type' => PARAM_INT
],
'status' => [
'choices' => [
self::STATUS_PENDING,
self::STATUS_APPROVED,
self::STATUS_REJECTED,
],
'default' => self::STATUS_PENDING,
'type' => PARAM_INT
]
];
}
}
@@ -0,0 +1,357 @@
<?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/>.
/**
* Data registry business logic methods. Mostly internal stuff.
*
* All methods should be considered part of the internal tool_dataprivacy API
* unless something different is specified.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
use coding_exception;
use core\persistent;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/coursecatlib.php');
/**
* Data registry business logic methods. Mostly internal stuff.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_registry {
/**
* Returns purpose and category var names from a context class name
*
* @param string $classname The context level's class.
* @param string $pluginname The name of the plugin associated with the context level.
* @return string[]
*/
public static function var_names_from_context($classname, $pluginname = '') {
$pluginname = trim($pluginname);
if (!empty($pluginname)) {
$categoryvar = $classname . '_' . $pluginname . '_category';
$purposevar = $classname . '_' . $pluginname . '_purpose';
} else {
$categoryvar = $classname . '_category';
$purposevar = $classname . '_purpose';
}
return [
$purposevar,
$categoryvar
];
}
/**
* Returns the default purpose id and category id for the provided context level.
*
* The caller code is responsible of checking that $contextlevel is an integer.
*
* @param int $contextlevel The context level.
* @param string $pluginname The name of the plugin associated with the context level.
* @return int[]|false[]
*/
public static function get_defaults($contextlevel, $pluginname = '') {
$classname = \context_helper::get_class_for_level($contextlevel);
list($purposevar, $categoryvar) = self::var_names_from_context($classname, $pluginname);
$purposeid = get_config('tool_dataprivacy', $purposevar);
$categoryid = get_config('tool_dataprivacy', $categoryvar);
if (!empty($pluginname)) {
list($purposevar, $categoryvar) = self::var_names_from_context($classname);
// If the plugin-level doesn't have a default purpose set, try the context level.
if ($purposeid == false) {
$purposeid = get_config('tool_dataprivacy', $purposevar);
}
// If the plugin-level doesn't have a default category set, try the context level.
if ($categoryid == false) {
$categoryid = get_config('tool_dataprivacy', $categoryvar);
}
}
if (empty($purposeid)) {
$purposeid = context_instance::NOTSET;
}
if (empty($categoryid)) {
$categoryid = context_instance::NOTSET;
}
return [$purposeid, $categoryid];
}
/**
* Are data registry defaults set?
*
* At least the system defaults need to be set.
*
* @return bool
*/
public static function defaults_set() {
list($purposeid, $categoryid) = self::get_defaults(CONTEXT_SYSTEM);
if (empty($purposeid) || empty($categoryid)) {
return false;
}
return true;
}
/**
* Returns all site categories that are visible to the current user.
*
* @return \coursecat[]
*/
public static function get_site_categories() {
global $DB;
if (method_exists('\coursecat', 'get_all')) {
$categories = \coursecat::get_all(['returnhidden' => true]);
} else {
// Fallback (to be removed once this gets integrated into master).
$ids = $DB->get_fieldset_select('course_categories', 'id', '');
$categories = \coursecat::get_many($ids);
}
foreach ($categories as $key => $category) {
if (!$category->is_uservisible()) {
unset($categories[$key]);
}
}
return $categories;
}
/**
* Returns the roles assigned to the provided level.
*
* Important to note that it returns course-level assigned roles
* if the provided context level is below course.
*
* @param \context $context
* @return array
*/
public static function get_subject_scope(\context $context) {
if ($contextcourse = $context->get_course_context(false)) {
// Below course level we look at module or block level roles + course-assigned roles.
$courseroles = get_roles_with_assignment_on_context($contextcourse);
$roles = $courseroles + get_roles_with_assignment_on_context($context);
} else {
// We list category + system for others (we don't work with user instances so no need to work about them).
$roles = get_roles_used_in_context($context);
}
return array_map(function($role) {
if ($role->name) {
return $role->name;
} else {
return $role->shortname;
}
}, $roles);
}
/**
* Returns the effective value given a context instance
*
* @param \context $context
* @param string $element 'category' or 'purpose'
* @param int|false $forcedvalue Use this value as if this was this context instance value.
* @return persistent|false It return a 'purpose' instance or a 'category' instance, depending on $element
*/
public static function get_effective_context_value(\context $context, $element, $forcedvalue = false) {
global $DB;
if ($element !== 'purpose' && $element !== 'category') {
throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
}
$fieldname = $element . 'id';
if (!empty($forcedvalue) && ($forcedvalue == context_instance::INHERIT)) {
// Do not include the current context when calculating the value.
// This has the effect that an inheritted value is calculated.
$parentcontextids = $context->get_parent_context_ids(false);
} else if (!empty($forcedvalue) && ($forcedvalue != context_instance::NOTSET)) {
return self::get_element_instance($element, $forcedvalue);
} else {
// Fetch all parent contexts, including self.
$parentcontextids = $context->get_parent_context_ids(true);
}
list($insql, $inparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED);
$inparams['contextmodule'] = CONTEXT_MODULE;
if ('purpose' === $element) {
$elementjoin = 'LEFT JOIN {tool_dataprivacy_purpose} ele ON ctxins.purposeid = ele.id';
$elementfields = purpose::get_sql_fields('ele', 'ele');
} else {
$elementjoin = 'LEFT JOIN {tool_dataprivacy_category} ele ON ctxins.categoryid = ele.id';
$elementfields = category::get_sql_fields('ele', 'ele');
}
$contextfields = \context_helper::get_preload_record_columns_sql('ctx');
$fields = implode(', ', ['ctx.id', 'm.name AS modname', $contextfields, $elementfields]);
$sql = "SELECT $fields
FROM {context} ctx
LEFT JOIN {tool_dataprivacy_ctxinstance} ctxins ON ctx.id = ctxins.contextid
LEFT JOIN {course_modules} cm ON ctx.contextlevel = :contextmodule AND ctx.instanceid = cm.id
LEFT JOIN {modules} m ON m.id = cm.module
{$elementjoin}
WHERE ctx.id {$insql}
ORDER BY ctx.path DESC";
$contextinstances = $DB->get_records_sql($sql, $inparams);
// Check whether this context is a user context, or a child of a user context.
// All children of a User context share the same context and cannot be set individually.
foreach ($contextinstances as $record) {
\context_helper::preload_from_record($record);
$parent = \context::instance_by_id($record->id, false);
if ($parent->contextlevel == CONTEXT_USER) {
// Use the context level value for the user.
return self::get_effective_contextlevel_value(CONTEXT_USER, $element);
}
}
foreach ($contextinstances as $record) {
$parent = \context::instance_by_id($record->id, false);
$checkcontextlevel = false;
if (empty($record->eleid)) {
$checkcontextlevel = true;
}
if (!empty($forcedvalue) && context_instance::NOTSET == $forcedvalue) {
$checkcontextlevel = true;
}
if ($checkcontextlevel) {
// Check for a value at the contextlevel
$forplugin = empty($record->modname) ? '' : $record->modname;
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category(
$parent->contextlevel, false, false, $forplugin);
$instancevalue = $$fieldname;
if (context_instance::NOTSET != $instancevalue && context_instance::INHERIT != $instancevalue) {
// There is an actual value. Return it.
return self::get_element_instance($element, $instancevalue);
}
} else {
$elementclass = "\\tool_dataprivacy\\{$element}";
$instance = new $elementclass(null, $elementclass::extract_record($record, 'ele'));
$instance->validate();
return $instance;
}
}
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
}
/**
* Returns the effective value for a context level.
*
* Note that this is different from the effective default context level
* (see get_effective_default_contextlevel_purpose_and_category) as this is returning
* the value set in the data registry, not in the defaults page.
*
* @param int $contextlevel
* @param string $element 'category' or 'purpose'
* @return \tool_dataprivacy\purpose|false
*/
public static function get_effective_contextlevel_value($contextlevel, $element) {
if ($element !== 'purpose' && $element !== 'category') {
throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
}
$fieldname = $element . 'id';
if ($contextlevel != CONTEXT_SYSTEM && $contextlevel != CONTEXT_USER) {
throw new \coding_exception('Only context_system and context_user values can be retrieved, no other context levels ' .
'have a purpose or a category.');
}
list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category($contextlevel);
// Note: The $$fieldname points to either $purposeid, or $categoryid.
if (context_instance::NOTSET != $$fieldname && context_instance::INHERIT != $$fieldname) {
// There is a specific value set.
return self::get_element_instance($element, $$fieldname);
}
throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
}
/**
* Returns the effective default purpose and category for a context level.
*
* @param int $contextlevel
* @param int|bool $forcedpurposevalue Use this value as if this was this context level purpose.
* @param int|bool $forcedcategoryvalue Use this value as if this was this context level category.
* @param string $component The name of the component to check.
* @return int[]
*/
public static function get_effective_default_contextlevel_purpose_and_category($contextlevel, $forcedpurposevalue = false,
$forcedcategoryvalue = false, $component = '') {
// Get the defaults for this context level.
list($purposeid, $categoryid) = self::get_defaults($contextlevel, $component);
// Honour forced values.
if ($forcedpurposevalue) {
$purposeid = $forcedpurposevalue;
}
if ($forcedcategoryvalue) {
$categoryid = $forcedcategoryvalue;
}
if ($contextlevel == CONTEXT_USER) {
// Only user context levels inherit from a parent context level.
list($parentpurposeid, $parentcategoryid) = self::get_defaults(CONTEXT_SYSTEM);
if (context_instance::INHERIT == $purposeid || context_instance::NOTSET == $purposeid) {
$purposeid = (int)$parentpurposeid;
}
if (context_instance::INHERIT == $categoryid || context_instance::NOTSET == $categoryid) {
$categoryid = $parentcategoryid;
}
}
return [$purposeid, $categoryid];
}
/**
* Returns an instance of the provided element.
*
* @throws \coding_exception
* @param string $element The element name 'purpose' or 'category'
* @param int $id The element id
* @return \core\persistent
*/
private static function get_element_instance($element, $id) {
if ($element !== 'purpose' && $element !== 'category') {
throw new coding_exception('No other elements than purpose and category are allowed');
}
$classname = '\tool_dataprivacy\\' . $element;
return new $classname($id);
}
}
@@ -0,0 +1,229 @@
<?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/>.
/**
* Class for loading/storing data requests from the DB.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
use core\persistent;
/**
* Class for loading/storing competencies from the DB.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_request extends persistent {
/** The table name this persistent object maps to. */
const TABLE = 'tool_dataprivacy_request';
/** Data request created manually. */
const DATAREQUEST_CREATION_MANUAL = 0;
/** Data request created automatically. */
const DATAREQUEST_CREATION_AUTO = 1;
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return [
'type' => [
'choices' => [
api::DATAREQUEST_TYPE_EXPORT,
api::DATAREQUEST_TYPE_DELETE,
api::DATAREQUEST_TYPE_OTHERS,
],
'type' => PARAM_INT
],
'comments' => [
'type' => PARAM_TEXT,
'default' => ''
],
'commentsformat' => [
'choices' => [
FORMAT_HTML,
FORMAT_MOODLE,
FORMAT_PLAIN,
FORMAT_MARKDOWN
],
'type' => PARAM_INT,
'default' => FORMAT_PLAIN
],
'userid' => [
'default' => 0,
'type' => PARAM_INT
],
'requestedby' => [
'default' => 0,
'type' => PARAM_INT
],
'status' => [
'default' => api::DATAREQUEST_STATUS_PENDING,
'choices' => [
api::DATAREQUEST_STATUS_PENDING,
api::DATAREQUEST_STATUS_PREPROCESSING,
api::DATAREQUEST_STATUS_AWAITING_APPROVAL,
api::DATAREQUEST_STATUS_APPROVED,
api::DATAREQUEST_STATUS_PROCESSING,
api::DATAREQUEST_STATUS_COMPLETE,
api::DATAREQUEST_STATUS_CANCELLED,
api::DATAREQUEST_STATUS_REJECTED,
api::DATAREQUEST_STATUS_DOWNLOAD_READY,
api::DATAREQUEST_STATUS_EXPIRED,
api::DATAREQUEST_STATUS_DELETED,
],
'type' => PARAM_INT
],
'dpo' => [
'default' => 0,
'type' => PARAM_INT,
'null' => NULL_ALLOWED
],
'dpocomment' => [
'default' => '',
'type' => PARAM_TEXT,
'null' => NULL_ALLOWED
],
'dpocommentformat' => [
'choices' => [
FORMAT_HTML,
FORMAT_MOODLE,
FORMAT_PLAIN,
FORMAT_MARKDOWN
],
'type' => PARAM_INT,
'default' => FORMAT_PLAIN
],
'creationmethod' => [
'default' => self::DATAREQUEST_CREATION_MANUAL,
'choices' => [
self::DATAREQUEST_CREATION_MANUAL,
self::DATAREQUEST_CREATION_AUTO
],
'type' => PARAM_INT
],
];
}
/**
* Determines whether a completed data export request has expired.
* The response will be valid regardless of the expiry scheduled task having run.
*
* @param data_request $request the data request object whose expiry will be checked.
* @return bool true if the request has expired.
*/
public static function is_expired(data_request $request) {
$result = false;
// Only export requests expire.
if ($request->get('type') == api::DATAREQUEST_TYPE_EXPORT) {
switch ($request->get('status')) {
// Expired requests are obviously expired.
case api::DATAREQUEST_STATUS_EXPIRED:
$result = true;
break;
// Complete requests are expired if the expiry time has elapsed.
case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
$expiryseconds = get_config('tool_dataprivacy', 'privacyrequestexpiry');
if ($expiryseconds > 0 && time() >= ($request->get('timemodified') + $expiryseconds)) {
$result = true;
}
break;
}
}
return $result;
}
/**
* Fetch completed data requests which are due to expire.
*
* @param int $userid Optional user ID to filter by.
*
* @return array Details of completed requests which are due to expire.
*/
public static function get_expired_requests($userid = 0) {
global $DB;
$expiryseconds = get_config('tool_dataprivacy', 'privacyrequestexpiry');
$expirytime = strtotime("-{$expiryseconds} second");
$table = self::TABLE;
$sqlwhere = 'type = :export_type AND status = :completestatus AND timemodified <= :expirytime';
$params = array(
'export_type' => api::DATAREQUEST_TYPE_EXPORT,
'completestatus' => api::DATAREQUEST_STATUS_DOWNLOAD_READY,
'expirytime' => $expirytime,
);
$sort = 'id';
$fields = 'id, userid';
// Filter by user ID if specified.
if ($userid > 0) {
$sqlwhere .= ' AND (userid = :userid OR requestedby = :requestedby)';
$params['userid'] = $userid;
$params['requestedby'] = $userid;
}
return $DB->get_records_select_menu($table, $sqlwhere, $params, $sort, $fields, 0, 2000);
}
/**
* Expire a given set of data requests.
* Update request status and delete the files.
*
* @param array $expiredrequests [requestid => userid]
*
* @return void
*/
public static function expire($expiredrequests) {
global $DB;
$ids = array_keys($expiredrequests);
if (count($ids) > 0) {
list($insql, $inparams) = $DB->get_in_or_equal($ids);
$initialparams = array(api::DATAREQUEST_STATUS_EXPIRED, time());
$params = array_merge($initialparams, $inparams);
$update = "UPDATE {" . self::TABLE . "}
SET status = ?, timemodified = ?
WHERE id $insql";
if ($DB->execute($update, $params)) {
$fs = get_file_storage();
foreach ($expiredrequests as $id => $userid) {
$usercontext = \context_user::instance($userid);
$fs->delete_area_files($usercontext->id, 'tool_dataprivacy', 'export', $id);
}
}
}
}
}
@@ -0,0 +1,63 @@
<?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/>.
/**
* Event observers supported by this module.
*
* @package tool_dataprivacy
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\event;
use \tool_dataprivacy\api;
use \tool_dataprivacy\data_request;
defined('MOODLE_INTERNAL') || die();
/**
* Event observers supported by this module.
*
* @package tool_dataprivacy
* @copyright 2018 Mihail Geshoski <mihail@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class user_deleted_observer {
/**
* Create user data deletion request when the user is deleted.
*
* @param \core\event\user_deleted $event
*/
public static function create_delete_data_request(\core\event\user_deleted $event) {
// Automatic creation of deletion requests must be enabled.
if (get_config('tool_dataprivacy', 'automaticdeletionrequests')) {
$requesttypes = [api::DATAREQUEST_TYPE_DELETE];
$requeststatuses = [api::DATAREQUEST_STATUS_COMPLETE, api::DATAREQUEST_STATUS_DELETED];
$hasongoingdeleterequests = api::has_ongoing_request($event->objectid, $requesttypes[0]);
$hascompleteddeleterequest = (api::get_data_requests_count($event->objectid, $requeststatuses,
$requesttypes) > 0) ? true : false;
if (!$hasongoingdeleterequests && !$hascompleteddeleterequest) {
api::create_data_request($event->objectid, $requesttypes[0],
get_string('datarequestcreatedupondelete', 'tool_dataprivacy'),
data_request::DATAREQUEST_CREATION_AUTO);
}
}
}
}
@@ -0,0 +1,209 @@
<?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/>.
/**
* Class that represents an expired context.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
use dml_exception;
defined('MOODLE_INTERNAL') || die();
/**
* Class that represents an expired context.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class expired_context extends \core\persistent {
/**
* Database table.
*/
const TABLE = 'tool_dataprivacy_ctxexpired';
/**
* Expired contexts with no delete action scheduled.
*/
const STATUS_EXPIRED = 0;
/**
* Expired contexts approved for deletion.
*/
const STATUS_APPROVED = 1;
/**
* Already processed expired contexts.
*/
const STATUS_CLEANED = 2;
/**
* Return the definition of the properties of this model.
*
* @return array
*/
protected static function define_properties() {
return array(
'contextid' => array(
'type' => PARAM_INT,
'description' => 'The context id.',
),
'status' => array(
'choices' => [
self::STATUS_EXPIRED,
self::STATUS_APPROVED,
self::STATUS_CLEANED,
],
'type' => PARAM_INT,
'description' => 'The deletion status of the context.',
),
);
}
/**
* Returns expired_contexts instances that match the provided level and status.
*
* @param int $contextlevel The context level filter criterion.
* @param bool $status The expired context record's status.
* @param string $sort The sort column. Must match the column name in {tool_dataprivacy_ctxexpired} table
* @param int $offset The query offset.
* @param int $limit The query limit.
* @return expired_context[]
* @throws dml_exception
*/
public static function get_records_by_contextlevel($contextlevel = null, $status = false, $sort = 'timecreated',
$offset = 0, $limit = 0) {
global $DB;
$sql = "SELECT expiredctx.*
FROM {" . self::TABLE . "} expiredctx
JOIN {context} ctx
ON ctx.id = expiredctx.contextid";
$params = [];
$conditions = [];
if (!empty($contextlevel)) {
$conditions[] = "ctx.contextlevel = :contextlevel";
$params['contextlevel'] = intval($contextlevel);
}
if ($status !== false) {
$conditions[] = "expiredctx.status = :status";
$params['status'] = intval($status);
}
if (!empty($conditions)) {
$sql .= ' WHERE ' . implode(' AND ', $conditions);
}
$sql .= " ORDER BY expiredctx.{$sort}";
$records = $DB->get_records_sql($sql, $params, $offset, $limit);
// We return class instances.
$instances = array();
foreach ($records as $key => $record) {
$instances[$key] = new static(0, $record);
}
return $instances;
}
/**
* Returns the number of expired_contexts instances that match the provided level and status.
*
* @param int $contextlevel
* @param bool $status
* @return int
* @throws dml_exception
*/
public static function get_record_count_by_contextlevel($contextlevel = null, $status = false) {
global $DB;
$sql = "SELECT COUNT(1)
FROM {" . self::TABLE . "} expiredctx
JOIN {context} ctx
ON ctx.id = expiredctx.contextid";
$conditions = [];
$params = [];
if (!empty($contextlevel)) {
$conditions[] = "ctx.contextlevel = :contextlevel";
$params['contextlevel'] = intval($contextlevel);
}
if ($status !== false) {
$sql .= " AND expiredctx.status = :status";
$params['status'] = intval($status);
}
if (!empty($conditions)) {
$sql .= ' WHERE ' . implode(' AND ', $conditions);
}
return $DB->count_records_sql($sql, $params);
}
/**
* Create a new expired_context based on the context, and expiry_info object.
*
* @param \context $context
* @param expiry_info $info
* @return expired_context
*/
public static function create_from_expiry_info(\context $context, expiry_info $info) {
$record = (object) [
'contextid' => $context->id,
'status' => self::STATUS_EXPIRED,
];
$expiredcontext = new static(0, $record);
$expiredcontext->save();
return $expiredcontext;
}
/**
* Update the expired_context from an expiry_info object which relates to this context.
*
* @param expiry_info $info
* @return $this
*/
public function update_from_expiry_info(expiry_info $info) {
return $this;
}
/**
* Check whether this expired_context record is in a state ready for deletion to actually take place.
*
* @return bool
*/
public function can_process_deletion() {
return ($this->get('status') == self::STATUS_APPROVED);
}
/**
* Check whether this expired_context record has already been cleaned.
*
* @return bool
*/
public function is_complete() {
return ($this->get('status') == self::STATUS_CLEANED);
}
}
@@ -0,0 +1,713 @@
<?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/>.
/**
* Expired contexts manager.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
use core_privacy\manager;
use tool_dataprivacy\expired_context;
defined('MOODLE_INTERNAL') || die();
/**
* Expired contexts manager.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class expired_contexts_manager {
/**
* Number of deleted contexts for each scheduled task run.
*/
const DELETE_LIMIT = 200;
/** @var progress_trace The log progress tracer */
protected $progresstracer = null;
/** @var manager The privacy manager */
protected $manager = null;
/**
* Flag expired contexts as expired.
*
* @return int[] The number of contexts flagged as expired for courses, and users.
*/
public function flag_expired_contexts() {
if (!$this->check_requirements()) {
return [0, 0];
}
// Clear old and stale records first.
static::clear_old_records();
$data = static::get_nested_expiry_info_for_courses();
$coursecount = 0;
foreach ($data as $expiryrecord) {
if ($this->update_from_expiry_info($expiryrecord)) {
$coursecount++;
}
}
$data = static::get_nested_expiry_info_for_user();
$usercount = 0;
foreach ($data as $expiryrecord) {
if ($this->update_from_expiry_info($expiryrecord)) {
$usercount++;
}
}
return [$coursecount, $usercount];
}
/**
* Clear old and stale records.
*/
protected static function clear_old_records() {
global $DB;
$sql = "SELECT dpctx.*
FROM {tool_dataprivacy_ctxexpired} dpctx
LEFT JOIN {context} ctx ON ctx.id = dpctx.contextid
WHERE ctx.id IS NULL";
$orphaned = $DB->get_recordset_sql($sql);
foreach ($orphaned as $orphan) {
$expiredcontext = new expired_context(0, $orphan);
$expiredcontext->delete();
}
// Delete any child of a user context.
$parentpath = $DB->sql_concat('ctxuser.path', "'/%'");
$params = [
'contextuser' => CONTEXT_USER,
];
$sql = "SELECT dpctx.*
FROM {tool_dataprivacy_ctxexpired} dpctx
WHERE dpctx.contextid IN (
SELECT ctx.id
FROM {context} ctxuser
JOIN {context} ctx ON ctx.path LIKE {$parentpath}
WHERE ctxuser.contextlevel = :contextuser
)";
$userchildren = $DB->get_recordset_sql($sql, $params);
foreach ($userchildren as $child) {
$expiredcontext = new expired_context(0, $child);
$expiredcontext->delete();
}
}
/**
* Get the full nested set of expiry data relating to all contexts.
*
* @param string $contextpath A contexpath to restrict results to
* @return \stdClass[]
*/
protected static function get_nested_expiry_info($contextpath = '') {
$coursepaths = self::get_nested_expiry_info_for_courses($contextpath);
$userpaths = self::get_nested_expiry_info_for_user($contextpath);
return array_merge($coursepaths, $userpaths);
}
/**
* Get the full nested set of expiry data relating to course-related contexts.
*
* @param string $contextpath A contexpath to restrict results to
* @return \stdClass[]
*/
protected static function get_nested_expiry_info_for_courses($contextpath = '') {
global $DB;
$contextfields = \context_helper::get_preload_record_columns_sql('ctx');
$expiredfields = expired_context::get_sql_fields('expiredctx', 'expiredctx');
$purposefields = 'dpctx.purposeid';
$coursefields = 'ctxcourse.expirydate AS expirydate';
$fields = implode(', ', ['ctx.id', $contextfields, $expiredfields, $coursefields, $purposefields]);
// We want all contexts at course-dependant levels.
$parentpath = $DB->sql_concat('ctxcourse.path', "'/%'");
// This SQL query returns all course-dependant contexts (including the course context)
// which course end date already passed.
// This is ordered by the context path in reverse order, which will give the child nodes before any parent node.
$params = [
'contextlevel' => CONTEXT_COURSE,
];
$where = '';
if (!empty($contextpath)) {
$where = "WHERE (ctx.path = :pathmatchexact OR ctx.path LIKE :pathmatchchildren)";
$params['pathmatchexact'] = $contextpath;
$params['pathmatchchildren'] = "{$contextpath}/%";
}
$sql = "SELECT $fields
FROM {context} ctx
JOIN (
SELECT c.enddate AS expirydate, subctx.path
FROM {context} subctx
JOIN {course} c
ON subctx.contextlevel = :contextlevel
AND subctx.instanceid = c.id
AND c.format != 'site'
) ctxcourse
ON ctx.path LIKE {$parentpath} OR ctx.path = ctxcourse.path
LEFT JOIN {tool_dataprivacy_ctxinstance} dpctx
ON dpctx.contextid = ctx.id
LEFT JOIN {tool_dataprivacy_ctxexpired} expiredctx
ON ctx.id = expiredctx.contextid
{$where}
ORDER BY ctx.path DESC";
return self::get_nested_expiry_info_from_sql($sql, $params);
}
/**
* Get the full nested set of expiry data.
*
* @param string $contextpath A contexpath to restrict results to
* @return \stdClass[]
*/
protected static function get_nested_expiry_info_for_user($contextpath = '') {
global $DB;
$contextfields = \context_helper::get_preload_record_columns_sql('ctx');
$expiredfields = expired_context::get_sql_fields('expiredctx', 'expiredctx');
$purposefields = 'dpctx.purposeid';
$userfields = 'u.lastaccess AS expirydate';
$fields = implode(', ', ['ctx.id', $contextfields, $expiredfields, $userfields, $purposefields]);
// We want all contexts at user-dependant levels.
$parentpath = $DB->sql_concat('ctxuser.path', "'/%'");
// This SQL query returns all user-dependant contexts (including the user context)
// This is ordered by the context path in reverse order, which will give the child nodes before any parent node.
$params = [
'contextlevel' => CONTEXT_USER,
];
$where = '';
if (!empty($contextpath)) {
$where = "AND ctx.path = :pathmatchexact";
$params['pathmatchexact'] = $contextpath;
}
$sql = "SELECT $fields, u.deleted AS userdeleted
FROM {context} ctx
JOIN {user} u ON ctx.instanceid = u.id
LEFT JOIN {tool_dataprivacy_ctxinstance} dpctx
ON dpctx.contextid = ctx.id
LEFT JOIN {tool_dataprivacy_ctxexpired} expiredctx
ON ctx.id = expiredctx.contextid
WHERE ctx.contextlevel = :contextlevel {$where}
ORDER BY ctx.path DESC";
return self::get_nested_expiry_info_from_sql($sql, $params);
}
/**
* Get the full nested set of expiry data given appropriate SQL.
* Only contexts which have expired will be included.
*
* @param string $sql The SQL used to select the nested information.
* @param array $params The params required by the SQL.
* @return \stdClass[]
*/
protected static function get_nested_expiry_info_from_sql($sql, array $params) {
global $DB;
$fulllist = $DB->get_recordset_sql($sql, $params);
$datalist = [];
$expiredcontents = [];
$pathstoskip = [];
foreach ($fulllist as $record) {
\context_helper::preload_from_record($record);
$context = \context::instance_by_id($record->id, false);
if (!self::is_eligible_for_deletion($pathstoskip, $context)) {
// We should skip this context, and therefore all of it's children.
$datalist = array_filter($datalist, function($data, $path) use ($context) {
// Remove any child of this context.
// Technically this should never be fulfilled because the query is ordered in path DESC, but is kept
// in to be certain.
return (false === strpos($path, "{$context->path}/"));
}, ARRAY_FILTER_USE_BOTH);
if ($record->expiredctxid) {
// There was previously an expired context record.
// Delete it to be on the safe side.
$expiredcontext = new expired_context(null, expired_context::extract_record($record, 'expiredctx'));
$expiredcontext->delete();
}
continue;
}
$purposevalue = $record->purposeid !== null ? $record->purposeid : context_instance::NOTSET;
$purpose = api::get_effective_context_purpose($context, $purposevalue);
if ($context instanceof \context_user && !empty($record->userdeleted)) {
$expiryinfo = static::get_expiry_info($purpose, $record->userdeleted);
} else {
$expiryinfo = static::get_expiry_info($purpose, $record->expirydate);
}
foreach ($datalist as $path => $data) {
// Merge with already-processed children.
if (strpos($path, $context->path) !== 0) {
continue;
}
$expiryinfo->merge_with_child($data->info);
}
$datalist[$context->path] = (object) [
'context' => $context,
'record' => $record,
'purpose' => $purpose,
'info' => $expiryinfo,
];
}
$fulllist->close();
return $datalist;
}
/**
* Check whether the supplied context would be elible for deletion.
*
* @param array $pathstoskip A set of paths which should be skipped
* @param \context $context
* @return bool
*/
protected static function is_eligible_for_deletion(array &$pathstoskip, \context $context) {
$shouldskip = false;
// Check whether any of the child contexts are ineligble.
$shouldskip = !empty(array_filter($pathstoskip, function($path) use ($context) {
// If any child context has already been skipped then it will appear in this list.
// Since paths include parents, test if the context under test appears as the haystack in the skipped
// context's needle.
return false !== (strpos($context->path, $path));
}));
if (!$shouldskip && $context instanceof \context_user) {
// The context instanceid is the user's ID.
if (isguestuser($context->instanceid) || is_siteadmin($context->instanceid)) {
// This is an admin, or the guest and cannot be deleted.
$shouldskip = true;
}
if (!$shouldskip) {
$courses = enrol_get_users_courses($context->instanceid, false, ['enddate']);
$requireenddate = self::require_all_end_dates_for_user_deletion();
foreach ($courses as $course) {
if (empty($course->enddate)) {
// This course has no end date.
if ($requireenddate) {
// Course end dates are required, and this course has no end date.
$shouldskip = true;
break;
}
// Course end dates are not required. The subsequent checks are pointless at this time so just
// skip them.
continue;
}
if ($course->enddate >= time()) {
// This course is still in the future.
$shouldskip = true;
break;
}
// This course has an end date which is in the past.
if (!self::is_course_expired($course)) {
// This course has not expired yet.
$shouldskip = true;
break;
}
}
}
}
if ($shouldskip) {
// Add this to the list of contexts to skip for parentage checks.
$pathstoskip[] = $context->path;
}
return !$shouldskip;
}
/**
* Deletes the expired contexts.
*
* @return int[] The number of deleted contexts.
*/
public function process_approved_deletions() {
if (!$this->check_requirements()) {
return [0, 0];
}
$expiredcontexts = expired_context::get_records(['status' => expired_context::STATUS_APPROVED]);
$totalprocessed = 0;
$usercount = 0;
$coursecount = 0;
foreach ($expiredcontexts as $expiredctx) {
$context = \context::instance_by_id($expiredctx->get('contextid'), IGNORE_MISSING);
if (empty($context)) {
// Unable to process this request further.
// We have no context to delete.
$expiredctx->delete();
continue;
}
if ($this->delete_expired_context($expiredctx)) {
if ($context instanceof \context_user) {
$usercount++;
} else {
$coursecount++;
}
$totalprocessed++;
if ($totalprocessed >= $this->get_delete_limit()) {
break;
}
}
}
return [$coursecount, $usercount];
}
/**
* Deletes user data from the provided context.
*
* @param expired_context $expiredctx
* @return \context|false
*/
protected function delete_expired_context(expired_context $expiredctx) {
$context = \context::instance_by_id($expiredctx->get('contextid'));
$this->get_progress()->output("Deleting context {$context->id} - " . $context->get_context_name(true, true));
// Update the expired_context and verify that it is still ready for deletion.
$expiredctx = $this->update_expired_context($expiredctx);
if (empty($expiredctx)) {
$this->get_progress()->output("Context has changed since approval and is no longer pending approval. Skipping", 1);
return false;
}
if (!$expiredctx->can_process_deletion()) {
// This only happens if the record was updated after being first fetched.
$this->get_progress()->output("Context has changed since approval and must be re-approved. Skipping", 1);
$expiredctx->set('status', expired_context::STATUS_EXPIRED);
$expiredctx->save();
return false;
}
$privacymanager = $this->get_privacy_manager();
if ($context instanceof \context_user) {
$this->delete_expired_user_context($expiredctx);
} else {
// This context is fully expired - that is that the default retention period has been reached.
$privacymanager->delete_data_for_all_users_in_context($context);
}
// Mark the record as cleaned.
$expiredctx->set('status', expired_context::STATUS_CLEANED);
$expiredctx->save();
return $context;
}
/**
* Deletes user data from the provided user context.
*
* @param expired_context $expiredctx
*/
protected function delete_expired_user_context(expired_context $expiredctx) {
global $DB;
$contextid = $expiredctx->get('contextid');
$context = \context::instance_by_id($contextid);
$user = \core_user::get_user($context->instanceid, '*', MUST_EXIST);
$privacymanager = $this->get_privacy_manager();
// Delete all child contexts of the user context.
$parentpath = $DB->sql_concat('ctxuser.path', "'/%'");
$params = [
'contextlevel' => CONTEXT_USER,
'contextid' => $expiredctx->get('contextid'),
];
$fields = \context_helper::get_preload_record_columns_sql('ctx');
$sql = "SELECT ctx.id, $fields
FROM {context} ctxuser
JOIN {context} ctx ON ctx.path LIKE {$parentpath}
WHERE ctxuser.contextlevel = :contextlevel AND ctxuser.id = :contextid
ORDER BY ctx.path DESC";
$children = $DB->get_recordset_sql($sql, $params);
foreach ($children as $child) {
\context_helper::preload_from_record($child);
$context = \context::instance_by_id($child->id);
$privacymanager->delete_data_for_all_users_in_context($context);
}
$children->close();
// Delete all unprotected data that the user holds.
$approvedlistcollection = new \core_privacy\local\request\contextlist_collection($user->id);
$contextlistcollection = $privacymanager->get_contexts_for_userid($user->id);
foreach ($contextlistcollection as $contextlist) {
$contextids = [];
$approvedlistcollection->add_contextlist(new \core_privacy\local\request\approved_contextlist(
$user,
$contextlist->get_component(),
$contextlist->get_contextids()
));
}
$privacymanager->delete_data_for_user($approvedlistcollection, $this->get_progress());
// Delete the user context.
$context = \context::instance_by_id($expiredctx->get('contextid'));
$privacymanager->delete_data_for_all_users_in_context($context);
// This user is now fully expired - finish by deleting the user.
delete_user($user);
}
/**
* Whether end dates are required on all courses in order for a user to be expired from them.
*
* @return bool
*/
protected static function require_all_end_dates_for_user_deletion() {
$requireenddate = get_config('tool_dataprivacy', 'requireallenddatesforuserdeletion');
return !empty($requireenddate);
}
/**
* Check that the requirements to start deleting contexts are satisified.
*
* @return bool
*/
protected function check_requirements() {
if (!data_registry::defaults_set()) {
return false;
}
return true;
}
/**
* Check whether a date is beyond the specified period.
*
* @param string $period The Expiry Period
* @param int $comparisondate The date for comparison
* @return bool
*/
protected static function has_expired($period, $comparisondate) {
$dt = new \DateTime();
$dt->setTimestamp($comparisondate);
$dt->add(new \DateInterval($period));
return (time() >= $dt->getTimestamp());
}
/**
* Get the expiry info object for the specified purpose and comparison date.
*
* @param purpose $purpose The purpose of this context
* @param int $comparisondate The date for comparison
* @return expiry_info
*/
protected static function get_expiry_info(purpose $purpose, $comparisondate = 0) {
if (empty($comparisondate)) {
// The date is empty, therefore this context cannot be considered for automatic expiry.
$defaultexpired = false;
} else {
$defaultexpired = static::has_expired($purpose->get('retentionperiod'), $comparisondate);
}
return new expiry_info($defaultexpired);
}
/**
* Update or delete the expired_context from the expiry_info object.
* This function depends upon the data structure returned from get_nested_expiry_info.
*
* If the context is expired in any way, then an expired_context will be returned, otherwise null will be returned.
*
* @param \stdClass $expiryrecord
* @return expired_context|null
*/
protected function update_from_expiry_info(\stdClass $expiryrecord) {
if ($expiryrecord->info->is_any_expired()) {
// The context is expired in some fashion.
// Create or update as required.
if ($expiryrecord->record->expiredctxid) {
$expiredcontext = new expired_context(null, expired_context::extract_record($expiryrecord->record, 'expiredctx'));
$expiredcontext->update_from_expiry_info($expiryrecord->info);
if ($expiredcontext->is_complete()) {
return null;
}
} else {
$expiredcontext = expired_context::create_from_expiry_info($expiryrecord->context, $expiryrecord->info);
}
return $expiredcontext;
} else {
// The context is not expired.
if ($expiryrecord->record->expiredctxid) {
// There was previously an expired context record, but it is no longer relevant.
// Delete it to be on the safe side.
$expiredcontext = new expired_context(null, expired_context::extract_record($expiryrecord->record, 'expiredctx'));
$expiredcontext->delete();
}
return null;
}
}
/**
* Update the expired context record.
*
* Note: You should use the return value as the provided value will be used to fetch data only.
*
* @param expired_context $expiredctx The record to update
* @return expired_context|null
*/
protected function update_expired_context(expired_context $expiredctx) {
// Fetch the context from the expired_context record.
$context = \context::instance_by_id($expiredctx->get('contextid'));
// Fetch the current nested expiry data.
$expiryrecords = self::get_nested_expiry_info($context->path);
// Find the current record.
if (empty($expiryrecords[$context->path])) {
$expiredctx->delete();
return null;
}
// Refresh the record.
// Note: Use the returned expiredctx.
$expiredctx = $this->update_from_expiry_info($expiryrecords[$context->path]);
if (empty($expiredctx)) {
return null;
}
if (!$context instanceof \context_user) {
// Where the target context is not a user, we check all children of the context.
// The expiryrecords array only contains children, fetched from the get_nested_expiry_info call above.
// No need to check that these _are_ children.
foreach ($expiryrecords as $expiryrecord) {
if ($expiryrecord->context->id === $context->id) {
// This is record for the context being tested that we checked earlier.
continue;
}
if (empty($expiryrecord->record->expiredctxid)) {
// There is no expired context record for this context.
// If there is no record, then this context cannot have been approved for removal.
return null;
}
// Fetch the expired_context object for this record.
// This needs to be updated from the expiry_info data too as there may be child changes to consider.
$expiredcontext = new expired_context(null, expired_context::extract_record($expiryrecord->record, 'expiredctx'));
$expiredcontext->update_from_expiry_info($expiryrecord->info);
if (!$expiredcontext->is_complete()) {
return null;
}
}
}
return $expiredctx;
}
/**
* Check whether the course has expired.
*
* @param \stdClass $course
* @return bool
*/
protected static function is_course_expired(\stdClass $course) {
$context = \context_course::instance($course->id);
$expiryrecords = self::get_nested_expiry_info_for_courses($context->path);
return !empty($expiryrecords[$context->path]) && $expiryrecords[$context->path]->info->is_fully_expired();
}
/**
* Create a new instance of the privacy manager.
*
* @return manager
*/
protected function get_privacy_manager() {
if (null === $this->manager) {
$this->manager = new manager();
$this->manager->set_observer(new \tool_dataprivacy\manager_observer());
}
return $this->manager;
}
/**
* Fetch the limit for the maximum number of contexts to delete in one session.
*
* @return int
*/
protected function get_delete_limit() {
return self::DELETE_LIMIT;
}
/**
* Get the progress tracer.
*
* @return \progress_trace
*/
protected function get_progress() {
if (null === $this->progresstracer) {
$this->set_progress(new \text_progress_trace());
}
return $this->progresstracer;
}
/**
* Set a specific tracer for the task.
*
* @param \progress_trace $trace
* @return $this
*/
public function set_progress(\progress_trace $trace) {
$this->progresstracer = $trace;
return $this;
}
}
@@ -0,0 +1,93 @@
<?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/>.
/**
* Expiry Data.
*
* @package tool_dataprivacy
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
use core_privacy\manager;
defined('MOODLE_INTERNAL') || die();
/**
* Expiry Data.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class expiry_info {
/** @var bool Whether this context is fully expired */
protected $isexpired = false;
/**
* Constructor for the expiry_info class.
*
* @param bool $isexpired Whether the retention period for this context has expired yet.
*/
public function __construct($isexpired) {
$this->isexpired = $isexpired;
}
/**
* Whether this context has 'fully' expired.
* That is to say that the default retention period has been reached, and that there are no unexpired roles.
*
* @return bool
*/
public function is_fully_expired() {
return $this->isexpired;
}
/**
* Whether any part of this context has expired.
*
* @return bool
*/
public function is_any_expired() {
if ($this->is_fully_expired()) {
return true;
}
return false;
}
/**
* Merge this expiry_info object with another belonging to a child context in order to set the 'safest' heritage.
*
* It is not possible to delete any part of a context that is not deleted by a parent.
* So if a course's retention policy has been reached, then only parts where the children have also expired can be
* deleted.
*
* @param expiry_info $child The child record to merge with.
* @return $this
*/
public function merge_with_child(expiry_info $child) {
if ($child->is_fully_expired()) {
return $this;
}
// If the child is not fully expired, then none of the parents can be either.
$this->isexpired = false;
return $this;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,79 @@
<?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/>.
/**
* Class for exporting data category.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\external;
defined('MOODLE_INTERNAL') || die();
use core\external\persistent_exporter;
use tool_dataprivacy\category;
use tool_dataprivacy\context_instance;
/**
* Class for exporting field data.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class category_exporter extends persistent_exporter {
/**
* Defines the persistent class.
*
* @return string
*/
protected static function define_class() {
return \tool_dataprivacy\category::class;
}
/**
* Returns a list of objects that are related.
*
* @return array
*/
protected static function define_related() {
return array(
'context' => 'context',
);
}
/**
* Utility function that fetches a category name from the given ID.
*
* @param int $categoryid The category ID. Could be INHERIT (false, -1), NOT_SET (0), or the actual ID.
* @return string The purpose name.
*/
public static function get_name($categoryid) {
global $PAGE;
if ($categoryid === false || $categoryid == context_instance::INHERIT) {
return get_string('inherit', 'tool_dataprivacy');
} else if ($categoryid == context_instance::NOTSET) {
return get_string('notset', 'tool_dataprivacy');
} else {
$purpose = new category($categoryid);
$output = $PAGE->get_renderer('tool_dataprivacy');
$exporter = new self($purpose, ['context' => \context_system::instance()]);
$data = $exporter->export($output);
return $data->name;
}
}
}
@@ -0,0 +1,45 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Class for exporting context instance.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\external;
defined('MOODLE_INTERNAL') || die();
use core\external\persistent_exporter;
/**
* Class for exporting context instance.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class context_instance_exporter extends persistent_exporter {
/**
* Defines the persistent class.
*
* @return string
*/
protected static function define_class() {
return \tool_dataprivacy\context_instance::class;
}
}
@@ -0,0 +1,201 @@
<?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/>.
/**
* Class for exporting user evidence with all competencies.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\external;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use core\external\persistent_exporter;
use core_user;
use core_user\external\user_summary_exporter;
use dml_exception;
use moodle_exception;
use renderer_base;
use tool_dataprivacy\api;
use tool_dataprivacy\data_request;
use tool_dataprivacy\local\helper;
/**
* Class for exporting user evidence with all competencies.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_request_exporter extends persistent_exporter {
/**
* Class definition.
*
* @return string
*/
protected static function define_class() {
return data_request::class;
}
/**
* Related objects definition.
*
* @return array
*/
protected static function define_related() {
return [
'context' => 'context',
];
}
/**
* Other properties definition.
*
* @return array
*/
protected static function define_other_properties() {
return [
'foruser' => [
'type' => user_summary_exporter::read_properties_definition(),
],
'requestedbyuser' => [
'type' => user_summary_exporter::read_properties_definition(),
'optional' => true
],
'dpouser' => [
'type' => user_summary_exporter::read_properties_definition(),
'optional' => true
],
'messagehtml' => [
'type' => PARAM_RAW,
'optional' => true
],
'typename' => [
'type' => PARAM_TEXT,
],
'typenameshort' => [
'type' => PARAM_TEXT,
],
'statuslabel' => [
'type' => PARAM_TEXT,
],
'statuslabelclass' => [
'type' => PARAM_TEXT,
],
'canreview' => [
'type' => PARAM_BOOL,
'optional' => true,
'default' => false
],
'approvedeny' => [
'type' => PARAM_BOOL,
'optional' => true,
'default' => false
],
'canmarkcomplete' => [
'type' => PARAM_BOOL,
'optional' => true,
'default' => false
],
];
}
/**
* Assign values to the defined other properties.
*
* @param renderer_base $output The output renderer object.
* @return array
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
protected function get_other_values(renderer_base $output) {
$values = [];
$foruserid = $this->persistent->get('userid');
$user = core_user::get_user($foruserid, '*', MUST_EXIST);
$userexporter = new user_summary_exporter($user);
$values['foruser'] = $userexporter->export($output);
$requestedbyid = $this->persistent->get('requestedby');
if ($requestedbyid != $foruserid) {
$user = core_user::get_user($requestedbyid, '*', MUST_EXIST);
$userexporter = new user_summary_exporter($user);
$values['requestedbyuser'] = $userexporter->export($output);
} else {
$values['requestedbyuser'] = $values['foruser'];
}
if (!empty($this->persistent->get('dpo'))) {
$dpoid = $this->persistent->get('dpo');
$user = core_user::get_user($dpoid, '*', MUST_EXIST);
$userexporter = new user_summary_exporter($user);
$values['dpouser'] = $userexporter->export($output);
}
$values['messagehtml'] = text_to_html($this->persistent->get('comments'));
$requesttype = $this->persistent->get('type');
$values['typename'] = helper::get_request_type_string($requesttype);
$values['typenameshort'] = helper::get_shortened_request_type_string($requesttype);
$values['canreview'] = false;
$values['approvedeny'] = false;
$values['statuslabel'] = helper::get_request_status_string($this->persistent->get('status'));
switch ($this->persistent->get('status')) {
case api::DATAREQUEST_STATUS_PENDING:
$values['statuslabelclass'] = 'label-info';
// Request can be manually completed for general enquiry requests.
$values['canmarkcomplete'] = $requesttype == api::DATAREQUEST_TYPE_OTHERS;
break;
case api::DATAREQUEST_STATUS_PREPROCESSING:
$values['statuslabelclass'] = 'label-default';
break;
case api::DATAREQUEST_STATUS_AWAITING_APPROVAL:
$values['statuslabelclass'] = 'label-info';
// DPO can review the request once it's ready.
$values['canreview'] = true;
// Whether the DPO can approve or deny the request.
$values['approvedeny'] = in_array($requesttype, [api::DATAREQUEST_TYPE_EXPORT, api::DATAREQUEST_TYPE_DELETE]);
break;
case api::DATAREQUEST_STATUS_APPROVED:
$values['statuslabelclass'] = 'label-info';
break;
case api::DATAREQUEST_STATUS_PROCESSING:
$values['statuslabelclass'] = 'label-info';
break;
case api::DATAREQUEST_STATUS_COMPLETE:
case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
case api::DATAREQUEST_STATUS_DELETED:
$values['statuslabelclass'] = 'label-success';
break;
case api::DATAREQUEST_STATUS_CANCELLED:
$values['statuslabelclass'] = 'label-warning';
break;
case api::DATAREQUEST_STATUS_REJECTED:
$values['statuslabelclass'] = 'label-important';
break;
case api::DATAREQUEST_STATUS_EXPIRED:
$values['statuslabelclass'] = 'label-default';
break;
}
return $values;
}
}
@@ -0,0 +1,63 @@
<?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/>.
/**
* Class for exporting an object containing a name and a description.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\external;
defined('MOODLE_INTERNAL') || die();
use core\external\exporter;
/**
* Class that exports an object containing a name and a description.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class name_description_exporter extends exporter {
/**
* Returns a list of objects that are related.
*
* @return array
*/
protected static function define_related() {
return array(
'context' => 'context',
);
}
/**
* Return the list of properties.
*
* @return array
*/
protected static function define_properties() {
return [
'name' => [
'type' => PARAM_TEXT,
],
'description' => [
'type' => PARAM_TEXT,
],
];
}
}
@@ -0,0 +1,168 @@
<?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/>.
/**
* Class for exporting data purpose.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\external;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use core\external\persistent_exporter;
use DateInterval;
use Exception;
use renderer_base;
use tool_dataprivacy\context_instance;
use tool_dataprivacy\purpose;
/**
* Class for exporting field data.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class purpose_exporter extends persistent_exporter {
/**
* Defines the persistent class.
*
* @return string
*/
protected static function define_class() {
return purpose::class;
}
/**
* Returns a list of objects that are related.
*
* @return array
*/
protected static function define_related() {
return array(
'context' => 'context',
);
}
/**
* Return the list of additional properties.
*
* @return array
*/
protected static function define_other_properties() {
return [
'formattedretentionperiod' => [
'type' => PARAM_TEXT
],
'formattedlawfulbases' => [
'type' => name_description_exporter::read_properties_definition(),
'multiple' => true
],
'formattedsensitivedatareasons' => [
'type' => name_description_exporter::read_properties_definition(),
'multiple' => true,
'optional' => true
],
];
}
/**
* Return other properties.
*
* @param renderer_base $output
* @return array
* @throws coding_exception
* @throws Exception
*/
protected function get_other_values(renderer_base $output) {
$values = [];
$formattedbases = [];
$lawfulbases = explode(',', $this->persistent->get('lawfulbases'));
if (!empty($lawfulbases)) {
foreach ($lawfulbases as $basis) {
if (empty(trim($basis))) {
continue;
}
$formattedbases[] = (object)[
'name' => get_string($basis . '_name', 'tool_dataprivacy'),
'description' => get_string($basis . '_description', 'tool_dataprivacy')
];
}
}
$values['formattedlawfulbases'] = $formattedbases;
$formattedsensitivereasons = [];
$sensitivereasons = explode(',', $this->persistent->get('sensitivedatareasons'));
if (!empty($sensitivereasons)) {
foreach ($sensitivereasons as $reason) {
if (empty(trim($reason))) {
continue;
}
$formattedsensitivereasons[] = (object)[
'name' => get_string($reason . '_name', 'tool_dataprivacy'),
'description' => get_string($reason . '_description', 'tool_dataprivacy')
];
}
}
$values['formattedsensitivedatareasons'] = $formattedsensitivereasons;
$retentionperiod = $this->persistent->get('retentionperiod');
if ($retentionperiod) {
$interval = new DateInterval($retentionperiod);
// It is one or another.
if ($interval->y) {
$formattedtime = get_string('numyears', 'moodle', $interval->format('%y'));
} else if ($interval->m) {
$formattedtime = get_string('nummonths', 'moodle', $interval->format('%m'));
} else if ($interval->d) {
$formattedtime = get_string('numdays', 'moodle', $interval->format('%d'));
} else {
$formattedtime = get_string('retentionperiodzero', 'tool_dataprivacy');
}
} else {
$formattedtime = get_string('retentionperiodnotdefined', 'tool_dataprivacy');
}
$values['formattedretentionperiod'] = $formattedtime;
return $values;
}
/**
* Utility function that fetches a purpose name from the given ID.
*
* @param int $purposeid The purpose ID. Could be INHERIT (false, -1), NOT_SET (0), or the actual ID.
* @return string The purpose name.
*/
public static function get_name($purposeid) {
global $PAGE;
if ($purposeid === false || $purposeid == context_instance::INHERIT) {
return get_string('inherit', 'tool_dataprivacy');
} else if ($purposeid == context_instance::NOTSET) {
return get_string('notset', 'tool_dataprivacy');
} else {
$purpose = new purpose($purposeid);
$output = $PAGE->get_renderer('tool_dataprivacy');
$exporter = new self($purpose, ['context' => \context_system::instance()]);
$data = $exporter->export($output);
return $data->name;
}
}
}
@@ -0,0 +1,67 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the form add/update a data category.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\form;
defined('MOODLE_INTERNAL') || die();
use core\form\persistent;
/**
* Data category form.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class category extends persistent {
/**
* @var The persistent class.
*/
protected static $persistentclass = 'tool_dataprivacy\\category';
/**
* Define the form - called by parent constructor
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('text', 'name', get_string('name'), 'maxlength="100"');
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', get_string('required'), 'required', null, 'server');
$mform->addRule('name', get_string('maximumchars', '', 100), 'maxlength', 100, 'server');
$mform->addElement('editor', 'description', get_string('description'), null, ['autosave' => false]);
$mform->setType('description', PARAM_CLEANHTML);
if (!empty($this->_customdata['showbuttons'])) {
if (!$this->get_persistent()->get('id')) {
$savetext = get_string('add');
} else {
$savetext = get_string('savechanges');
}
$this->add_action_buttons(true, $savetext);
}
}
}
@@ -0,0 +1,226 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the form add/update context instance data.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\form;
defined('MOODLE_INTERNAL') || die();
use tool_dataprivacy\api;
use tool_dataprivacy\data_registry;
use tool_dataprivacy\purpose;
/**
* Context instance data form.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class context_instance extends \core\form\persistent {
/**
* @var The persistent class.
*/
protected static $persistentclass = 'tool_dataprivacy\\context_instance';
/**
* Define the form - called by parent constructor
*/
public function definition() {
$this->_form->setDisableShortforms();
$this->_form->addElement('header', 'contextname', $this->_customdata['contextname']);
$subjectscope = implode(', ', $this->_customdata['subjectscope']);
if (empty($subjectscope)) {
$subjectscope = get_string('noassignedroles', 'tool_dataprivacy');
}
$this->_form->addElement('static', 'subjectscope', get_string('subjectscope', 'tool_dataprivacy'), $subjectscope);
$this->_form->addHelpButton('subjectscope', 'subjectscope', 'tool_dataprivacy');
$this->add_purpose_category($this->_customdata['context']->contextlevel);
$this->_form->addElement('hidden', 'contextid');
$this->_form->setType('contextid', PARAM_INT);
parent::add_action_buttons(false, get_string('savechanges'));
}
/**
* Adds purpose and category selectors.
*
* @param int $contextlevel Apply this context level defaults. False for no defaults.
* @return null
*/
protected function add_purpose_category($contextlevel = false) {
$mform = $this->_form;
$addcategorytext = $this->get_add_element_content(get_string('addcategory', 'tool_dataprivacy'));
$categoryselect = $mform->createElement('select', 'categoryid', null, $this->_customdata['categories']);
$addcategory = $mform->createElement('button', 'addcategory', $addcategorytext, ['data-add-element' => 'category']);
$mform->addElement('group', 'categorygroup', get_string('category', 'tool_dataprivacy'),
[$categoryselect, $addcategory], null, false);
$mform->addHelpButton('categorygroup', 'category', 'tool_dataprivacy');
$mform->setType('categoryid', PARAM_INT);
$mform->setDefault('categoryid', 0);
$addpurposetext = $this->get_add_element_content(get_string('addpurpose', 'tool_dataprivacy'));
$purposeselect = $mform->createElement('select', 'purposeid', null, $this->_customdata['purposes']);
$addpurpose = $mform->createElement('button', 'addpurpose', $addpurposetext, ['data-add-element' => 'purpose']);
$mform->addElement('group', 'purposegroup', get_string('purpose', 'tool_dataprivacy'),
[$purposeselect, $addpurpose], null, false);
$mform->addHelpButton('purposegroup', 'purpose', 'tool_dataprivacy');
$mform->setType('purposeid', PARAM_INT);
$mform->setDefault('purposeid', 0);
if (!empty($this->_customdata['currentretentionperiod'])) {
$mform->addElement('static', 'retention_current', get_string('retentionperiod', 'tool_dataprivacy'),
$this->_customdata['currentretentionperiod']);
$mform->addHelpButton('retention_current', 'retentionperiod', 'tool_dataprivacy');
}
}
/**
* Returns the 'add' label.
*
* It depends on the theme in use.
*
* @param string $label
* @return \renderable|string
*/
private function get_add_element_content($label) {
global $PAGE, $OUTPUT;
$bs4 = false;
$theme = $PAGE->theme;
if ($theme->name === 'boost') {
$bs4 = true;
} else {
foreach ($theme->parents as $basetheme) {
if ($basetheme === 'boost') {
$bs4 = true;
}
}
}
if (!$bs4) {
return $label;
}
return $OUTPUT->pix_icon('e/insert', $label);
}
/**
* Returns the customdata array for the provided context instance.
*
* @param \context $context
* @return array
*/
public static function get_context_instance_customdata(\context $context) {
$persistent = \tool_dataprivacy\context_instance::get_record_by_contextid($context->id, false);
if (!$persistent) {
$persistent = new \tool_dataprivacy\context_instance();
$persistent->set('contextid', $context->id);
}
$purposes = [];
foreach (api::get_purposes() as $purpose) {
$purposes[$purpose->get('id')] = $purpose;
}
$purposeoptions = \tool_dataprivacy\output\data_registry_page::purpose_options($purposes);
$categoryoptions = \tool_dataprivacy\output\data_registry_page::category_options(api::get_categories());
$customdata = [
'context' => $context,
'subjectscope' => data_registry::get_subject_scope($context),
'contextname' => $context->get_context_name(),
'persistent' => $persistent,
'purposes' => $purposeoptions,
'categories' => $categoryoptions,
];
$effectivepurpose = api::get_effective_context_purpose($context);
if ($effectivepurpose) {
$customdata['currentretentionperiod'] = self::get_retention_display_text($effectivepurpose, $context->contextlevel,
$context);
$customdata['purposeretentionperiods'] = [];
foreach (array_keys($purposeoptions) as $optionvalue) {
if (isset($purposes[$optionvalue])) {
$purpose = $purposes[$optionvalue];
} else {
// Get the effective purpose if $optionvalue would be the selected value.
$purpose = api::get_effective_context_purpose($context, $optionvalue);
}
$retentionperiod = self::get_retention_display_text(
$purpose,
$context->contextlevel,
$context
);
$customdata['purposeretentionperiods'][$optionvalue] = $retentionperiod;
}
}
return $customdata;
}
/**
* Returns the purpose display text.
*
* @param purpose $effectivepurpose
* @param int $retentioncontextlevel
* @param \context $context The context, just for displaying (filters) purposes.
* @return string
*/
protected static function get_retention_display_text(purpose $effectivepurpose, $retentioncontextlevel, \context $context) {
global $PAGE;
$renderer = $PAGE->get_renderer('tool_dataprivacy');
$exporter = new \tool_dataprivacy\external\purpose_exporter($effectivepurpose, ['context' => $context]);
$exportedpurpose = $exporter->export($renderer);
switch ($retentioncontextlevel) {
case CONTEXT_COURSE:
case CONTEXT_MODULE:
case CONTEXT_BLOCK:
$str = get_string('effectiveretentionperiodcourse', 'tool_dataprivacy',
$exportedpurpose->formattedretentionperiod);
break;
case CONTEXT_USER:
$str = get_string('effectiveretentionperioduser', 'tool_dataprivacy',
$exportedpurpose->formattedretentionperiod);
break;
default:
$str = $exportedpurpose->formattedretentionperiod;
}
return $str;
}
}
@@ -0,0 +1,124 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the form add/update context level data.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\form;
defined('MOODLE_INTERNAL') || die();
use core\form\persistent;
use tool_dataprivacy\api;
use tool_dataprivacy\data_registry;
/**
* Context level data form.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class contextlevel extends context_instance {
/**
* @var The persistent class.
*/
protected static $persistentclass = 'tool_dataprivacy\\contextlevel';
/**
* Define the form - called by parent constructor
*/
public function definition() {
$this->_form->setDisableShortforms();
$this->_form->addElement('header', 'contextlevelname', $this->_customdata['contextlevelname']);
$this->add_purpose_category();
$this->_form->addElement('hidden', 'contextlevel');
$this->_form->setType('contextlevel', PARAM_INT);
parent::add_action_buttons(false, get_string('savechanges'));
}
/**
* Returns the customdata array for the provided context level.
*
* @param int $contextlevel
* @return array
*/
public static function get_contextlevel_customdata($contextlevel) {
$persistent = \tool_dataprivacy\contextlevel::get_record_by_contextlevel($contextlevel, false);
if (!$persistent) {
$persistent = new \tool_dataprivacy\contextlevel();
$persistent->set('contextlevel', $contextlevel);
}
$includeinherit = true;
if ($contextlevel == CONTEXT_SYSTEM) {
// Nothing to inherit from Site level.
$includeinherit = false;
}
$includenotset = true;
if ($contextlevel == CONTEXT_SYSTEM || $contextlevel == CONTEXT_USER) {
// No 'not set' value for system and user because we do not have defaults for them.
$includenotset = false;
}
$purposeoptions = \tool_dataprivacy\output\data_registry_page::purpose_options(
api::get_purposes(), $includenotset, $includeinherit);
$categoryoptions = \tool_dataprivacy\output\data_registry_page::category_options(
api::get_categories(), $includenotset, $includeinherit);
$customdata = [
'contextlevel' => $contextlevel,
'contextlevelname' => get_string('contextlevelname' . $contextlevel, 'tool_dataprivacy'),
'persistent' => $persistent,
'purposes' => $purposeoptions,
'categories' => $categoryoptions,
];
$effectivepurpose = api::get_effective_contextlevel_purpose($contextlevel);
if ($effectivepurpose) {
$customdata['currentretentionperiod'] = self::get_retention_display_text($effectivepurpose, $contextlevel,
\context_system::instance());
$customdata['purposeretentionperiods'] = [];
foreach ($purposeoptions as $optionvalue => $unused) {
// Get the effective purpose if $optionvalue would be the selected value.
list($purposeid, $unused) = data_registry::get_effective_default_contextlevel_purpose_and_category($contextlevel,
$optionvalue);
$purpose = new \tool_dataprivacy\purpose($purposeid);
$retentionperiod = self::get_retention_display_text(
$purpose,
$contextlevel,
\context_system::instance()
);
$customdata['purposeretentionperiods'][$optionvalue] = $retentionperiod;
}
}
return $customdata;
}
}
@@ -0,0 +1,149 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the form add/update a data purpose.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\form;
defined('MOODLE_INTERNAL') || die();
use core\form\persistent;
/**
* Data purpose form.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class purpose extends persistent {
/**
* @var string The persistent class.
*/
protected static $persistentclass = 'tool_dataprivacy\\purpose';
/**
* Define the form - called by parent constructor
*/
public function definition() {
$mform = $this->_form;
$mform->addElement('text', 'name', get_string('name'), 'maxlength="100"');
$mform->setType('name', PARAM_TEXT);
$mform->addRule('name', get_string('required'), 'required', null, 'server');
$mform->addRule('name', get_string('maximumchars', '', 100), 'maxlength', 100, 'server');
$mform->addElement('editor', 'description', get_string('description'), null, ['autosave' => false]);
$mform->setType('description', PARAM_CLEANHTML);
// Field for selecting lawful bases (from GDPR Article 6.1).
$lawfulbases = [];
foreach (\tool_dataprivacy\purpose::GDPR_ART_6_1_ITEMS as $article) {
$key = 'gdpr_art_6_1_' . $article;
$lawfulbases[$key] = get_string($key . '_name', 'tool_dataprivacy');
}
$options = array(
'multiple' => true,
);
$mform->addElement('autocomplete', 'lawfulbases', get_string('lawfulbases', 'tool_dataprivacy'), $lawfulbases, $options);
$mform->addRule('lawfulbases', get_string('required'), 'required', null, 'server');
$mform->addHelpButton('lawfulbases', 'lawfulbases', 'tool_dataprivacy');
// Optional field for selecting reasons for collecting sensitive personal data (from GDPR Article 9.2).
$sensitivereasons = [];
foreach (\tool_dataprivacy\purpose::GDPR_ART_9_2_ITEMS as $article) {
$key = 'gdpr_art_9_2_' . $article;
$sensitivereasons[$key] = get_string($key . '_name', 'tool_dataprivacy');
}
$mform->addElement('autocomplete', 'sensitivedatareasons', get_string('sensitivedatareasons', 'tool_dataprivacy'),
$sensitivereasons, $options);
$mform->addHelpButton('sensitivedatareasons', 'sensitivedatareasons', 'tool_dataprivacy');
$number = $mform->createElement('text', 'retentionperiodnumber', null, ['size' => 8]);
$unitoptions = [
'Y' => get_string('years'),
'M' => strtolower(get_string('months')),
'D' => strtolower(get_string('days'))
];
$unit = $mform->createElement('select', 'retentionperiodunit', '', $unitoptions);
$mform->addGroup(['number' => $number, 'unit' => $unit], 'retentionperiod',
get_string('retentionperiod', 'tool_dataprivacy'), null, false);
$mform->setType('retentionperiodnumber', PARAM_INT);
$this->_form->addElement('advcheckbox', 'protected', get_string('protected', 'tool_dataprivacy'),
get_string('protectedlabel', 'tool_dataprivacy'));
if (!empty($this->_customdata['showbuttons'])) {
if (!$this->get_persistent()->get('id')) {
$savetext = get_string('add');
} else {
$savetext = get_string('savechanges');
}
$this->add_action_buttons(true, $savetext);
}
}
/**
* Converts fields.
*
* @param \stdClass $data
* @return \stdClass
*/
protected static function convert_fields(\stdClass $data) {
$data = parent::convert_fields($data);
if (is_array($data->lawfulbases)) {
$data->lawfulbases = implode(',', $data->lawfulbases);
}
if (!empty($data->sensitivedatareasons) && is_array($data->sensitivedatareasons)) {
$data->sensitivedatareasons = implode(',', $data->sensitivedatareasons);
}
// A single value.
$data->retentionperiod = 'P' . $data->retentionperiodnumber . $data->retentionperiodunit;
unset($data->retentionperiodnumber);
unset($data->retentionperiodunit);
return $data;
}
/**
* Get the default data.
*
* @return \stdClass
*/
protected function get_default_data() {
$data = parent::get_default_data();
$data->lawfulbases = explode(',', $data->lawfulbases);
if (!empty($data->sensitivedatareasons)) {
$data->sensitivedatareasons = explode(',', $data->sensitivedatareasons);
}
// Convert the single properties into number and unit.
$strlen = strlen($data->retentionperiod);
$data->retentionperiodnumber = substr($data->retentionperiod, 1, $strlen - 2);
$data->retentionperiodunit = substr($data->retentionperiod, $strlen - 1);
unset($data->retentionperiod);
return $data;
}
}
@@ -0,0 +1,105 @@
<?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/>.
/**
* Filter selector field.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\form;
defined('MOODLE_INTERNAL') || die();
use MoodleQuickForm_autocomplete;
global $CFG;
require_once($CFG->libdir . '/form/autocomplete.php');
/**
* Form field type for choosing a user on the data request creation form.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class request_user_autocomplete extends MoodleQuickForm_autocomplete {
/**
* Constructor.
*
* @param string $elementname Element name
* @param mixed $elementlabel Label(s) for an element
* @param array $options Options to control the element's display
* Valid options are:
* - multiple bool Whether or not the field accepts more than one values.
*/
public function __construct($elementname = null, $elementlabel = null, $options = array()) {
$validattributes = array(
'ajax' => 'tool_dataprivacy/form-user-selector',
);
if (!empty($options['multiple'])) {
$validattributes['multiple'] = 'multiple';
}
parent::__construct($elementname, $elementlabel, array(), $validattributes);
}
/**
* Set the value of this element.
*
* @param string|array $value The value to set.
* @return boolean
*/
public function setValue($value) {
global $DB;
$values = (array) $value;
$ids = [];
foreach ($values as $onevalue) {
if (!empty($onevalue) && (!$this->optionExists($onevalue)) &&
($onevalue !== '_qf__force_multiselect_submission')) {
array_push($ids, $onevalue);
}
}
if (empty($ids)) {
return $this->setSelected([]);
}
$toselect = [];
list($insql, $inparams) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED);
$allusernames = get_all_user_name_fields(true);
// Exclude admins and guest user.
$excludedusers = array_keys(get_admins()) + [guest_user()->id];
$sort = 'firstname ASC';
$fields = 'id, email, ' . $allusernames;
// Fetch the selected users, exclude the admins and guest users.
$users = get_users(true, '', true, $excludedusers, $sort, '', '', 0, 30, $fields, "id $insql", $inparams);
foreach ($users as $user) {
$userdata = (object)[
'name' => fullname($user),
'email' => $user->email
];
$this->addOption(get_string('nameemail', 'tool_dataprivacy', $userdata), $user->id);
array_push($toselect, $user->id);
}
return $this->setSelected($toselect);
}
}
@@ -0,0 +1,251 @@
<?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/>.
/**
* Collection of helper functions for the data privacy tool.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\local;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use moodle_exception;
use tool_dataprivacy\api;
use tool_dataprivacy\data_request;
/**
* Class containing helper functions for the data privacy tool.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/** The default number of results to be shown per page. */
const DEFAULT_PAGE_SIZE = 20;
/** Filter constant associated with the request type filter. */
const FILTER_TYPE = 1;
/** Filter constant associated with the request status filter. */
const FILTER_STATUS = 2;
/** Filter constant associated with the request creation filter. */
const FILTER_CREATION = 3;
/** The request filters preference key. */
const PREF_REQUEST_FILTERS = 'tool_dataprivacy_request-filters';
/** The number of data request records per page preference key. */
const PREF_REQUEST_PERPAGE = 'tool_dataprivacy_request-perpage';
/**
* Retrieves the human-readable text value of a data request type.
*
* @param int $requesttype The request type.
* @return string
* @throws coding_exception
* @throws moodle_exception
*/
public static function get_request_type_string($requesttype) {
$types = self::get_request_types();
if (!isset($types[$requesttype])) {
throw new moodle_exception('errorinvalidrequesttype', 'tool_dataprivacy');
}
return $types[$requesttype];
}
/**
* Retrieves the human-readable shortened text value of a data request type.
*
* @param int $requesttype The request type.
* @return string
* @throws coding_exception
* @throws moodle_exception
*/
public static function get_shortened_request_type_string($requesttype) {
$types = self::get_request_types_short();
if (!isset($types[$requesttype])) {
throw new moodle_exception('errorinvalidrequesttype', 'tool_dataprivacy');
}
return $types[$requesttype];
}
/**
* Returns the key value-pairs of request type code and their string value.
*
* @return array
*/
public static function get_request_types() {
return [
api::DATAREQUEST_TYPE_EXPORT => get_string('requesttypeexport', 'tool_dataprivacy'),
api::DATAREQUEST_TYPE_DELETE => get_string('requesttypedelete', 'tool_dataprivacy'),
api::DATAREQUEST_TYPE_OTHERS => get_string('requesttypeothers', 'tool_dataprivacy'),
];
}
/**
* Returns the key value-pairs of request type code and their shortened string value.
*
* @return array
*/
public static function get_request_types_short() {
return [
api::DATAREQUEST_TYPE_EXPORT => get_string('requesttypeexportshort', 'tool_dataprivacy'),
api::DATAREQUEST_TYPE_DELETE => get_string('requesttypedeleteshort', 'tool_dataprivacy'),
api::DATAREQUEST_TYPE_OTHERS => get_string('requesttypeothersshort', 'tool_dataprivacy'),
];
}
/**
* Retrieves the human-readable value of a data request status.
*
* @param int $status The request status.
* @return string
* @throws moodle_exception
*/
public static function get_request_status_string($status) {
$statuses = self::get_request_statuses();
if (!isset($statuses[$status])) {
throw new moodle_exception('errorinvalidrequeststatus', 'tool_dataprivacy');
}
return $statuses[$status];
}
/**
* Returns the key value-pairs of request status code and string value.
*
* @return array
*/
public static function get_request_statuses() {
return [
api::DATAREQUEST_STATUS_PENDING => get_string('statuspending', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_PREPROCESSING => get_string('statuspreprocessing', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_AWAITING_APPROVAL => get_string('statusawaitingapproval', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_APPROVED => get_string('statusapproved', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_PROCESSING => get_string('statusprocessing', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_COMPLETE => get_string('statuscomplete', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_DOWNLOAD_READY => get_string('statusready', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_EXPIRED => get_string('statusexpired', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_CANCELLED => get_string('statuscancelled', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_REJECTED => get_string('statusrejected', 'tool_dataprivacy'),
api::DATAREQUEST_STATUS_DELETED => get_string('statusdeleted', 'tool_dataprivacy'),
];
}
/**
* Retrieves the human-readable value of a data request creation method.
*
* @param int $creation The request creation method.
* @return string
* @throws moodle_exception
*/
public static function get_request_creation_method_string($creation) {
$creationmethods = self::get_request_creation_methods();
if (!isset($creationmethods[$creation])) {
throw new moodle_exception('errorinvalidrequestcreationmethod', 'tool_dataprivacy');
}
return $creationmethods[$creation];
}
/**
* Returns the key value-pairs of request creation method code and string value.
*
* @return array
*/
public static function get_request_creation_methods() {
return [
data_request::DATAREQUEST_CREATION_MANUAL => get_string('creationmanual', 'tool_dataprivacy'),
data_request::DATAREQUEST_CREATION_AUTO => get_string('creationauto', 'tool_dataprivacy'),
];
}
/**
* Get the users that a user can make data request for.
*
* E.g. User having a parent role and has the 'tool/dataprivacy:makedatarequestsforchildren' capability.
* @param int $userid The user's ID.
* @return array
*/
public static function get_children_of_user($userid) {
global $DB;
// Get users that the user has role assignments to.
$allusernames = get_all_user_name_fields(true, 'u');
$sql = "SELECT u.id, $allusernames
FROM {role_assignments} ra, {context} c, {user} u
WHERE ra.userid = :userid
AND ra.contextid = c.id
AND c.instanceid = u.id
AND c.contextlevel = :contextlevel";
$params = [
'userid' => $userid,
'contextlevel' => CONTEXT_USER
];
// The final list of users that we will return.
$finalresults = [];
// Our prospective list of users.
if ($candidates = $DB->get_records_sql($sql, $params)) {
foreach ($candidates as $key => $child) {
$childcontext = \context_user::instance($child->id);
if (has_capability('tool/dataprivacy:makedatarequestsforchildren', $childcontext, $userid)) {
$finalresults[$key] = $child;
}
}
}
return $finalresults;
}
/**
* Get options for the data requests filter.
*
* @return array
* @throws coding_exception
*/
public static function get_request_filter_options() {
$filters = [
self::FILTER_TYPE => (object)[
'name' => get_string('requesttype', 'tool_dataprivacy'),
'options' => self::get_request_types_short()
],
self::FILTER_STATUS => (object)[
'name' => get_string('requeststatus', 'tool_dataprivacy'),
'options' => self::get_request_statuses()
],
self::FILTER_CREATION => (object)[
'name' => get_string('requestcreation', 'tool_dataprivacy'),
'options' => self::get_request_creation_methods()
],
];
$options = [];
foreach ($filters as $category => $filtercategory) {
foreach ($filtercategory->options as $key => $name) {
$option = (object)[
'category' => $filtercategory->name,
'name' => $name
];
$options["{$category}:{$key}"] = get_string('filteroption', 'tool_dataprivacy', $option);
}
}
return $options;
}
}
@@ -0,0 +1,76 @@
<?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/>.
/**
* Class \tool_dataprivacy\manager_observer.
*
* @package tool_dataprivacy
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
/**
* A failure observer for the \core_privacy\manager.
*
* @package tool_dataprivacy
* @copyright 2018 Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class manager_observer implements \core_privacy\manager_observer {
/**
* Notifies all DPOs that an exception occurred.
*
* @param \Throwable $e
* @param string $component
* @param string $interface
* @param string $methodname
* @param array $params
*/
public function handle_component_failure($e, $component, $interface, $methodname, array $params) {
// Get the list of the site Data Protection Officers.
$dpos = api::get_site_dpos();
$messagesubject = get_string('exceptionnotificationsubject', 'tool_dataprivacy');
$a = (object)[
'fullmethodname' => \core_privacy\manager::get_provider_classname_for_component($component) . '::' . $methodname,
'component' => $component,
'message' => $e->getMessage(),
'backtrace' => $e->getTraceAsString()
];
$messagebody = get_string('exceptionnotificationbody', 'tool_dataprivacy', $a);
// Email the data request to the Data Protection Officer(s)/Admin(s).
foreach ($dpos as $dpo) {
$message = new \core\message\message();
$message->courseid = SITEID;
$message->component = 'tool_dataprivacy';
$message->name = 'notifyexceptions';
$message->userfrom = \core_user::get_noreply_user();
$message->subject = $messagesubject;
$message->fullmessageformat = FORMAT_HTML;
$message->notification = 1;
$message->userto = $dpo;
$message->fullmessagehtml = $messagebody;
$message->fullmessage = html_to_text($messagebody);
// Send message.
message_send($message);
}
}
}
@@ -0,0 +1,168 @@
<?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/>.
/**
* Class containing helper methods for processing data requests.
*
* @package tool_dataprivacy
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy;
defined('MOODLE_INTERNAL') || die();
/**
* Class containing helper methods for processing data requests.
*
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class metadata_registry {
/**
* Returns plugin types / plugins and the user data that it stores in a format that can be sent to a template.
*
* @return array An array with all of the plugin types / plugins and the user data they store.
*/
public function get_registry_metadata() {
$manager = new \core_privacy\manager();
$manager->set_observer(new \tool_dataprivacy\manager_observer());
$pluginman = \core_plugin_manager::instance();
$contributedplugins = $this->get_contrib_list();
$metadata = $manager->get_metadata_for_components();
$fullyrichtree = $this->get_full_component_list();
foreach ($fullyrichtree as $branch => $leaves) {
$plugintype = $leaves['plugin_type'];
$plugins = array_map(function($component) use ($manager, $metadata, $contributedplugins, $plugintype, $pluginman) {
// Use the plugin name for the plugins, ignore for core subsystems.
$internaldata = ($plugintype == 'core') ? ['component' => $component] :
['component' => $pluginman->plugin_name($component)];
$internaldata['raw_component'] = $component;
if ($manager->component_is_compliant($component)) {
$internaldata['compliant'] = true;
if (isset($metadata[$component])) {
$collection = $metadata[$component]->get_collection();
$internaldata = $this->format_metadata($collection, $component, $internaldata);
} else if ($manager->is_empty_subsystem($component)) {
// This is an unused subsystem.
// Use the generic string.
$internaldata['nullprovider'] = get_string('privacy:subsystem:empty', 'core_privacy');
} else {
// Call get_reason for null provider.
$internaldata['nullprovider'] = get_string($manager->get_null_provider_reason($component), $component);
}
} else {
$internaldata['compliant'] = false;
}
// Check to see if we are an external plugin.
// Plugin names can contain _ characters, limit to 2 to just remove initial plugintype.
$componentshortname = explode('_', $component, 2);
$shortname = array_pop($componentshortname);
if (isset($contributedplugins[$plugintype][$shortname])) {
$internaldata['external'] = true;
}
// Check if the interface is deprecated.
if (!$manager->is_empty_subsystem($component)) {
$classname = $manager->get_provider_classname_for_component($component);
if (class_exists($classname)) {
$componentclass = new $classname();
if ($componentclass instanceof \core_privacy\local\deprecated) {
$internaldata['deprecated'] = true;
}
}
}
return $internaldata;
}, $leaves['plugins']);
$fullyrichtree[$branch]['plugin_type_raw'] = $plugintype;
// We're done using the plugin type. Convert it to a readable string.
$fullyrichtree[$branch]['plugin_type'] = $pluginman->plugintype_name($plugintype);
$fullyrichtree[$branch]['plugins'] = $plugins;
}
return $fullyrichtree;
}
/**
* Formats the metadata for use with a template.
*
* @param array $collection The collection associated with the component that we want to expand and format.
* @param string $component The component that we are dealing in
* @param array $internaldata The array to add the formatted metadata to.
* @return array The internal data array with the formatted metadata.
*/
protected function format_metadata($collection, $component, $internaldata) {
foreach ($collection as $collectioninfo) {
$privacyfields = $collectioninfo->get_privacy_fields();
$fields = '';
if (!empty($privacyfields)) {
$fields = array_map(function($key, $field) use ($component) {
return [
'field_name' => $key,
'field_summary' => get_string($field, $component)
];
}, array_keys($privacyfields), $privacyfields);
}
// Can the metadata types be located somewhere else besides core?
$items = explode('\\', get_class($collectioninfo));
$type = array_pop($items);
$typedata = [
'name' => $collectioninfo->get_name(),
'type' => $type,
'fields' => $fields,
'summary' => get_string($collectioninfo->get_summary(), $component)
];
if (strpos($type, 'subsystem_link') === 0 || strpos($type, 'plugintype_link') === 0) {
$typedata['link'] = true;
}
$internaldata['metadata'][] = $typedata;
}
return $internaldata;
}
/**
* Return the full list of components.
*
* @return array An array of plugin types which contain plugin data.
*/
protected function get_full_component_list() {
global $CFG;
$list = \core_component::get_component_list();
$list['core']['core'] = "{$CFG->dirroot}/lib";
$formattedlist = [];
foreach ($list as $plugintype => $plugin) {
$formattedlist[] = ['plugin_type' => $plugintype, 'plugins' => array_keys($plugin)];
}
return $formattedlist;
}
/**
* Returns a list of contributed plugins installed on the system.
*
* @return array A list of contributed plugins installed.
*/
protected function get_contrib_list() {
return array_map(function($plugins) {
return array_filter($plugins, function($plugindata) {
return !$plugindata->is_standard();
});
}, \core_plugin_manager::instance()->get_plugins());
}
}
@@ -0,0 +1,88 @@
<?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/>.
/**
* Categories renderable.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\external\category_exporter;
/**
* Class containing the categories page renderable.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class categories extends crud_element implements renderable, templatable {
/** @var array $categories All system categories. */
protected $categories = [];
/**
* Construct this renderable.
*
* @param \tool_dataprivacy\category[] $categories
*/
public function __construct($categories) {
$this->categories = $categories;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $PAGE;
$context = \context_system::instance();
$PAGE->requires->js_call_amd('tool_dataprivacy/categoriesactions', 'init');
$PAGE->requires->js_call_amd('tool_dataprivacy/add_category', 'getInstance', [$context->id]);
$data = new stdClass();
// Navigation links.
$data->navigation = [];
$navigationlinks = $this->get_navigation();
foreach ($navigationlinks as $navlink) {
$data->navigation[] = $navlink->export_for_template($output);
}
$data->categories = [];
foreach ($this->categories as $category) {
$exporter = new category_exporter($category, ['context' => \context_system::instance()]);
$exportedcategory = $exporter->export($output);
$actionmenu = $this->action_menu('category', $exportedcategory, $category);
$exportedcategory->actions = $actionmenu->export_for_template($output);
$data->categories[] = $exportedcategory;
}
return $data;
}
}
@@ -0,0 +1,92 @@
<?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/>.
/**
* Abstract renderer for independent renderable elements.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\external\purpose_exporter;
use tool_dataprivacy\external\category_exporter;
/**
* Abstract renderer for independent renderable elements.
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class crud_element {
/**
* Returns the top navigation buttons.
*
* @return \action_link[]
*/
protected final function get_navigation() {
$back = new \action_link(
new \moodle_url('/admin/tool/dataprivacy/dataregistry.php'),
get_string('back'),
null,
['class' => 'btn btn-default']
);
return [$back];
}
/**
* Adds an action menu for the provided element
*
* @param string $elementname 'purpose' or 'category'.
* @param \stdClass $exported
* @param \core\persistent $persistent
* @return \action_menu
*/
protected final function action_menu($elementname, $exported, $persistent) {
// Just in case, we are doing funny stuff below.
$elementname = clean_param($elementname, PARAM_ALPHA);
// Actions.
$actionmenu = new \action_menu();
$actionmenu->set_menu_trigger(get_string('actions'));
$actionmenu->set_owner_selector($elementname . '-' . $exported->id . '-actions');
$actionmenu->set_alignment(\action_menu::TL, \action_menu::BL);
$url = new \moodle_url('/admin/tool/dataprivacy/edit' . $elementname . '.php',
['id' => $exported->id]);
$link = new \action_menu_link_secondary($url, new \pix_icon('t/edit',
get_string('edit')), get_string('edit'));
$actionmenu->add($link);
if (!$persistent->is_used()) {
$url = new \moodle_url('#');
$attrs = ['data-id' => $exported->id, 'data-action' => 'delete' . $elementname, 'data-name' => $exported->name];
$link = new \action_menu_link_secondary($url, new \pix_icon('t/delete',
get_string('delete')), get_string('delete'), $attrs);
$actionmenu->add($link);
}
return $actionmenu;
}
}
@@ -0,0 +1,94 @@
<?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/>.
/**
* Class containing data for a user's data requests.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use single_select;
use stdClass;
use templatable;
use tool_dataprivacy\data_request;
use tool_dataprivacy\local\helper;
/**
* Class containing data for a user's data requests.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_deletion_page implements renderable, templatable {
/** @var data_request[] $requests List of data requests. */
protected $filter = null;
/** @var data_request[] $requests List of data requests. */
protected $expiredcontextstable = [];
/**
* Construct this renderable.
*
* @param \tool_dataprivacy\data_request[] $filter
* @param expired_contexts_table $expiredcontextstable
*/
public function __construct($filter, expired_contexts_table $expiredcontextstable) {
$this->filter = $filter;
$this->expiredcontextstable = $expiredcontextstable;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
$data = new stdClass();
$url = new moodle_url('/admin/tool/dataprivacy/datadeletion.php');
$options = [
CONTEXT_USER => get_string('user'),
CONTEXT_COURSE => get_string('course'),
CONTEXT_MODULE => get_string('activitiesandresources', 'tool_dataprivacy'),
CONTEXT_BLOCK => get_string('blocks'),
];
$filterselector = new single_select($url, 'filter', $options, $this->filter, null);
$data->filter = $filterselector->export_for_template($output);
ob_start();
$this->expiredcontextstable->out(helper::DEFAULT_PAGE_SIZE, true);
$expiredcontexts = ob_get_contents();
ob_end_clean();
$data->expiredcontexts = $expiredcontexts;
$data->existingcontexts = $this->expiredcontextstable->rawdata ? true : false;
return $data;
}
}
@@ -0,0 +1,60 @@
<?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/>.
/**
* Contains the data registry compliance renderable.
*
* @package tool_dataprivacy
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
/**
* Class containing the data registry compliance renderable
*
* @copyright 2018 Adrian Greeve
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_registry_compliance_page implements renderable, templatable {
/** @var array meta-data to be displayed about the system. */
protected $metadata;
/**
* Constructor.
*
* @param array $metadata
*/
public function __construct($metadata) {
$this->metadata = $metadata;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
return ['types' => $this->metadata];
}
}
@@ -0,0 +1,481 @@
<?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/>.
/**
* Data registry renderable.
*
* @package tool_dataprivacy
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\data_registry;
require_once($CFG->libdir . '/coursecatlib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/dataprivacy/lib.php');
require_once($CFG->libdir . '/blocklib.php');
/**
* Class containing the data registry renderable
*
* @copyright 2018 David Monllao
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_registry_page implements renderable, templatable {
/**
* @var int
*/
private $defaultcontextlevel;
/**
* @var int
*/
private $defaultcontextid;
/**
* Constructor.
*
* @param int $defaultcontextlevel
* @param int $defaultcontextid
* @return null
*/
public function __construct($defaultcontextlevel = false, $defaultcontextid = false) {
$this->defaultcontextlevel = $defaultcontextlevel;
$this->defaultcontextid = $defaultcontextid;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $PAGE;
$params = [\context_system::instance()->id, $this->defaultcontextlevel, $this->defaultcontextid];
$PAGE->requires->js_call_amd('tool_dataprivacy/data_registry', 'init', $params);
$data = new stdClass();
$defaultsbutton = new \action_link(
new \moodle_url('/admin/tool/dataprivacy/defaults.php'),
get_string('setdefaults', 'tool_dataprivacy'),
null,
['class' => 'btn btn-default']
);
$data->defaultsbutton = $defaultsbutton->export_for_template($output);
$actionmenu = new \action_menu();
$actionmenu->set_menu_trigger(get_string('edit'), 'btn btn-default');
$actionmenu->set_owner_selector('dataregistry-actions');
$actionmenu->set_alignment(\action_menu::TL, \action_menu::BL);
$url = new \moodle_url('/admin/tool/dataprivacy/categories.php');
$categories = new \action_menu_link_secondary($url, null, get_string('categories', 'tool_dataprivacy'));
$actionmenu->add($categories);
$url = new \moodle_url('/admin/tool/dataprivacy/purposes.php');
$purposes = new \action_menu_link_secondary($url, null, get_string('purposes', 'tool_dataprivacy'));
$actionmenu->add($purposes);
$data->actions = $actionmenu->export_for_template($output);
if (!data_registry::defaults_set()) {
$data->info = (object)[
'message' => get_string('dataregistryinfo', 'tool_dataprivacy'),
'announce' => 1
];
$data->nosystemdefaults = (object)[
'message' => get_string('nosystemdefaults', 'tool_dataprivacy'),
'announce' => 1
];
}
$data->tree = $this->get_default_tree_structure();
return $data;
}
/**
* Returns the tree default structure.
*
* @return array
*/
private function get_default_tree_structure() {
$frontpage = \context_course::instance(SITEID);
$categorybranches = $this->get_all_category_branches();
$elements = [
'text' => get_string('contextlevelname' . CONTEXT_SYSTEM, 'tool_dataprivacy'),
'contextlevel' => CONTEXT_SYSTEM,
'branches' => [
[
'text' => get_string('user'),
'contextlevel' => CONTEXT_USER,
], [
'text' => get_string('categories'),
'branches' => $categorybranches,
'expandelement' => 'category',
], [
'text' => get_string('frontpagecourse', 'tool_dataprivacy'),
'contextid' => $frontpage->id,
'branches' => [
[
'text' => get_string('activitiesandresources', 'tool_dataprivacy'),
'expandcontextid' => $frontpage->id,
'expandelement' => 'module',
'expanded' => 0,
], [
'text' => get_string('blocks'),
'expandcontextid' => $frontpage->id,
'expandelement' => 'block',
'expanded' => 0,
],
]
]
]
];
// Returned as an array to follow a common array format.
return [self::complete($elements, $this->defaultcontextlevel, $this->defaultcontextid)];
}
/**
* Returns the hierarchy of system course categories.
*
* @return array
*/
private function get_all_category_branches() {
$categories = data_registry::get_site_categories();
$categoriesbranch = [];
while (count($categories) > 0) {
foreach ($categories as $key => $category) {
$context = \context_coursecat::instance($category->id);
$newnode = [
'text' => shorten_text(format_string($category->name, true, ['context' => $context])),
'categoryid' => $category->id,
'contextid' => $context->id,
];
if ($category->coursecount > 0) {
$newnode['branches'] = [
[
'text' => get_string('courses'),
'expandcontextid' => $context->id,
'expandelement' => 'course',
'expanded' => 0,
]
];
}
$added = false;
if ($category->parent == 0) {
// New categories root-level node.
$categoriesbranch[] = $newnode;
$added = true;
} else {
// Add the new node under the appropriate parent.
if ($this->add_to_parent_category_branch($category, $newnode, $categoriesbranch)) {
$added = true;
}
}
if ($added) {
unset($categories[$key]);
}
}
}
return $categoriesbranch;
}
/**
* Gets the courses branch for the provided category.
*
* @param \context $catcontext
* @return array
*/
public static function get_courses_branch(\context $catcontext) {
if ($catcontext->contextlevel !== CONTEXT_COURSECAT) {
throw new \coding_exception('A course category context should be provided');
}
$coursecat = \coursecat::get($catcontext->instanceid);
$courses = $coursecat->get_courses();
$branches = [];
foreach ($courses as $course) {
$coursecontext = \context_course::instance($course->id);
if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
continue;
}
$coursenode = [
'text' => shorten_text(format_string($course->shortname, true, ['context' => $coursecontext])),
'contextid' => $coursecontext->id,
'branches' => [
[
'text' => get_string('activitiesandresources', 'tool_dataprivacy'),
'expandcontextid' => $coursecontext->id,
'expandelement' => 'module',
'expanded' => 0,
], [
'text' => get_string('blocks'),
'expandcontextid' => $coursecontext->id,
'expandelement' => 'block',
'expanded' => 0,
],
]
];
$branches[] = self::complete($coursenode);
}
return $branches;
}
/**
* Gets the modules branch for the provided course.
*
* @param \context $coursecontext
* @return array
*/
public static function get_modules_branch(\context $coursecontext) {
if ($coursecontext->contextlevel !== CONTEXT_COURSE) {
throw new \coding_exception('A course context should be provided');
}
$branches = [];
// Using the current user.
$modinfo = get_fast_modinfo($coursecontext->instanceid);
foreach ($modinfo->get_instances() as $moduletype => $instances) {
foreach ($instances as $cm) {
if (!$cm->uservisible) {
continue;
}
$a = (object)[
'instancename' => shorten_text($cm->get_formatted_name()),
'modulename' => get_string('pluginname', 'mod_' . $moduletype),
];
$text = get_string('moduleinstancename', 'tool_dataprivacy', $a);
$branches[] = self::complete([
'text' => $text,
'contextid' => $cm->context->id,
]);
}
}
return $branches;
}
/**
* Gets the blocks branch for the provided course.
*
* @param \context $coursecontext
* @return null
*/
public static function get_blocks_branch(\context $coursecontext) {
global $DB;
if ($coursecontext->contextlevel !== CONTEXT_COURSE) {
throw new \coding_exception('A course context should be provided');
}
$branches = [];
$children = $coursecontext->get_child_contexts();
foreach ($children as $childcontext) {
if ($childcontext->contextlevel !== CONTEXT_BLOCK) {
continue;
}
$blockinstance = block_instance_by_id($childcontext->instanceid);
$displayname = shorten_text(format_string($blockinstance->get_title(), true, ['context' => $childcontext]));
$branches[] = self::complete([
'text' => $displayname,
'contextid' => $childcontext->id,
]);
}
return $branches;
}
/**
* Adds the provided category to the categories branch.
*
* @param stdClass $category
* @param array $newnode
* @param array $categoriesbranch
* @return bool
*/
private function add_to_parent_category_branch($category, $newnode, &$categoriesbranch) {
foreach ($categoriesbranch as $key => $branch) {
if (!empty($branch['categoryid']) && $branch['categoryid'] == $category->parent) {
// It may be empty (if it does not contain courses and this is the first child cat).
if (!isset($categoriesbranch[$key]['branches'])) {
$categoriesbranch[$key]['branches'] = [];
}
$categoriesbranch[$key]['branches'][] = $newnode;
return true;
}
if (!empty($branch['branches'])) {
$parent = $this->add_to_parent_category_branch($category, $newnode, $categoriesbranch[$key]['branches']);
if ($parent) {
return true;
}
}
}
return false;
}
/**
* Completes tree nodes with default values.
*
* @param array $node
* @param int|false $currentcontextlevel
* @param int|false $currentcontextid
* @return array
*/
private static function complete($node, $currentcontextlevel = false, $currentcontextid = false) {
if (!isset($node['active'])) {
if ($currentcontextlevel && !empty($node['contextlevel']) &&
$currentcontextlevel == $node['contextlevel'] &&
empty($currentcontextid)) {
// This is the active context level, we also checked that there
// is no default contextid set.
$node['active'] = true;
} else if ($currentcontextid && !empty($node['contextid']) &&
$currentcontextid == $node['contextid']) {
$node['active'] = true;
} else {
$node['active'] = null;
}
}
if (!isset($node['branches'])) {
$node['branches'] = [];
} else {
foreach ($node['branches'] as $key => $childnode) {
$node['branches'][$key] = self::complete($childnode, $currentcontextlevel, $currentcontextid);
}
}
if (!isset($node['expandelement'])) {
$node['expandelement'] = null;
}
if (!isset($node['expandcontextid'])) {
$node['expandcontextid'] = null;
}
if (!isset($node['contextid'])) {
$node['contextid'] = null;
}
if (!isset($node['contextlevel'])) {
$node['contextlevel'] = null;
}
if (!isset($node['expanded'])) {
if (!empty($node['branches'])) {
$node['expanded'] = 1;
} else {
$node['expanded'] = 0;
}
}
return $node;
}
/**
* From a list of purpose persistents to a list of id => name purposes.
*
* @param \tool_dataprivacy\purpose[] $purposes
* @param bool $includenotset
* @param bool $includeinherit
* @return string[]
*/
public static function purpose_options($purposes, $includenotset = true, $includeinherit = true) {
$options = self::base_options($includenotset, $includeinherit);
foreach ($purposes as $purpose) {
$options[$purpose->get('id')] = $purpose->get('name');
}
return $options;
}
/**
* From a list of category persistents to a list of id => name categories.
*
* @param \tool_dataprivacy\category[] $categories
* @param bool $includenotset
* @param bool $includeinherit
* @return string[]
*/
public static function category_options($categories, $includenotset = true, $includeinherit = true) {
$options = self::base_options($includenotset, $includeinherit);
foreach ($categories as $category) {
$options[$category->get('id')] = $category->get('name');
}
return $options;
}
/**
* Base not set and inherit options.
*
* @param bool $includenotset
* @param bool $includeinherit
* @return array
*/
private static function base_options($includenotset = true, $includeinherit = true) {
$options = [];
if ($includenotset) {
$options[\tool_dataprivacy\context_instance::NOTSET] = get_string('notset', 'tool_dataprivacy');
}
if ($includeinherit) {
$options[\tool_dataprivacy\context_instance::INHERIT] = get_string('inherit', 'tool_dataprivacy');
}
return $options;
}
}
@@ -0,0 +1,96 @@
<?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/>.
/**
* Class containing data for a user's data requests.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use coding_exception;
use dml_exception;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use single_select;
use stdClass;
use templatable;
use tool_dataprivacy\api;
use tool_dataprivacy\local\helper;
/**
* Class containing data for a user's data requests.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_requests_page implements renderable, templatable {
/** @var data_requests_table $table The data requests table. */
protected $table;
/** @var int[] $filters The applied filters. */
protected $filters = [];
/**
* Construct this renderable.
*
* @param data_requests_table $table The data requests table.
* @param int[] $filters The applied filters.
*/
public function __construct($table, $filters) {
$this->table = $table;
$this->filters = $filters;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws dml_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
$data = new stdClass();
$data->newdatarequesturl = new moodle_url('/admin/tool/dataprivacy/createdatarequest.php');
$data->newdatarequesturl->param('manage', true);
if (!is_https()) {
$httpwarningmessage = get_string('httpwarning', 'tool_dataprivacy');
$data->httpsite = array('message' => $httpwarningmessage, 'announce' => 1);
}
$url = new moodle_url('/admin/tool/dataprivacy/datarequests.php');
$filteroptions = helper::get_request_filter_options();
$filter = new request_filter($filteroptions, $this->filters, $url);
$data->filter = $filter->export_for_template($output);
ob_start();
$this->table->out($this->table->get_requests_per_page(), true);
$requests = ob_get_contents();
ob_end_clean();
$data->datarequests = $requests;
return $data;
}
}
@@ -0,0 +1,395 @@
<?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/>.
/**
* Contains the class used for the displaying the data requests table.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/tablelib.php');
use action_menu;
use action_menu_link_secondary;
use coding_exception;
use dml_exception;
use html_writer;
use moodle_url;
use stdClass;
use table_sql;
use tool_dataprivacy\api;
use tool_dataprivacy\external\data_request_exporter;
defined('MOODLE_INTERNAL') || die;
/**
* The class for displaying the data requests table.
*
* @copyright 2018 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class data_requests_table extends table_sql {
/** @var int The user ID. */
protected $userid = 0;
/** @var int[] The status filters. */
protected $statuses = [];
/** @var int[] The request type filters. */
protected $types = [];
/** @var bool Whether this table is being rendered for managing data requests. */
protected $manage = false;
/** @var \tool_dataprivacy\data_request[] Array of data request persistents. */
protected $datarequests = [];
/** @var int The number of data request to be displayed per page. */
protected $perpage;
/** @var int[] The available options for the number of data request to be displayed per page. */
protected $perpageoptions = [25, 50, 100, 250];
/**
* data_requests_table constructor.
*
* @param int $userid The user ID
* @param int[] $statuses
* @param int[] $types
* @param int[] $creationmethods
* @param bool $manage
* @throws coding_exception
*/
public function __construct($userid = 0, $statuses = [], $types = [], $creationmethods = [], $manage = false) {
parent::__construct('data-requests-table');
$this->userid = $userid;
$this->statuses = $statuses;
$this->types = $types;
$this->creationmethods = $creationmethods;
$this->manage = $manage;
$checkboxattrs = [
'title' => get_string('selectall'),
'data-action' => 'selectall'
];
$columnheaders = [
'select' => html_writer::checkbox('selectall', 1, false, null, $checkboxattrs),
'type' => get_string('requesttype', 'tool_dataprivacy'),
'userid' => get_string('user', 'tool_dataprivacy'),
'timecreated' => get_string('daterequested', 'tool_dataprivacy'),
'requestedby' => get_string('requestby', 'tool_dataprivacy'),
'status' => get_string('requeststatus', 'tool_dataprivacy'),
'comments' => get_string('message', 'tool_dataprivacy'),
'actions' => '',
];
$this->define_columns(array_keys($columnheaders));
$this->define_headers(array_values($columnheaders));
$this->no_sorting('select', 'actions');
}
/**
* The select column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_select($data) {
if ($data->status == \tool_dataprivacy\api::DATAREQUEST_STATUS_AWAITING_APPROVAL) {
$stringdata = [
'username' => $data->foruser->fullname,
'requesttype' => \core_text::strtolower($data->typenameshort)
];
return \html_writer::checkbox('requestids[]', $data->id, false, '',
['class' => 'selectrequests', 'title' => get_string('selectuserdatarequest',
'tool_dataprivacy', $stringdata)]);
}
}
/**
* The type column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_type($data) {
if ($this->manage) {
return $data->typenameshort;
}
return $data->typename;
}
/**
* The user column.
*
* @param stdClass $data The row data.
* @return mixed
*/
public function col_userid($data) {
$user = $data->foruser;
return html_writer::link($user->profileurl, $user->fullname, ['title' => get_string('viewprofile')]);
}
/**
* The context information column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_timecreated($data) {
return userdate($data->timecreated);
}
/**
* The requesting user's column.
*
* @param stdClass $data The row data.
* @return mixed
*/
public function col_requestedby($data) {
$user = $data->requestedbyuser;
return html_writer::link($user->profileurl, $user->fullname, ['title' => get_string('viewprofile')]);
}
/**
* The status column.
*
* @param stdClass $data The row data.
* @return mixed
*/
public function col_status($data) {
return html_writer::span($data->statuslabel, 'label ' . $data->statuslabelclass);
}
/**
* The comments column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_comments($data) {
return shorten_text($data->comments, 60);
}
/**
* The actions column.
*
* @param stdClass $data The row data.
* @return string
*/
public function col_actions($data) {
global $OUTPUT;
$requestid = $data->id;
$status = $data->status;
// Prepare actions.
$actions = [];
// View action.
$actionurl = new moodle_url('#');
$actiondata = ['data-action' => 'view', 'data-requestid' => $requestid];
$actiontext = get_string('viewrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
switch ($status) {
case api::DATAREQUEST_STATUS_PENDING:
// Add action to mark a general enquiry request as complete.
if ($data->type == api::DATAREQUEST_TYPE_OTHERS) {
$actiondata['data-action'] = 'complete';
$nameemail = (object)[
'name' => $data->foruser->fullname,
'email' => $data->foruser->email
];
$actiondata['data-requestid'] = $data->id;
$actiondata['data-replytoemail'] = get_string('nameemail', 'tool_dataprivacy', $nameemail);
$actiontext = get_string('markcomplete', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
}
break;
case api::DATAREQUEST_STATUS_AWAITING_APPROVAL:
// Approve.
$actiondata['data-action'] = 'approve';
$actiontext = get_string('approverequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
// Deny.
$actiondata['data-action'] = 'deny';
$actiontext = get_string('denyrequest', 'tool_dataprivacy');
$actions[] = new action_menu_link_secondary($actionurl, null, $actiontext, $actiondata);
break;
case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
$userid = $data->foruser->id;
$usercontext = \context_user::instance($userid, IGNORE_MISSING);
// If user has permission to view download link, show relevant action item.
if ($usercontext && api::can_download_data_request_for_user($userid, $data->requestedbyuser->id)) {
$actions[] = api::get_download_link($usercontext, $requestid);
}
break;
}
$actionsmenu = new action_menu($actions);
$actionsmenu->set_menu_trigger(get_string('actions'));
$actionsmenu->set_owner_selector('request-actions-' . $requestid);
$actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL);
$actionsmenu->set_constraint('[data-region=data-requests-table] > .no-overflow');
return $OUTPUT->render($actionsmenu);
}
/**
* Query the database for results to display in the table.
*
* @param int $pagesize size of page for paginated displayed table.
* @param bool $useinitialsbar do you want to use the initials bar.
* @throws dml_exception
* @throws coding_exception
*/
public function query_db($pagesize, $useinitialsbar = true) {
global $PAGE;
// Set dummy page total until we fetch full result set.
$this->pagesize($pagesize, $pagesize + 1);
$sort = $this->get_sql_sort();
// Get data requests from the given conditions.
$datarequests = api::get_data_requests($this->userid, $this->statuses, $this->types,
$this->creationmethods, $sort, $this->get_page_start(), $this->get_page_size());
// Count data requests from the given conditions.
$total = api::get_data_requests_count($this->userid, $this->statuses, $this->types,
$this->creationmethods);
$this->pagesize($pagesize, $total);
$this->rawdata = [];
$context = \context_system::instance();
$renderer = $PAGE->get_renderer('tool_dataprivacy');
foreach ($datarequests as $persistent) {
$this->datarequests[$persistent->get('id')] = $persistent;
$exporter = new data_request_exporter($persistent, ['context' => $context]);
$this->rawdata[] = $exporter->export($renderer);
}
// Set initial bars.
if ($useinitialsbar) {
$this->initialbars($total > $pagesize);
}
}
/**
* Override default implementation to display a more meaningful information to the user.
*/
public function print_nothing_to_display() {
global $OUTPUT;
echo $this->render_reset_button();
$this->print_initials_bar();
if (!empty($this->statuses) || !empty($this->types)) {
$message = get_string('nodatarequestsmatchingfilter', 'tool_dataprivacy');
} else {
$message = get_string('nodatarequests', 'tool_dataprivacy');
}
echo $OUTPUT->notification($message, 'warning');
}
/**
* Override the table's show_hide_link method to prevent the show/hide links from rendering.
*
* @param string $column the column name, index into various names.
* @param int $index numerical index of the column.
* @return string HTML fragment.
*/
protected function show_hide_link($column, $index) {
return '';
}
/**
* Override the table's wrap_html_finish method in order to render the bulk actions and
* records per page options.
*/
public function wrap_html_finish() {
global $OUTPUT;
$data = new stdClass();
$data->options = [
[
'value' => 0,
'name' => ''
],
[
'value' => \tool_dataprivacy\api::DATAREQUEST_ACTION_APPROVE,
'name' => get_string('approve', 'tool_dataprivacy')
],
[
'value' => \tool_dataprivacy\api::DATAREQUEST_ACTION_REJECT,
'name' => get_string('deny', 'tool_dataprivacy')
]
];
$perpageoptions = array_combine($this->perpageoptions, $this->perpageoptions);
$perpageselect = new \single_select(new moodle_url(''), 'perpage',
$perpageoptions, get_user_preferences('tool_dataprivacy_request-perpage'), null, 'selectgroup');
$perpageselect->label = get_string('perpage', 'moodle');
$data->perpage = $OUTPUT->render($perpageselect);
echo $OUTPUT->render_from_template('tool_dataprivacy/data_requests_bulk_actions', $data);
}
/**
* Set the number of data request records to be displayed per page.
*
* @param int $perpage The number of data request records.
*/
public function set_requests_per_page($perpage) {
$this->perpage = $perpage;
}
/**
* Get the number of data request records to be displayed per page.
*
* @return int The number of data request records.
*/
public function get_requests_per_page() {
return $this->perpage;
}
/**
* Set the available options for the number of data request to be displayed per page.
*
* @param array $perpageoptions The available options for the number of data request to be displayed per page.
*/
public function set_requests_per_page_options($perpageoptions) {
$this->$perpageoptions = $perpageoptions;
}
/**
* Get the available options for the number of data request to be displayed per page.
*
* @return array The available options for the number of data request to be displayed per page.
*/
public function get_requests_per_page_options() {
return $this->perpageoptions;
}
}
@@ -0,0 +1,178 @@
<?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/>.
/**
* Class containing data for the data registry defaults.
*
* @package tool_dataprivacy
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_dataprivacy\output;
defined('MOODLE_INTERNAL') || die();
use action_menu_link_primary;
use coding_exception;
use moodle_exception;
use moodle_url;
use renderable;
use renderer_base;
use stdClass;
use templatable;
use tool_dataprivacy\data_registry;
use tool_dataprivacy\external\category_exporter;
use tool_dataprivacy\external\purpose_exporter;
/**
* Class containing data for the data registry defaults.
*
* @copyright 2018 Jun Pataleta
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class defaults_page implements renderable, templatable {
/** @var int $mode The display mode. */
protected $mode = null;
/** @var int $category The default category for the given mode. */
protected $category = null;
/** @var int $purpose The default purpose for the given mode. */
protected $purpose = null;
/** @var stdClass[] $otherdefaults Other defaults for the given mode. */
protected $otherdefaults = [];
/** @var bool $canedit Whether editing is allowed. */
protected $canedit = false;
/**
* Construct this renderable.
*
* @param int $mode The display mode.
* @param int $category The default category for the given mode.
* @param int $purpose The default purpose for the given mode.
* @param stdClass[] $otherdefaults Other defaults for the given mode.
* @param bool $canedit Whether editing is allowed.
*/
public function __construct($mode, $category, $purpose, $otherdefaults = [], $canedit = false) {
$this->mode = $mode;
$this->category = $category;
$this->purpose = $purpose;
$this->otherdefaults = $otherdefaults;
$this->canedit = $canedit;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param renderer_base $output
* @return stdClass
* @throws coding_exception
* @throws moodle_exception
*/
public function export_for_template(renderer_base $output) {
$data = new stdClass();
// Set tab URLs.
$coursecaturl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_COURSECAT]);
$courseurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_COURSE]);
$moduleurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_MODULE]);
$blockurl = new moodle_url('/admin/tool/dataprivacy/defaults.php', ['mode' => CONTEXT_BLOCK]);
$data->coursecaturl = $coursecaturl;
$data->courseurl = $courseurl;
$data->moduleurl = $moduleurl;
$data->blockurl = $blockurl;
// Set display mode.
switch ($this->mode) {
case CONTEXT_COURSECAT:
$data->modecoursecat = true;
break;
case CONTEXT_COURSE:
$data->modecourse = true;
break;
case CONTEXT_MODULE:
$data->modemodule = true;
break;
case CONTEXT_BLOCK:
$data->modeblock = true;
break;
default:
$data->modecoursecat = true;
break;
}
// Set config variables.
$configname = \context_helper::get_class_for_level($this->mode);
list($purposevar, $categoryvar) = data_registry::var_names_from_context($configname);
$data->categoryvar = $categoryvar;
$data->purposevar = $purposevar;
// Set default category.
$data->categoryid = $this->category;
$data->category = category_exporter::get_name($this->category);
// Set default purpose.
$data->purposeid = $this->purpose;
$data->purpose = purpose_exporter::get_name($this->purpose);
// Set other defaults.
$otherdefaults = [];
$url = new moodle_url('#');
foreach ($this->otherdefaults as $pluginname => $values) {
$defaults = [
'name' => $values->name,
'category' => category_exporter::get_name($values->category),
'purpose' => purpose_exporter::get_name($values->purpose),
];
if ($this->canedit) {
$actions = [];
// Edit link.
$editattrs = [
'data-action' => 'edit-activity-defaults',
'data-contextlevel' => $this->mode,
'data-activityname' => $pluginname,
'data-category' => $values->category,
'data-purpose' => $values->purpose,
];
$editlink = new action_menu_link_primary($url, new \pix_icon('t/edit', get_string('edit')),
get_string('edit'), $editattrs);
$actions[] = $editlink->export_for_template($output);
// Delete link.
$deleteattrs = [
'data-action' => 'delete-activity-defaults',
'data-contextlevel' => $this->mode,
'data-activityname' => $pluginname,
'data-activitydisplayname' => $values->name,
];
$deletelink = new action_menu_link_primary($url, new \pix_icon('t/delete', get_string('delete')),
get_string('delete'), $deleteattrs);
$actions[] = $deletelink->export_for_template($output);
$defaults['actions'] = $actions;
}
$otherdefaults[] = (object)$defaults;
}
$data->otherdefaults = $otherdefaults;
$data->canedit = $this->canedit;
$data->contextlevel = $this->mode;
return $data;
}
}

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