Merge branch 'MDL-62056-master' of git://github.com/sarjona/moodle
authorDavid Monllao <davidm@moodle.com>
Wed, 9 May 2018 13:20:46 +0000 (15:20 +0200)
committerJun Pataleta <jun@moodle.com>
Thu, 10 May 2018 01:17:28 +0000 (09:17 +0800)
513 files changed:
admin/roles/classes/privacy/provider.php [new file with mode: 0644]
admin/roles/tests/privacy_test.php [new file with mode: 0644]
admin/tool/analytics/version.php
admin/tool/assignmentupgrade/version.php
admin/tool/availabilityconditions/version.php
admin/tool/behat/version.php
admin/tool/capability/version.php
admin/tool/cohortroles/version.php
admin/tool/customlang/version.php
admin/tool/dataprivacy/version.php
admin/tool/dbtransfer/version.php
admin/tool/filetypes/version.php
admin/tool/generator/version.php
admin/tool/health/version.php
admin/tool/httpsreplace/version.php
admin/tool/innodb/version.php
admin/tool/installaddon/version.php
admin/tool/langimport/version.php
admin/tool/log/store/database/version.php
admin/tool/log/store/legacy/version.php
admin/tool/log/store/standard/version.php
admin/tool/log/version.php
admin/tool/lp/version.php
admin/tool/lpimportcsv/version.php
admin/tool/lpmigrate/version.php
admin/tool/messageinbound/version.php
admin/tool/mobile/version.php
admin/tool/monitor/version.php
admin/tool/multilangupgrade/version.php
admin/tool/oauth2/version.php
admin/tool/phpunit/version.php
admin/tool/policy/version.php
admin/tool/profiling/version.php
admin/tool/recyclebin/version.php
admin/tool/replace/version.php
admin/tool/spamcleaner/version.php
admin/tool/task/version.php
admin/tool/templatelibrary/version.php
admin/tool/unsuproles/version.php
admin/tool/uploadcourse/version.php
admin/tool/uploaduser/version.php
admin/tool/usertours/version.php
admin/tool/xmldb/version.php
auth/cas/version.php
auth/db/version.php
auth/email/version.php
auth/ldap/version.php
auth/lti/version.php
auth/manual/version.php
auth/mnet/classes/privacy/provider.php
auth/mnet/lang/en/auth_mnet.php
auth/mnet/tests/privacy_provider_test.php [new file with mode: 0644]
auth/mnet/version.php
auth/nologin/version.php
auth/none/version.php
auth/oauth2/version.php
auth/shibboleth/version.php
auth/webservice/version.php
availability/condition/completion/version.php
availability/condition/date/version.php
availability/condition/grade/version.php
availability/condition/group/version.php
availability/condition/grouping/version.php
availability/condition/profile/version.php
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js
availability/yui/src/form/js/form.js
backup/backup.class.php
blocks/activity_modules/version.php
blocks/activity_results/version.php
blocks/admin_bookmarks/version.php
blocks/badges/version.php
blocks/blog_menu/version.php
blocks/blog_recent/version.php
blocks/blog_tags/version.php
blocks/calendar_month/version.php
blocks/calendar_upcoming/version.php
blocks/comments/version.php
blocks/community/version.php
blocks/completionstatus/version.php
blocks/course_list/version.php
blocks/course_summary/version.php
blocks/feedback/version.php
blocks/globalsearch/version.php
blocks/glossary_random/version.php
blocks/html/version.php
blocks/login/version.php
blocks/lp/version.php
blocks/mentees/version.php
blocks/mnet_hosts/version.php
blocks/myoverview/version.php
blocks/myprofile/version.php
blocks/navigation/version.php
blocks/news_items/version.php
blocks/online_users/version.php
blocks/participants/version.php
blocks/private_files/version.php
blocks/quiz_results/version.php
blocks/recent_activity/version.php
blocks/rss_client/version.php
blocks/search_forums/version.php
blocks/section_links/version.php
blocks/selfcompletion/version.php
blocks/settings/version.php
blocks/site_main_menu/version.php
blocks/social_activities/version.php
blocks/tag_flickr/classes/privacy/provider.php
blocks/tag_flickr/lang/en/block_tag_flickr.php
blocks/tag_flickr/version.php
blocks/tag_youtube/version.php
blocks/tags/version.php
blog/classes/privacy/provider.php
cache/locks/file/version.php
cache/stores/apcu/version.php
cache/stores/file/version.php
cache/stores/memcache/version.php
cache/stores/memcached/version.php
cache/stores/mongodb/version.php
cache/stores/redis/version.php
cache/stores/session/version.php
cache/stores/static/version.php
calendar/type/gregorian/version.php
competency/classes/privacy/provider.php
course/classes/privacy/provider.php [new file with mode: 0644]
course/format/singleactivity/version.php
course/format/social/version.php
course/format/topics/version.php
course/format/weeks/version.php
course/tests/privacy_test.php [new file with mode: 0644]
dataformat/csv/version.php
dataformat/excel/version.php
dataformat/html/version.php
dataformat/json/version.php
dataformat/ods/version.php
enrol/category/version.php
enrol/classes/privacy/provider.php [new file with mode: 0644]
enrol/cohort/version.php
enrol/database/version.php
enrol/flatfile/version.php
enrol/guest/version.php
enrol/imsenterprise/version.php
enrol/ldap/version.php
enrol/lti/version.php
enrol/manual/version.php
enrol/meta/version.php
enrol/mnet/version.php
enrol/paypal/classes/privacy/provider.php [new file with mode: 0644]
enrol/paypal/lang/en/enrol_paypal.php
enrol/paypal/tests/privacy_provider_test.php [new file with mode: 0644]
enrol/paypal/version.php
enrol/self/version.php
enrol/tests/privacy_test.php [new file with mode: 0644]
files/converter/googledrive/version.php
files/converter/unoconv/version.php
filter/activitynames/version.php
filter/algebra/version.php
filter/censor/version.php
filter/data/version.php
filter/emailprotect/version.php
filter/emoticon/version.php
filter/glossary/version.php
filter/mathjaxloader/version.php
filter/mediaplugin/version.php
filter/multilang/version.php
filter/tex/version.php
filter/tidy/version.php
filter/urltolink/version.php
grade/export/ods/version.php
grade/export/txt/version.php
grade/export/xls/version.php
grade/export/xml/version.php
grade/grading/form/guide/version.php
grade/grading/form/rubric/version.php
grade/import/csv/version.php
grade/import/direct/version.php
grade/import/xml/version.php
grade/report/grader/version.php
grade/report/history/version.php
grade/report/outcomes/version.php
grade/report/overview/version.php
grade/report/singleview/version.php
grade/report/user/version.php
group/classes/privacy/provider.php [new file with mode: 0644]
group/tests/privacy_provider_test.php [new file with mode: 0644]
index.php
lang/en/course.php [new file with mode: 0644]
lang/en/enrol.php
lang/en/group.php
lang/en/portfolio.php
lang/en/role.php
lang/en/search.php
lang/en/user.php [new file with mode: 0644]
lib/antivirus/clamav/version.php
lib/classes/event/notification_sent.php
lib/editor/atto/plugins/accessibilitychecker/version.php
lib/editor/atto/plugins/accessibilityhelper/version.php
lib/editor/atto/plugins/align/version.php
lib/editor/atto/plugins/backcolor/version.php
lib/editor/atto/plugins/bold/version.php
lib/editor/atto/plugins/charmap/version.php
lib/editor/atto/plugins/clear/version.php
lib/editor/atto/plugins/collapse/version.php
lib/editor/atto/plugins/emoticon/version.php
lib/editor/atto/plugins/equation/version.php
lib/editor/atto/plugins/fontcolor/version.php
lib/editor/atto/plugins/html/version.php
lib/editor/atto/plugins/image/version.php
lib/editor/atto/plugins/indent/version.php
lib/editor/atto/plugins/italic/version.php
lib/editor/atto/plugins/link/version.php
lib/editor/atto/plugins/managefiles/version.php
lib/editor/atto/plugins/media/version.php
lib/editor/atto/plugins/noautolink/version.php
lib/editor/atto/plugins/orderedlist/version.php
lib/editor/atto/plugins/recordrtc/version.php
lib/editor/atto/plugins/rtl/version.php
lib/editor/atto/plugins/strike/version.php
lib/editor/atto/plugins/subscript/version.php
lib/editor/atto/plugins/superscript/version.php
lib/editor/atto/plugins/table/version.php
lib/editor/atto/plugins/title/version.php
lib/editor/atto/plugins/underline/version.php
lib/editor/atto/plugins/undo/version.php
lib/editor/atto/plugins/unorderedlist/version.php
lib/editor/atto/version.php
lib/editor/textarea/version.php
lib/editor/tinymce/plugins/ctrlhelp/version.php
lib/editor/tinymce/plugins/managefiles/version.php
lib/editor/tinymce/plugins/moodleemoticon/version.php
lib/editor/tinymce/plugins/moodleimage/version.php
lib/editor/tinymce/plugins/moodlemedia/version.php
lib/editor/tinymce/plugins/moodlenolink/version.php
lib/editor/tinymce/plugins/pdw/version.php
lib/editor/tinymce/plugins/spellchecker/version.php
lib/editor/tinymce/plugins/wrap/version.php
lib/editor/tinymce/version.php
lib/mlbackend/php/version.php
lib/mlbackend/python/version.php
lib/moodlelib.php
lib/portfolio/exporter.php
lib/portfoliolib.php
media/player/html5audio/version.php
media/player/html5video/version.php
media/player/swf/version.php
media/player/videojs/version.php
media/player/vimeo/version.php
media/player/youtube/version.php
message/output/airnotifier/version.php
message/output/email/version.php
message/output/jabber/version.php
message/output/popup/version.php
message/tests/events_test.php
mnet/service/enrol/version.php
mod/assign/feedback/comments/version.php
mod/assign/feedback/editpdf/classes/privacy/provider.php
mod/assign/feedback/editpdf/version.php
mod/assign/feedback/file/version.php
mod/assign/feedback/offline/version.php
mod/assign/submission/comments/version.php
mod/assign/submission/file/version.php
mod/assign/submission/onlinetext/version.php
mod/assign/version.php
mod/assignment/type/offline/version.php
mod/assignment/type/online/version.php
mod/assignment/type/upload/version.php
mod/assignment/type/uploadsingle/version.php
mod/assignment/version.php
mod/book/tool/exportimscp/version.php
mod/book/tool/importhtml/version.php
mod/book/tool/print/version.php
mod/book/version.php
mod/chat/version.php
mod/choice/version.php
mod/data/field/checkbox/version.php
mod/data/field/date/version.php
mod/data/field/file/version.php
mod/data/field/latlong/version.php
mod/data/field/menu/version.php
mod/data/field/multimenu/version.php
mod/data/field/number/version.php
mod/data/field/picture/version.php
mod/data/field/radiobutton/version.php
mod/data/field/text/version.php
mod/data/field/textarea/version.php
mod/data/field/url/version.php
mod/data/preset/imagegallery/version.php
mod/data/version.php
mod/feedback/version.php
mod/folder/version.php
mod/forum/classes/message/inbound/reply_handler.php
mod/forum/classes/privacy/provider.php [new file with mode: 0644]
mod/forum/classes/privacy/subcontext_info.php [new file with mode: 0644]
mod/forum/db/install.xml
mod/forum/db/upgrade.php
mod/forum/discuss.php
mod/forum/externallib.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/locallib.php
mod/forum/post.php
mod/forum/rsslib.php
mod/forum/tests/externallib_test.php
mod/forum/tests/helper.php [new file with mode: 0644]
mod/forum/tests/mail_test.php
mod/forum/tests/portfolio_caller_test.php [new file with mode: 0644]
mod/forum/tests/privacy_provider_test.php [new file with mode: 0644]
mod/forum/tests/subscriptions_test.php
mod/forum/version.php
mod/glossary/classes/privacy/provider.php [new file with mode: 0644]
mod/glossary/lang/en/glossary.php
mod/glossary/tests/privacy_provider_test.php [new file with mode: 0644]
mod/glossary/version.php
mod/imscp/version.php
mod/label/version.php
mod/lesson/version.php
mod/lti/service/gradebookservices/version.php
mod/lti/service/memberships/version.php
mod/lti/service/profile/version.php
mod/lti/service/toolproxy/version.php
mod/lti/service/toolsettings/version.php
mod/lti/version.php
mod/page/version.php
mod/quiz/accessrule/delaybetweenattempts/version.php
mod/quiz/accessrule/ipaddress/version.php
mod/quiz/accessrule/numattempts/version.php
mod/quiz/accessrule/offlineattempts/version.php
mod/quiz/accessrule/openclosedate/version.php
mod/quiz/accessrule/password/version.php
mod/quiz/accessrule/safebrowser/version.php
mod/quiz/accessrule/securewindow/version.php
mod/quiz/accessrule/timelimit/version.php
mod/quiz/report/grading/version.php
mod/quiz/report/overview/version.php
mod/quiz/report/responses/version.php
mod/quiz/report/statistics/version.php
mod/quiz/version.php
mod/resource/version.php
mod/scorm/report/basic/version.php
mod/scorm/report/graphs/version.php
mod/scorm/report/interactions/version.php
mod/scorm/report/objectives/version.php
mod/scorm/version.php
mod/survey/version.php
mod/url/version.php
mod/wiki/classes/privacy/provider.php [new file with mode: 0644]
mod/wiki/lang/en/wiki.php
mod/wiki/tests/generator/lib.php
mod/wiki/tests/privacy_test.php [new file with mode: 0644]
mod/wiki/version.php
mod/workshop/allocation/manual/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/allocation/manual/lang/en/workshopallocation_manual.php
mod/workshop/allocation/manual/tests/privacy_provider_test.php [new file with mode: 0644]
mod/workshop/allocation/manual/version.php
mod/workshop/allocation/random/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/allocation/random/lang/en/workshopallocation_random.php
mod/workshop/allocation/random/version.php
mod/workshop/allocation/scheduled/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/allocation/scheduled/lang/en/workshopallocation_scheduled.php
mod/workshop/allocation/scheduled/version.php
mod/workshop/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/classes/privacy/workshopform_legacy_polyfill.php [new file with mode: 0644]
mod/workshop/classes/privacy/workshopform_provider.php [new file with mode: 0644]
mod/workshop/db/install.xml
mod/workshop/db/upgrade.php
mod/workshop/eval/best/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/eval/best/lang/en/workshopeval_best.php
mod/workshop/eval/best/version.php
mod/workshop/form/accumulative/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/form/accumulative/lang/en/workshopform_accumulative.php
mod/workshop/form/accumulative/tests/privacy_provider_test.php [new file with mode: 0644]
mod/workshop/form/accumulative/version.php
mod/workshop/form/comments/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/form/comments/lang/en/workshopform_comments.php
mod/workshop/form/comments/tests/privacy_provider_test.php [new file with mode: 0644]
mod/workshop/form/comments/version.php
mod/workshop/form/numerrors/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/form/numerrors/lang/en/workshopform_numerrors.php
mod/workshop/form/numerrors/tests/privacy_provider_test.php [new file with mode: 0644]
mod/workshop/form/numerrors/version.php
mod/workshop/form/rubric/classes/privacy/provider.php [new file with mode: 0644]
mod/workshop/form/rubric/lang/en/workshopform_rubric.php
mod/workshop/form/rubric/tests/privacy_provider_test.php [new file with mode: 0644]
mod/workshop/form/rubric/version.php
mod/workshop/lang/en/workshop.php
mod/workshop/tests/generator/lib.php
mod/workshop/tests/privacy_provider_test.php [new file with mode: 0644]
mod/workshop/version.php
portfolio/boxnet/version.php
portfolio/classes/privacy/provider.php
portfolio/download/version.php
portfolio/flickr/version.php
portfolio/googledocs/version.php
portfolio/mahara/version.php
portfolio/picasa/version.php
portfolio/tests/privacy_provider_test.php
privacy/classes/local/request/context_aware_provider.php [new file with mode: 0644]
privacy/classes/manager.php
privacy/classes/tests/request/content_writer.php
privacy/tests/provider_test.php
privacy/tests/tests_content_writer_test.php
question/behaviour/adaptive/version.php
question/behaviour/adaptivenopenalty/version.php
question/behaviour/deferredcbm/version.php
question/behaviour/deferredfeedback/version.php
question/behaviour/immediatecbm/version.php
question/behaviour/immediatefeedback/version.php
question/behaviour/informationitem/version.php
question/behaviour/interactive/version.php
question/behaviour/interactivecountback/version.php
question/behaviour/manualgraded/version.php
question/behaviour/missing/version.php
question/format/aiken/version.php
question/format/blackboard_six/version.php
question/format/examview/version.php
question/format/gift/version.php
question/format/missingword/version.php
question/format/multianswer/version.php
question/format/webct/version.php
question/format/xhtml/version.php
question/format/xml/version.php
question/type/calculated/version.php
question/type/calculatedmulti/version.php
question/type/calculatedsimple/version.php
question/type/ddimageortext/version.php
question/type/ddmarker/version.php
question/type/ddwtos/version.php
question/type/description/version.php
question/type/essay/version.php
question/type/gapselect/version.php
question/type/match/version.php
question/type/missingtype/version.php
question/type/multianswer/version.php
question/type/multichoice/version.php
question/type/numerical/version.php
question/type/random/version.php
question/type/randomsamatch/version.php
question/type/shortanswer/version.php
question/type/truefalse/version.php
report/backups/version.php
report/competency/version.php
report/completion/version.php
report/configlog/version.php
report/courseoverview/version.php
report/eventlist/version.php
report/insights/version.php
report/log/version.php
report/loglive/version.php
report/outline/version.php
report/participation/version.php
report/performance/version.php
report/progress/version.php
report/questioninstances/version.php
report/security/version.php
report/stats/classes/privacy/provider.php
report/stats/lang/en/report_stats.php
report/stats/tests/privacy_test.php [new file with mode: 0644]
report/stats/version.php
report/usersessions/version.php
repository/areafiles/version.php
repository/boxnet/version.php
repository/coursefiles/version.php
repository/dropbox/version.php
repository/equella/version.php
repository/filesystem/version.php
repository/flickr/version.php
repository/flickr_public/version.php
repository/googledocs/version.php
repository/local/version.php
repository/merlot/version.php
repository/onedrive/version.php
repository/picasa/version.php
repository/recent/version.php
repository/s3/version.php
repository/skydrive/version.php
repository/upload/version.php
repository/url/version.php
repository/user/version.php
repository/webdav/version.php
repository/wikimedia/version.php
repository/youtube/version.php
search/classes/privacy/provider.php [new file with mode: 0644]
search/engine/simpledb/classes/privacy/provider.php [new file with mode: 0644]
search/engine/simpledb/lang/en/search_simpledb.php
search/engine/simpledb/tests/privacy_test.php [new file with mode: 0644]
search/engine/simpledb/version.php
search/engine/solr/classes/privacy/provider.php [new file with mode: 0644]
search/engine/solr/lang/en/search_solr.php
search/engine/solr/tests/privacy_test.php [new file with mode: 0644]
search/engine/solr/version.php
search/tests/fixtures/mock_search_area.php
tag/classes/tests/privacy_helper.php [new file with mode: 0644]
theme/boost/scss/moodle/bs4alphacompat.scss
theme/boost/scss/moodle/forms.scss
theme/boost/scss/moodle/undo.scss
theme/boost/templates/columns2.mustache
theme/boost/templates/core/paging_bar.mustache
theme/boost/templates/footer.mustache
theme/boost/version.php
theme/bootstrapbase/version.php
theme/clean/version.php
theme/more/version.php
user/classes/privacy/provider.php [new file with mode: 0644]
user/profile/field/checkbox/version.php
user/profile/field/datetime/version.php
user/profile/field/menu/version.php
user/profile/field/text/version.php
user/profile/field/textarea/version.php
user/tests/privacy_test.php [new file with mode: 0644]
version.php
webservice/rest/version.php
webservice/soap/version.php
webservice/xmlrpc/version.php

diff --git a/admin/roles/classes/privacy/provider.php b/admin/roles/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..ee8bcea
--- /dev/null
@@ -0,0 +1,382 @@
+<?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) : collection {
+        $rolecapabilities = [
+            'roleid' => 'privacy:metadata:role_capabilities:roleid',
+            'capability' => 'privacy:metadata:role_capabilities:capability',
+            'permission' => 'privacy:metadata:role_capabilities:permission',
+            'timemodified' => 'privacy:metadata:role_capabilities:timemodified',
+            'modifierid' => 'privacy:metadata:role_capabilities:modifierid'
+        ];
+        $roleassignments = [
+            'roleid' => 'privacy:metadata:role_assignments:roleid',
+            'userid' => 'privacy:metadata:role_assignments:userid',
+            'timemodified' => 'privacy:metadata:role_assignments:timemodified',
+            'modifierid' => 'privacy:metadata:role_assignments:modifierid',
+            'component' => 'privacy:metadata:role_assignments:component',
+            'itemid' => 'privacy:metadata:role_assignments:itemid'
+        ];
+        $collection->add_database_table('role_capabilities', $rolecapabilities,
+            'privacy:metadata:role_capabilities:tableexplanation');
+        $collection->add_database_table('role_assignments', $roleassignments,
+            'privacy:metadata:role_assignments:tableexplanation');
+
+        $collection->add_user_preference('definerole_showadvanced',
+            'privacy:metadata:preference:showadvanced');
+
+        return $collection;
+    }
+    /**
+     * Export all user preferences for the plugin.
+     *
+     * @param   int         $userid The userid of the user whose data is to be exported.
+     */
+    public static function export_user_preferences(int $userid) {
+        $showadvanced = get_user_preferences('definerole_showadvanced', null, $userid);
+        if ($showadvanced !== null) {
+            writer::export_user_preference('core_role',
+                'definerole_showadvanced',
+                transform::yesno($showadvanced),
+                get_string('privacy:metadata:preference:showadvanced', 'core_role')
+            );
+        }
+    }
+    /**
+     * Return all contexts for this userid.
+     *
+     * @param  int $userid The user ID.
+     * @return contextlist The list of context IDs.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        global $DB;
+
+        $contextlist = new contextlist();
+
+        // The role_capabilities table contains user data.
+        $contexts = [
+            CONTEXT_SYSTEM,
+            CONTEXT_USER,
+            CONTEXT_COURSECAT,
+            CONTEXT_COURSE,
+            CONTEXT_MODULE,
+            CONTEXT_BLOCK
+        ];
+        list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
+        $sql = "SELECT ctx.id
+                  FROM {context} ctx
+                  JOIN {role_capabilities} rc
+                    ON rc.contextid = ctx.id
+                   AND ((ctx.contextlevel {$insql} AND rc.modifierid = :modifierid)
+                    OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))";
+        $params = [
+            'modifierid' => $userid,
+            'contextlevel' => CONTEXT_USER,
+            'userid' => $userid
+         ];
+        $params += $inparams;
+
+        $contextlist->add_from_sql($sql, $params);
+
+        // The role_assignments table contains user data.
+        $contexts = [
+            CONTEXT_SYSTEM,
+            CONTEXT_USER,
+            CONTEXT_COURSECAT,
+            CONTEXT_COURSE,
+            CONTEXT_MODULE,
+            CONTEXT_BLOCK
+        ];
+        list($insql, $inparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
+        $params = [
+            'userid' => $userid,
+            'modifierid' => $userid
+         ];
+        $params += $inparams;
+        $sql = "SELECT ctx.id
+                  FROM {role_assignments} ra
+                  JOIN {context} ctx
+                    ON ctx.id = ra.contextid
+                   AND ctx.contextlevel {$insql}
+                 WHERE (ra.userid = :userid
+                    OR ra.modifierid = :modifierid)
+                   AND ra.component != 'tool_cohortroles'";
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param  approved_contextlist $contextlist The list of approved contexts for a user.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        global $DB;
+
+        if (empty($contextlist)) {
+             return;
+        }
+
+        $rolesnames = self::get_roles_name();
+        $userid = $contextlist->get_user()->id;
+        $ctxfields = \context_helper::get_preload_record_columns_sql('ctx');
+        list($insql, $inparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+
+        // Role Assignments export data.
+        $contexts = [
+            CONTEXT_SYSTEM,
+            CONTEXT_USER,
+            CONTEXT_COURSECAT,
+            CONTEXT_COURSE,
+            CONTEXT_MODULE,
+            CONTEXT_BLOCK
+        ];
+        list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
+        $sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, $ctxfields
+                  FROM {role_assignments} ra
+                  JOIN {context} ctx
+                    ON ctx.id = ra.contextid
+                   AND ctx.contextlevel {$inctxsql}
+                   AND (ra.userid = :userid OR ra.modifierid = :modifierid)
+                   AND ra.component != 'tool_cohortroles'
+                  JOIN {role} r
+                    ON r.id = ra.roleid
+                 WHERE ctx.id {$insql}";
+        $params = ['userid' => $userid, 'modifierid' => $userid];
+        $params += $inparams;
+        $params += $ctxparams;
+        $assignments = $DB->get_recordset_sql($sql, $params);
+        foreach ($assignments as $assignment) {
+            \context_helper::preload_from_record($assignment);
+            $alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
+                'timemodified' => transform::datetime($assignment->timemodified),
+                'userid' => transform::user($assignment->userid),
+                'modifierid' => transform::user($assignment->modifierid)
+            ];
+        }
+        $assignments->close();
+        if (!empty($alldata)) {
+            array_walk($alldata, function($roledata, $contextid) {
+                $context = \context::instance_by_id($contextid);
+                array_walk($roledata, function($data, $rolename) use ($context) {
+                    writer::with_context($context)->export_data(
+                            [get_string('privacy:metadata:role_assignments', 'core_role'), $rolename],
+                            (object)$data);
+                });
+            });
+            unset($alldata);
+        }
+
+        // Role Capabilities export data.
+        $strpermissions = self::get_permissions_name();
+        $contexts = [
+            CONTEXT_SYSTEM,
+            CONTEXT_USER,
+            CONTEXT_COURSECAT,
+            CONTEXT_COURSE,
+            CONTEXT_MODULE,
+            CONTEXT_BLOCK
+        ];
+        list($inctxsql, $ctxparams) = $DB->get_in_or_equal($contexts, SQL_PARAMS_NAMED);
+        $sql = "SELECT rc.id, rc.contextid, rc.capability, rc.permission, rc.timemodified, rc.roleid, $ctxfields
+                  FROM {context} ctx
+                  JOIN {role_capabilities} rc
+                    ON rc.contextid = ctx.id
+                   AND ((ctx.contextlevel {$inctxsql} AND rc.modifierid = :modifierid)
+                    OR (ctx.contextlevel = :contextlevel AND ctx.instanceid = :userid))
+                 WHERE ctx.id {$insql}";
+        $params = [
+            'modifierid' => $userid,
+            'contextlevel' => CONTEXT_USER,
+            'userid' => $userid
+         ];
+        $params += $inparams;
+        $params += $ctxparams;
+        $capabilities = $DB->get_recordset_sql($sql, $params);
+        foreach ($capabilities as $capability) {
+            \context_helper::preload_from_record($capability);
+            $alldata[$capability->contextid][$rolesnames[$capability->roleid]][] = (object)[
+                'timemodified' => transform::datetime($capability->timemodified),
+                'capability' => $capability->capability,
+                'permission' => $strpermissions[$capability->permission]
+            ];
+        }
+        $capabilities->close();
+        if (!empty($alldata)) {
+            array_walk($alldata, function($capdata, $contextid) {
+                $context = \context::instance_by_id($contextid);
+                array_walk($capdata, function($data, $rolename) use ($context) {
+                    writer::with_context($context)->export_data(
+                            [get_string('privacy:metadata:role_capabilities', 'core_role'), $rolename],
+                            (object)$data);
+                });
+            });
+        }
+    }
+    /**
+     * Exports the data relating to tool_cohortroles component on role assignments by
+     * Assign user roles to cohort feature.
+     *
+     * @param  int $userid The user ID.
+     */
+    public static function export_user_role_to_cohort(int $userid) {
+        global $DB;
+
+        $rolesnames = self::get_roles_name();
+        $sql = "SELECT ra.id, ra.contextid, ra.roleid, ra.userid, ra.timemodified, ra.modifierid, r.id as roleid
+                  FROM {role_assignments} ra
+                  JOIN {context} ctx
+                    ON ctx.id = ra.contextid
+                   AND ctx.contextlevel = :contextlevel
+                   AND ra.component = 'tool_cohortroles'
+                  JOIN {role} r
+                    ON r.id = ra.roleid
+                 WHERE ctx.instanceid = :instanceid
+                    OR ra.userid = :userid";
+        $params = ['userid' => $userid, 'instanceid' => $userid, 'contextlevel' => CONTEXT_USER];
+        $assignments = $DB->get_recordset_sql($sql, $params);
+        foreach ($assignments as $assignment) {
+            $alldata[$assignment->contextid][$rolesnames[$assignment->roleid]][] = (object)[
+                'timemodified' => transform::datetime($assignment->timemodified),
+                'userid' => transform::user($assignment->userid),
+                'modifierid' => transform::user($assignment->modifierid)
+            ];
+        }
+        $assignments->close();
+        if (!empty($alldata)) {
+            array_walk($alldata, function($roledata, $contextid) {
+                $context = \context::instance_by_id($contextid);
+                array_walk($roledata, function($data, $rolename) use ($context) {
+                    writer::with_context($context)->export_related_data(
+                            [get_string('privacy:metadata:role_cohortroles', 'core_role'), $rolename], 'cohortroles',
+                            (object)$data);
+                });
+            });
+        }
+    }
+    /**
+     * Delete all user data for this context.
+     *
+     * @param  \context $context The context to delete data for.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        global $DB;
+
+        // Don't remove data from role_capabilities.
+        // Because this data affects the whole Moodle, there are override capabilities.
+        // Don't belong to the modifier user.
+
+        // Remove data from role_assignments.
+        if (empty($context)) {
+            return;
+        }
+        $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(int $userid) {
+        global $DB;
+
+        // Delete entries where userid is a mentor by tool_cohortroles.
+        $DB->delete_records('role_assignments', ['userid' => $userid, 'component' => 'tool_cohortroles']);
+    }
+    /**
+     * Get all the localised roles name in a simple array.
+     *
+     * @return array Array of name of the roles by roleid.
+     */
+    protected static function get_roles_name() {
+        $roles = role_fix_names(get_all_roles(), \context_system::instance(), ROLENAME_ORIGINAL);
+        $rolesnames = array();
+        foreach ($roles as $role) {
+            $rolesnames[$role->id] = $role->localname;
+        }
+        return $rolesnames;
+    }
+    /**
+     * Get all the permissions name in a simple array.
+     *
+     * @return array Array of permissions name.
+     */
+    protected static function get_permissions_name() {
+        $strpermissions = array(
+            CAP_INHERIT => get_string('inherit', 'role'),
+            CAP_ALLOW => get_string('allow', 'role'),
+            CAP_PREVENT => get_string('prevent', 'role'),
+            CAP_PROHIBIT => get_string('prohibit', 'role')
+        );
+        return $strpermissions;
+    }
+}
\ No newline at end of file
diff --git a/admin/roles/tests/privacy_test.php b/admin/roles/tests/privacy_test.php
new file mode 100644 (file)
index 0000000..bffc919
--- /dev/null
@@ -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;
+    }
+}
\ No newline at end of file
index 162e89c..42e81f0 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_analytics'; // Full name of the plugin (used for diagnostics).
index 20d06f1..63fd29d 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;
-$plugin->requires  = 2017110800;
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;
 $plugin->component = 'tool_assignmentupgrade';
-$plugin->dependencies = array('mod_assign' => 2017110800);
+$plugin->dependencies = array('mod_assign' => 2018050800);
index 0ed3384..a30d705 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'tool_availabilityconditions';
index 8066574..7771e76 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;   // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;   // Requires this Moodle version
+$plugin->version   = 2018051400;   // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;   // Requires this Moodle version
 $plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
index d8980e4..9cfa8f7 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
index 4e7de4a..663c515 100644 (file)
@@ -25,8 +25,8 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_cohortroles'; // Full name of the plugin (used for diagnostics).
 
 $plugin->dependencies = array(
index 4dfe9c2..400e4b9 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;
-$plugin->requires  = 2017110800;
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;
 $plugin->component = 'tool_customlang'; // Full name of the plugin (used for diagnostics)
index 9d73fe1..3561d57 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2018040500;
-$plugin->requires  = 2018040500;        // Moodle 3.5dev (Build 2018031600) and upwards.
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;        // Moodle 3.5dev (Build 2018031600) and upwards.
 $plugin->component = 'tool_dataprivacy';
index 26baf54..9fa2f1e 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics).
index 8910e8d..550536d 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'tool_filetypes';
index e27c676..4049283 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'tool_generator';
index c2e4db6..a4ef47c 100644 (file)
@@ -25,8 +25,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_health'; // Full name of the plugin (used for diagnostics)
 
 $plugin->maturity  = MATURITY_ALPHA; // this version's maturity level
index f0a1df0..4a2e8cf 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_httpsreplace'; // Full name of the plugin (used for diagnostics).
index 5e80b83..cbc2912 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_innodb'; // Full name of the plugin (used for diagnostics)
index ff1f7ea..b0ba3ac 100644 (file)
@@ -24,6 +24,6 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component  = 'tool_installaddon';
-$plugin->version    = 2017111300;
-$plugin->requires   = 2017110800;
+$plugin->version    = 2018051400;
+$plugin->requires   = 2018050800;
 $plugin->maturity   = MATURITY_STABLE;
index fafa6ed..c34440f 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_langimport'; // Full name of the plugin (used for diagnostics)
index 27596c0..f3841d4 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2017110800; // Requires this Moodle version.
+$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2018050800; // Requires this Moodle version.
 $plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
index 8eb6ff7..8d5b532 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2017110800; // Requires this Moodle version.
+$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2018050800; // Requires this Moodle version.
 $plugin->component = 'logstore_legacy'; // Full name of the plugin (used for diagnostics).
index dc08ba9..b509968 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2017110800; // Requires this Moodle version.
+$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2018050800; // Requires this Moodle version.
 $plugin->component = 'logstore_standard'; // Full name of the plugin (used for diagnostics).
index 041c70e..b5a7d90 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2017110800; // Requires this Moodle version.
+$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_log'; // Full name of the plugin (used for diagnostics).
index 7477548..4436def 100644 (file)
@@ -25,6 +25,6 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).
index 1cae087..47fc25c 100644 (file)
@@ -25,8 +25,8 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_lpimportcsv'; // Full name of the plugin (used for diagnostics).
-$plugin->dependencies = array('tool_lp' => 2017110800);
+$plugin->dependencies = array('tool_lp' => 2018050800);
 
index a293e26..7ef6bd0 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_lpmigrate'; // Full name of the plugin (used for diagnostics).
 $plugin->dependencies = array(
     'tool_lp' => ANY_VERSION
index 0bf7da9..a13983f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;
-$plugin->requires  = 2017110800;
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;
 $plugin->component = 'tool_messageinbound';
index 438a6d5..2457ecf 100644 (file)
@@ -23,9 +23,9 @@
  */
 
 defined('MOODLE_INTERNAL') || die();
-$plugin->version   = 2017111301; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_mobile'; // Full name of the plugin (used for diagnostics).
 $plugin->dependencies = array(
-    'webservice_rest' => 2017110800
+    'webservice_rest' => 2018050800
 );
index c5239d8..5601b72 100644 (file)
@@ -26,6 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2017111300;     // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;     // Requires this Moodle version.
+$plugin->version   = 2018051400;     // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;     // Requires this Moodle version.
 $plugin->component = 'tool_monitor'; // Full name of the plugin (used for diagnostics).
index 09000e0..6efabad 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_multilangupgrade'; // Full name of the plugin (used for diagnostics)
 
index fe05f0e..4f78e33 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_oauth2'; // Full name of the plugin (used for diagnostics).
 
index b0741a2..dbc7baf 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_phpunit'; // Full name of the plugin (used for diagnostics)
 
index 159cb2a..e87145d 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2018032900;         // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2018032900;         // Requires this Moodle version.
+$plugin->version   = 2018051400;         // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;         // Requires this Moodle version.
 $plugin->component = 'tool_policy';      // Full name of the plugin (used for diagnostics).
index c85b558..372332b 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_profiling'; // Full name of the plugin (used for diagnostics)
index 82dc549..976bc91 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_recyclebin'; // Full name of the plugin (used for diagnostics).
index db0cf98..bb17971 100644 (file)
@@ -25,8 +25,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_replace'; // Full name of the plugin (used for diagnostics)
 
 $plugin->maturity  = MATURITY_ALPHA; // this version's maturity level
index c182791..67b7e81 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;
-$plugin->requires  = 2017110800;
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;
 $plugin->component = 'tool_spamcleaner'; // Full name of the plugin (used for diagnostics)
 
index f243e16..adb0081 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_task'; // Full name of the plugin (used for diagnostics)
 
index 6c2e44e..0a3ae84 100644 (file)
@@ -21,6 +21,6 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 defined('MOODLE_INTERNAL') || die();
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'tool_templatelibrary'; // Full name of the plugin (used for diagnostics).
index 5017a11..20e4245 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_unsuproles'; // Full name of the plugin (used for diagnostics)
 
index b23fe01..8573143 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;            // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;            // Requires this Moodle version.
+$plugin->version   = 2018051400;            // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;            // Requires this Moodle version.
 $plugin->component = 'tool_uploadcourse';   // Full name of the plugin (used for diagnostics).
index 5e83d26..671f015 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_uploaduser'; // Full name of the plugin (used for diagnostics)
 
index c2ede76..b9aa86b 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;            // The current module version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;            // Requires this Moodle version.
+$plugin->version   = 2018051400;            // The current module version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;            // Requires this Moodle version.
 $plugin->component = 'tool_usertours';      // Full name of the plugin (used for diagnostics).
index 8b54f77..486ba9e 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800; // Requires this Moodle version
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800; // Requires this Moodle version
 $plugin->component = 'tool_xmldb'; // Full name of the plugin (used for diagnostics)
 
index 5096c44..a572e5b 100644 (file)
@@ -26,8 +26,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_cas';        // Full name of the plugin (used for diagnostics)
 
-$plugin->dependencies = array('auth_ldap' => 2017110800);
+$plugin->dependencies = array('auth_ldap' => 2018050800);
index 5324ed8..a1acfba 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_db';         // Full name of the plugin (used for diagnostics)
index 2d3c4cd..d88f88d 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_email';      // Full name of the plugin (used for diagnostics)
index 5c9d370..4a98703 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_ldap';       // Full name of the plugin (used for diagnostics)
index 7e7cd26..bbbe28a 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2017110800; // Requires this Moodle version.
+$plugin->version = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2018050800; // Requires this Moodle version.
 $plugin->component = 'auth_lti'; // Full name of the plugin (used for diagnostics).
index fc5be6a..d61bd51 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_manual';     // Full name of the plugin (used for diagnostics)
index 3c79a2d..dbe0f5d 100644 (file)
  * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
+
 namespace auth_mnet\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 Subsystem for auth_mnet implementing null_provider.
+ * Privacy provider for the mnet authentication
  *
  * @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 {
+class provider implements
+        \core_privacy\local\metadata\provider,
+        \core_privacy\local\request\plugin\provider {
     /**
-     * Get the language string identifier with the component's language
-     * file to explain why this plugin stores no data.
+     * Returns meta data about this system.
      *
-     * @return  string
+     * @param   collection $collection The initialised item collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
      */
-    public static function get_reason() : string {
-        return 'privacy:metadata';
+    public static function get_metadata(collection $collection) : collection {
+
+        $sessionfields = [
+                'userid' => 'privacy:metadata:mnet_session:userid',
+                'username' => 'privacy:metadata:mnet_session:username',
+                'token' => 'privacy:metadata:mnet_session:token',
+                'mnethostid' => 'privacy:metadata:mnet_session:mnethostid',
+                'useragent' => 'privacy:metadata:mnet_session:useragent',
+                'expires' => 'privacy:metadata:mnet_session:expires'
+        ];
+
+        $collection->add_database_table('mnet_session', $sessionfields, 'privacy:metadata:mnet_session');
+
+        $logfields = [
+                'hostid' => 'privacy:metadata:mnet_log:hostid',
+                'remoteid' => 'privacy:metadata:mnet_log:remoteid',
+                'time' => 'privacy:metadata:mnet_log:time',
+                'userid' => 'privacy:metadata:mnet_log:userid',
+                'ip' => 'privacy:metadata:mnet_log:ip',
+                'course' => 'privacy:metadata:mnet_log:course',
+                'coursename' => 'privacy:metadata:mnet_log:coursename',
+                'module' => 'privacy:metadata:mnet_log:module',
+                'cmid' => 'privacy:metadata:mnet_log:cmid',
+                'action' => 'privacy:metadata:mnet_log:action',
+                'url' => 'privacy:metadata:mnet_log:url',
+                'info' => 'privacy:metadata:mnet_log:info'
+        ];
+
+        $collection->add_database_table('mnet_log', $logfields, 'privacy:metadata:mnet_log');
+
+        $externalfields = [
+                'address' => 'privacy:metadata:mnet_external:address',
+                'aim' => 'privacy:metadata:mnet_external:aim',
+                'alternatename' => 'privacy:metadata:mnet_external:alternatename',
+                'autosubscribe' => 'privacy:metadata:mnet_external:autosubscribe',
+                'calendartype' => 'privacy:metadata:mnet_external:calendartype',
+                'city' => 'privacy:metadata:mnet_external:city',
+                'country' => 'privacy:metadata:mnet_external:country',
+                'currentlogin' => 'privacy:metadata:mnet_external:currentlogin',
+                'department' => 'privacy:metadata:mnet_external:department',
+                'description' => 'privacy:metadata:mnet_external:description',
+                'email' => 'privacy:metadata:mnet_external:email',
+                'emailstop' => 'privacy:metadata:mnet_external:emailstop',
+                'firstaccess' => 'privacy:metadata:mnet_external:firstaccess',
+                'firstname' => 'privacy:metadata:mnet_external:firstname',
+                'firstnamephonetic' => 'privacy:metadata:mnet_external:firstnamephonetic',
+                'icq' => 'privacy:metadata:mnet_external:icq',
+                'id' => 'privacy:metadata:mnet_external:id',
+                'idnumber' => 'privacy:metadata:mnet_external:idnumber',
+                'imagealt' => 'privacy:metadata:mnet_external:imagealt',
+                'institution' => 'privacy:metadata:mnet_external:institution',
+                'lang' => 'privacy:metadata:mnet_external:lang',
+                'lastaccess' => 'privacy:metadata:mnet_external:lastaccess',
+                'lastlogin' => 'privacy:metadata:mnet_external:lastlogin',
+                'lastname' => 'privacy:metadata:mnet_external:lastname',
+                'lastnamephonetic' => 'privacy:metadata:mnet_external:lastnamephonetic',
+                'maildigest' => 'privacy:metadata:mnet_external:maildigest',
+                'maildisplay' => 'privacy:metadata:mnet_external:maildisplay',
+                'middlename' => 'privacy:metadata:mnet_external:middlename',
+                'msn' => 'privacy:metadata:mnet_external:msn',
+                'phone1' => 'privacy:metadata:mnet_external:phone1',
+                'pnone2' => 'privacy:metadata:mnet_external:phone2',
+                'picture' => 'privacy:metadata:mnet_external:picture',
+                'policyagreed' => 'privacy:metadata:mnet_external:policyagreed',
+                'skype' => 'privacy:metadata:mnet_external:skype',
+                'suspended' => 'privacy:metadata:mnet_external:suspended',
+                'timezone' => 'privacy:metadata:mnet_external:timezone',
+                'trackforums' => 'privacy:metadata:mnet_external:trackforums',
+                'trustbitmask' => 'privacy:metadata:mnet_external:trustbitmask',
+                'url' => 'privacy:metadata:mnet_external:url',
+                'username' => 'privacy:metadata:mnet_external:username',
+                'yahoo' => 'privacy:metadata:mnet_external:yahoo',
+        ];
+
+        $collection->add_external_location_link('moodle', $externalfields, 'privacy:metadata:external:moodle');
+
+        $collection->add_external_location_link('mahara', $externalfields, 'privacy:metadata:external:mahara');
+
+        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 list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        $sql = "SELECT ctx.id
+                  FROM {mnet_log} ml
+                  JOIN {context} ctx ON ctx.instanceid = ml.userid AND ctx.contextlevel = :contextlevel
+                 WHERE ml.userid = :userid";
+        $params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER];
+
+        $contextlist = new contextlist();
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+
+    /**
+     * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.
+     *
+     * @param   approved_contextlist $contextlist The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        global $DB;
+
+        $context = \context_user::instance($contextlist->get_user()->id);
+
+        $sql = "SELECT ml.id, mh.wwwroot, mh.name, ml.remoteid, ml.time, ml.userid, ml.ip, ml.course,
+                       ml.coursename, ml.module, ml.cmid, ml.action, ml.url, ml.info
+                  FROM {mnet_log} ml
+                  JOIN {mnet_host} mh ON mh.id = ml.hostid
+                 WHERE ml.userid = :userid
+              ORDER BY mh.name, ml.coursename";
+        $params = ['userid' => $contextlist->get_user()->id];
+
+        $data = [];
+        $lastcourseid = null;
+
+        $logentries = $DB->get_recordset_sql($sql, $params);
+        foreach ($logentries as $logentry) {
+            $item = (object) [
+                    'time' => transform::datetime($logentry->time),
+                    'remoteid' => $logentry->remoteid,
+                    'ip' => $logentry->ip,
+                    'course' => $logentry->course,
+                    'coursename' => format_string($logentry->coursename),
+                    'module' => $logentry->module,
+                    'cmid' => $logentry->cmid,
+                    'action' => $logentry->action,
+                    'url' => $logentry->url,
+                    'info' => format_string($logentry->info)
+            ];
+
+            $item->externalhost =
+                    ($logentry->name == '') ? preg_replace('#^https?://#', '', $logentry->wwwroot) :
+                            preg_replace('#^https?://#', '', $logentry->name);
+
+            if ($lastcourseid && $lastcourseid != $logentry->course) {
+                $path = [get_string('pluginname', 'auth_mnet'), $data[0]->externalhost, $data[0]->coursename];
+                writer::with_context($context)->export_data($path, (object) $data);
+                $data = [];
+            }
+
+            $data[] = $item;
+            $lastcourseid = $logentry->course;
+        }
+        $logentries->close();
+
+        $path = [get_string('pluginname', 'auth_mnet'), $item->externalhost, $item->coursename];
+        writer::with_context($context)->export_data($path, (object) $data);
+    }
+
+    /**
+     * Delete all personal data for all users in the specified context.
+     *
+     * @param context $context Context to delete data from.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        global $DB;
+
+        if ($context->contextlevel != CONTEXT_USER) {
+            return;
+        }
+
+        $DB->delete_records('mnet_log', ['userid' => $context->instanceid]);
+    }
+
+    /**
+     * 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 (empty($contextlist->count())) {
+            return;
+        }
+
+        foreach ($contextlist->get_contexts() as $context) {
+            if ($context->contextlevel != CONTEXT_USER) {
+                return;
+            }
+
+            // Because we only use user contexts the instance ID is the user ID.
+            $DB->delete_records('mnet_log', ['userid' => $context->instanceid]);
+        }
     }
 }
\ No newline at end of file
index 6fa6ff1..412d35b 100644 (file)
@@ -35,4 +35,67 @@ $string['sso_mnet_login_refused'] = 'Username {$a->user} is not permitted to log
 $string['sso_sp_description'] = 'Publish  this service to allow authenticated users from {$a} to access your site without having to re-login. <ul><li><em>Dependency</em>: You must also <strong>subscribe</strong> to the SSO (Identity Provider) service on {$a}.</li></ul><br />Subscribe to this service to allow your users to roam to the {$a} site without having to re-login there. <ul><li><em>Dependency</em>: You must also <strong>publish</strong> the SSO (Identity Provider) service to {$a}.</li></ul><br />';
 $string['sso_sp_name'] = 'SSO (Service Provider)';
 $string['pluginname'] = 'MNet authentication';
-$string['privacy:metadata'] = 'The MNet authentication plugin does not store any personal data.';
+$string['privacy:metadata:external:mahara'] = 'This plugin can send data externally to a linked Mahara application.';
+$string['privacy:metadata:external:moodle'] = 'This plugin can send data externally to a linked Moodle application.';
+$string['privacy:metadata:mnet_external:address'] = 'The address of the user.';
+$string['privacy:metadata:mnet_external:aim'] = 'The AIM identifier of the user.';
+$string['privacy:metadata:mnet_external:alternatename'] = 'An alternative name for the user.';
+$string['privacy:metadata:mnet_external:autosubscribe'] = 'A preference as to if the user should be auto-subscribed to forums the user posts in.';
+$string['privacy:metadata:mnet_external:calendartype'] = 'A user preference for the type of calendar to use.';
+$string['privacy:metadata:mnet_external:city'] = 'The city of the user.';
+$string['privacy:metadata:mnet_external:country'] = 'The country that the user is in.';
+$string['privacy:metadata:mnet_external:currentlogin'] = 'The current login for this user.';
+$string['privacy:metadata:mnet_external:department'] = 'The department that this user can be found in.';
+$string['privacy:metadata:mnet_external:description'] = 'General details about this user.';
+$string['privacy:metadata:mnet_external:email'] = 'An email address for contact.';
+$string['privacy:metadata:mnet_external:emailstop'] = 'A preference to stop email being sent to the user.';
+$string['privacy:metadata:mnet_external:firstaccess'] = 'The time that this user first accessed the site.';
+$string['privacy:metadata:mnet_external:firstname'] = 'The first name of the user.';
+$string['privacy:metadata:mnet_external:firstnamephonetic'] = 'The phonetic details about the user\'s first name.';
+$string['privacy:metadata:mnet_external:icq'] = 'The ICQ number of the user.';
+$string['privacy:metadata:mnet_external:id'] = 'The identifier for the user.';
+$string['privacy:metadata:mnet_external:idnumber'] = 'An identification number given by the institution.';
+$string['privacy:metadata:mnet_external:imagealt'] = 'Alternative text for the user\'s image.';
+$string['privacy:metadata:mnet_external:institution'] = 'The institution that this user is a member of.';
+$string['privacy:metadata:mnet_external:lang'] = 'A user preference for the language shown.';
+$string['privacy:metadata:mnet_external:lastaccess'] = 'The time that the user last accessed the site.';
+$string['privacy:metadata:mnet_external:lastlogin'] = 'The last login of this user.';
+$string['privacy:metadata:mnet_external:lastname'] = 'The surname of the user.';
+$string['privacy:metadata:mnet_external:lastnamephonetic'] = 'The phonetic details about the user\'s surname.';
+$string['privacy:metadata:mnet_external:maildigest'] = 'A setting for the mail digest for this user.';
+$string['privacy:metadata:mnet_external:maildisplay'] = 'A preference for the user about displaying their email address to other users.';
+$string['privacy:metadata:mnet_external:middlename'] = 'The middle name of the user.';
+$string['privacy:metadata:mnet_external:msn'] = 'The MSN identifier of the user.';
+$string['privacy:metadata:mnet_external:phone1'] = 'A phone number for the user.';
+$string['privacy:metadata:mnet_external:phone2'] = 'An additional phone number for the user.';
+$string['privacy:metadata:mnet_external:picture'] = 'The picture details associated with this user.';
+$string['privacy:metadata:mnet_external:policyagreed'] = 'A flag to determine if the user has agreed to the site policy.';
+$string['privacy:metadata:mnet_external:skype'] = 'The skype identifier of the user.';
+$string['privacy:metadata:mnet_external:suspended'] = 'A flag to show if the user has been suspended on this system.';
+$string['privacy:metadata:mnet_external:timezone'] = 'The timezone that the user resides in.';
+$string['privacy:metadata:mnet_external:trackforums'] = 'A preference for forums and tracking them.';
+$string['privacy:metadata:mnet_external:trustbitmask'] = 'The trust bit mask';
+$string['privacy:metadata:mnet_external:url'] = 'A URL related to this user.';
+$string['privacy:metadata:mnet_external:username'] = 'The username for this user.';
+$string['privacy:metadata:mnet_external:yahoo'] = 'The yahoo identifier of the user.';
+$string['privacy:metadata:mnet_log'] = 'Details of remote actions carried out by a local user logged in a remote system.';
+$string['privacy:metadata:mnet_log:action'] = 'Action carried out by the user.';
+$string['privacy:metadata:mnet_log:cmid'] = 'ID of the course module.';
+$string['privacy:metadata:mnet_log:course'] = 'Remote system course ID where the action occurred.';
+$string['privacy:metadata:mnet_log:coursename'] = 'Remote system course full name where the action occurred.';
+$string['privacy:metadata:mnet_log:hostid'] = 'Remote system MNet ID.';
+$string['privacy:metadata:mnet_log:info'] = 'Additional information about the action.';
+$string['privacy:metadata:mnet_log:ip'] = 'The IP address used at the time of the action occurred.';
+$string['privacy:metadata:mnet_log:module'] = 'Remote system module where the event the action occurred.';
+$string['privacy:metadata:mnet_log:remoteid'] = 'Remote ID of the user who carried out the action in the remote system.';
+$string['privacy:metadata:mnet_log:time'] = 'Time when the action occurred.';
+$string['privacy:metadata:mnet_log:url'] = 'Remote system URL where the action occurred.';
+$string['privacy:metadata:mnet_log:userid'] = 'Local ID of the user who carried out the action in the remote system.';
+$string['privacy:metadata:mnet_session'] = 'The details of each MNet user session in a remote system is stored temporarily.';
+$string['privacy:metadata:mnet_session:expires'] = 'Time when the session expires.';
+$string['privacy:metadata:mnet_session:mnethostid'] = 'Remote system MNet ID.';
+$string['privacy:metadata:mnet_session:token'] = 'Unique session identifier.';
+$string['privacy:metadata:mnet_session:useragent'] = 'String denoting the user agent being which is accessing the page.';
+$string['privacy:metadata:mnet_session:userid'] = 'ID of the user jumping to remote system.';
+$string['privacy:metadata:mnet_session:username'] = 'Username of the user jumping to remote system.';
+$string['unknownhost'] = 'Unknown host';
\ No newline at end of file
diff --git a/auth/mnet/tests/privacy_provider_test.php b/auth/mnet/tests/privacy_provider_test.php
new file mode 100644 (file)
index 0000000..2c7292b
--- /dev/null
@@ -0,0 +1,214 @@
+<?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 the authentication mnet
+ *
+ * @package    auth_mnet
+ * @category   test
+ * @copyright  2018 Victor Deniz <victor@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+use \auth_mnet\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;
+
+/**
+ * Privacy test for the authentication mnet
+ *
+ * @package    auth_mnet
+ * @category   test
+ * @copyright  2018 Victor Deniz <victor@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class auth_mnet_privacy_testcase extends provider_testcase {
+    /**
+     * Set up method.
+     */
+    public function setUp() {
+        $this->resetAfterTest();
+        $this->setAdminUser();
+    }
+
+    /**
+     * Check that a user context is returned if there is any user data for this user.
+     */
+    public function test_get_contexts_for_userid() {
+        global $DB;
+
+        $user = $this->getDataGenerator()->create_user(['auth' => 'mnet']);
+        $this->assertEmpty(provider::get_contexts_for_userid($user->id));
+
+        // Insert mnet_log record.
+        $logrecord = new stdClass();
+        $logrecord->hostid = '';
+        $logrecord->remoteid = 65;
+        $logrecord->time = time();
+        $logrecord->userid = $user->id;
+
+        $DB->insert_record('mnet_log', $logrecord);
+
+        $contextlist = provider::get_contexts_for_userid($user->id);
+
+        // Check that we only get back one context.
+        $this->assertCount(1, $contextlist);
+
+        // Check that a context is returned is the expected.
+        $usercontext = \context_user::instance($user->id);
+        $this->assertEquals($usercontext->id, $contextlist->get_contextids()[0]);
+    }
+
+    /**
+     * Test that user data is exported correctly.
+     */
+    public function test_export_user_data() {
+        global $DB;
+
+        $user = $this->getDataGenerator()->create_user(['auth' => 'mnet']);
+
+        // Insert mnet_host record.
+        $hostrecord = new stdClass();
+        $hostrecord->wwwroot = 'https://external.moodle.com';
+        $hostrecord->name = 'External Moodle';
+        $hostrecord->public_key = '-----BEGIN CERTIFICATE-----';
+
+        $hostid = $DB->insert_record('mnet_host', $hostrecord);
+
+        // Insert mnet_log record.
+        $logrecord = new stdClass();
+        $logrecord->hostid = $hostid;
+        $logrecord->remoteid = 65;
+        $logrecord->time = time();
+        $logrecord->userid = $user->id;
+        $logrecord->course = 3;
+        $logrecord->coursename = 'test course';
+
+        $DB->insert_record('mnet_log', $logrecord);
+
+        $usercontext = \context_user::instance($user->id);
+
+        $writer = writer::with_context($usercontext);
+        $this->assertFalse($writer->has_any_data());
+        $approvedlist = new approved_contextlist($user, 'auth_mnet', [$usercontext->id]);
+        provider::export_user_data($approvedlist);
+
+        $data = $writer->get_data([get_string('pluginname', 'auth_mnet'), $hostrecord->name, $logrecord->coursename]);
+
+        $this->assertEquals($logrecord->remoteid, reset($data)->remoteid);
+        $this->assertEquals(transform::datetime($logrecord->time),  reset($data)->time);
+    }
+
+    /**
+     * Test deleting all user data for a specific context.
+     */
+    public function test_delete_data_for_all_users_in_context() {
+        global $DB;
+
+        $user1 = $this->getDataGenerator()->create_user(['auth' => 'mnet']);
+
+        // Insert mnet_log record.
+        $logrecord1 = new stdClass();
+        $logrecord1->hostid = '';
+        $logrecord1->remoteid = 65;
+        $logrecord1->time = time();
+        $logrecord1->userid = $user1->id;
+
+        $DB->insert_record('mnet_log', $logrecord1);
+
+        $user1context = \context_user::instance($user1->id);
+
+        $user2 = $this->getDataGenerator()->create_user(['auth' => 'mnet']);
+
+        // Insert mnet_log record.
+        $logrecord2 = new stdClass();
+        $logrecord2->hostid = '';
+        $logrecord2->remoteid = 65;
+        $logrecord2->time = time();
+        $logrecord2->userid = $user2->id;
+
+        $DB->insert_record('mnet_log', $logrecord2);
+
+        // Get all mnet log records.
+        $mnetlogrecords = $DB->get_records('mnet_log', array());
+        // There should be two.
+        $this->assertCount(2, $mnetlogrecords);
+
+        // Delete everything for the first user context.
+        provider::delete_data_for_all_users_in_context($user1context);
+
+        // Get all user1 mnet log records.
+        $mnetlogrecords = $DB->get_records('mnet_log', ['userid' => $user1->id]);
+        $this->assertCount(0, $mnetlogrecords);
+
+        // Get all mnet log records.
+        $mnetlogrecords = $DB->get_records('mnet_log', array());
+        // There should be one (user2).
+        $this->assertCount(1, $mnetlogrecords);
+    }
+
+    /**
+     * This should work identical to the above test.
+     */
+    public function test_delete_data_for_user() {
+        global $DB;
+
+        $user1 = $this->getDataGenerator()->create_user(['auth' => 'mnet']);
+
+        // Insert mnet_log record.
+        $logrecord1 = new stdClass();
+        $logrecord1->hostid = '';
+        $logrecord1->remoteid = 65;
+        $logrecord1->time = time();
+        $logrecord1->userid = $user1->id;
+
+        $DB->insert_record('mnet_log', $logrecord1);
+
+        $user1context = \context_user::instance($user1->id);
+
+        $user2 = $this->getDataGenerator()->create_user(['auth' => 'mnet']);
+
+        // Insert mnet_log record.
+        $logrecord2 = new stdClass();
+        $logrecord2->hostid = '';
+        $logrecord2->remoteid = 65;
+        $logrecord2->time = time();
+        $logrecord2->userid = $user2->id;
+
+        $DB->insert_record('mnet_log', $logrecord2);
+
+        // Get all mnet log records.
+        $mnetlogrecords = $DB->get_records('mnet_log', array());
+        // There should be two.
+        $this->assertCount(2, $mnetlogrecords);
+
+        // Delete everything for the first user.
+        $approvedlist = new approved_contextlist($user1, 'auth_mnet', [$user1context->id]);
+        provider::delete_data_for_user($approvedlist);
+
+        // Get all user1 mnet log records.
+        $mnetlogrecords = $DB->get_records('mnet_log', ['userid' => $user1->id]);
+        $this->assertCount(0, $mnetlogrecords);
+
+        // Get all mnet log records.
+        $mnetlogrecords = $DB->get_records('mnet_log', array());
+        // There should be one (user2).
+        $this->assertCount(1, $mnetlogrecords);
+    }
+}
index cd77e96..a827888 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_mnet';       // Full name of the plugin (used for diagnostics)
index 874d1ac..fa7542b 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_nologin';    // Full name of the plugin (used for diagnostics)
index 5827c59..e3ef197 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_none';       // Full name of the plugin (used for diagnostics)
index 9b5972b..d792c98 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;        // Requires this Moodle version.
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;        // Requires this Moodle version.
 $plugin->component = 'auth_oauth2';       // Full name of the plugin (used for diagnostics).
index d2eecb4..932a622 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_shibboleth'; // Full name of the plugin (used for diagnostics)
index 344fe4f..a0aa331 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'auth_webservice'; // Full name of the plugin (used for diagnostics)
index ef4a3c5..353d800 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'availability_completion';
index d6a148b..219eecf 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'availability_date';
index a926230..1f1d635 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'availability_grade';
index 90c9b3a..4a0ea62 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'availability_group';
index 08408e0..01f8940 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'availability_grouping';
index ae27d79..6d7de73 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->component = 'availability_profile';
index bfdb2fc..1a7586a 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js differ
index 7b569c3..3f3c424 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js differ
index bfdb2fc..1a7586a 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js differ
index a2cc382..8c93223 100644 (file)
@@ -356,7 +356,7 @@ M.core_availability.List = function(json, root, parentRoot) {
     // Create DIV structure (without kids).
     this.node = Y.Node.create('<div class="availability-list"><h3 class="accesshide"></h3>' +
             '<div class="availability-inner">' +
-            '<div class="availability-header"><span class="p-l-1">' +
+            '<div class="availability-header m-b-1"><span>' +
             M.util.get_string('listheader_sign_before', 'availability') + '</span>' +
             ' <label><span class="accesshide">' + M.util.get_string('label_sign', 'availability') +
             ' </span><select class="availability-neg custom-select m-x-1"' +
@@ -376,7 +376,7 @@ M.core_availability.List = function(json, root, parentRoot) {
             '<div class="clearfix m-t-1"></div>' +
             '<div class="availability-button"></div></div><div class="clearfix"></div></div>');
     if (!root) {
-        this.node.addClass('availability-childlist');
+        this.node.addClass('availability-childlist d-sm-flex align-items-center');
     }
     this.inner = this.node.one('> .availability-inner');
 
@@ -687,24 +687,24 @@ M.core_availability.List.prototype.clickAdd = function() {
         // Add entry for plugin.
         li = Y.Node.create('<li class="clearfix row"></li>');
         id = 'availability_addrestriction_' + type;
-        button = Y.Node.create('<button type="button" class="btn btn-default col-xs-6"' +
-                'id="' + id + '">' + M.util.get_string('title', 'availability_' + type) + '</button>');
+        button = Y.Node.create('<div class="col-6"><button type="button" class="btn btn-default w-100"' +
+                'id="' + id + '">' + M.util.get_string('title', 'availability_' + type) + '</button></div>');
         button.on('click', this.getAddHandler(type, dialogRef), this);
         li.appendChild(button);
-        label = Y.Node.create('<label for="' + id + '" class="col-xs-6">' +
-                M.util.get_string('description', 'availability_' + type) + '</label>');
+        label = Y.Node.create('<div class="col-6"><label for="' + id + '">' +
+                M.util.get_string('description', 'availability_' + type) + '</label></div>');
         li.appendChild(label);
         ul.appendChild(li);
     }
     // Extra entry for lists.
     li = Y.Node.create('<li class="clearfix row"></li>');
     id = 'availability_addrestriction_list_';
-    button = Y.Node.create('<button type="button" class="btn btn-default col-xs-6"' +
-            'id="' + id + '">' + M.util.get_string('condition_group', 'availability') + '</button>');
+    button = Y.Node.create('<div class="col-6"><button type="button" class="btn btn-default w-100"' +
+            'id="' + id + '">' + M.util.get_string('condition_group', 'availability') + '</button></div>');
     button.on('click', this.getAddHandler(null, dialogRef), this);
     li.appendChild(button);
-    label = Y.Node.create('<label for="' + id + '" class="col-xs-6">' +
-            M.util.get_string('condition_group_info', 'availability') + '</label>');
+    label = Y.Node.create('<div class="col-6"><label for="' + id + '">' +
+            M.util.get_string('condition_group_info', 'availability') + '</label></div>');
     li.appendChild(label);
     ul.appendChild(li);
 
@@ -899,7 +899,7 @@ M.core_availability.Item = function(json, root) {
         this.pluginNode.addClass('availability_' + json.type);
     }
 
-    this.node = Y.Node.create('<div class="availability-item d-inline-block"><h3 class="accesshide"></h3></div>');
+    this.node = Y.Node.create('<div class="availability-item d-sm-flex align-items-center"><h3 class="accesshide"></h3></div>');
 
     // Add eye icon if required. This icon is added for root items, but may be
     // hidden depending on the selected list operator.
@@ -922,7 +922,7 @@ M.core_availability.Item = function(json, root) {
 
     // Add the invalid marker (empty).
     this.node.appendChild(document.createTextNode(' '));
-    this.node.appendChild(Y.Node.create('<span class="m-t-1 label label-warning"/>'));
+    this.node.appendChild(Y.Node.create('<span class="label label-warning"/>'));
 };
 
 /**
index e79c2d7..66e5ce8 100644 (file)
@@ -136,7 +136,7 @@ abstract class backup implements checksumable {
      * point is backup when some behavior/approach channged, in order to allow
      * conditional coding based on it.
      */
-    const VERSION = 2017111300;
+    const VERSION = 2018051400;
     /**
      * Usually same than major release zero version, mainly for informative/historic purposes.
      */
index 90b9013..2edb45f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_activity_modules'; // Full name of the plugin (used for diagnostics)
index 72ca345..6eb9031 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;               // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;               // Requires this Moodle version.
+$plugin->version   = 2018051400;               // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;               // Requires this Moodle version.
 $plugin->component = 'block_activity_results'; // Full name of the plugin (used for diagnostics).
\ No newline at end of file
index 48bb616..ee047c1 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_admin_bookmarks'; // Full name of the plugin (used for diagnostics)
index 1d4b45e..ff4cda3 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;        // Requires this Moodle version.
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;        // Requires this Moodle version.
 $plugin->component = 'block_badges';
index 3e17b83..0d96478 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_blog_menu'; // Full name of the plugin (used for diagnostics)
index 09e5fde..60a82e8 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_blog_recent'; // Full name of the plugin (used for diagnostics)
index 4aa532b..af3a7c5 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_blog_tags'; // Full name of the plugin (used for diagnostics)
index 8dc47fc..b91baa4 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_calendar_month'; // Full name of the plugin (used for diagnostics)
index 65d7ddc..bbd4e43 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_calendar_upcoming'; // Full name of the plugin (used for diagnostics)
index 51d1aec..9982f0e 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_comments'; // Full name of the plugin (used for diagnostics)
index 3989975..9bc9957 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_community'; // Full name of the plugin (used for diagnostics)
index 7861df5..1009943 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version      = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires     = 2017110800; // Requires this Moodle version.
+$plugin->version      = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires     = 2018050800; // Requires this Moodle version.
 $plugin->component    = 'block_completionstatus';
-$plugin->dependencies = array('report_completion' => 2017110800);
+$plugin->dependencies = array('report_completion' => 2018050800);
index 761d4da..35e5580 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_course_list'; // Full name of the plugin (used for diagnostics)
index 7aeba8a..62f27c5 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_course_summary'; // Full name of the plugin (used for diagnostics)
index d9d7879..5043285 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_feedback';  // Full name of the plugin (used for diagnostics)
 
-$plugin->dependencies = array('mod_feedback' => 2017110800);
+$plugin->dependencies = array('mod_feedback' => 2018050800);
index b0c311f..332dce1 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version = 2017111300;
-$plugin->requires  = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires  = 2018050800;
 $plugin->component = 'block_globalsearch';
index 4173a86..2a36e21 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_glossary_random'; // Full name of the plugin (used for diagnostics)
 
-$plugin->dependencies = array('mod_glossary' => 2017110800);
+$plugin->dependencies = array('mod_glossary' => 2018050800);
index fb39b26..07c49bd 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_html';      // Full name of the plugin (used for diagnostics)
index bc69d00..b4caa4f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_login';     // Full name of the plugin (used for diagnostics)
index 781474d..8d99fe3 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;
-$plugin->requires  = 2017110800;
+$plugin->version   = 2018051400;
+$plugin->requires  = 2018050800;
 $plugin->component = 'block_lp';
 $plugin->dependencies = array(
     'tool_lp' => ANY_VERSION
index db5946a..6c47867 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_mentees';   // Full name of the plugin (used for diagnostics)
index 01ea880..87c8b62 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_mnet_hosts'; // Full name of the plugin (used for diagnostics)
index c64c4c4..26ccc6d 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;         // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;         // Requires this Moodle version.
+$plugin->version   = 2018051400;         // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;         // Requires this Moodle version.
 $plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics).
index 668f00e..09d06a2 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_myprofile'; // Full name of the plugin (used for diagnostics)
index 225840b..2b08391 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_navigation'; // Full name of the plugin (used for diagnostics)
index 6ed0dd2..6802862 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;         // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;         // Requires this Moodle version
+$plugin->version   = 2018051400;         // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;         // Requires this Moodle version
 $plugin->component = 'block_news_items'; // Full name of the plugin (used for diagnostics)
-$plugin->dependencies = array('mod_forum' => 2017110800);
+$plugin->dependencies = array('mod_forum' => 2018050800);
index ddf6752..6bbce9f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_online_users'; // Full name of the plugin (used for diagnostics)
index 577f37f..d05b247 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_participants'; // Full name of the plugin (used for diagnostics)
index dc47b55..3376580 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_private_files'; // Full name of the plugin (used for diagnostics)
index 0516383..b3ae74a 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_quiz_results'; // Full name of the plugin (used for diagnostics)
 
-$plugin->dependencies = array('mod_quiz' => 2017110800);
+$plugin->dependencies = array('mod_quiz' => 2018050800);
index 0d7dd7c..1943157 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_recent_activity'; // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 24*3600;           // Cron interval 1 day.
\ No newline at end of file
index b0b2254..c0e9e59 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_rss_client'; // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 300;               // Set min time between cron executions to 300 secs (5 mins)
index ea4526c..e62c1d8 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_search_forums'; // Full name of the plugin (used for diagnostics)
 
-$plugin->dependencies = array('mod_forum' => 2017110800);
+$plugin->dependencies = array('mod_forum' => 2018050800);
index c99d13b..8f9aa4f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_section_links'; // Full name of the plugin (used for diagnostics)
index 8623775..07db48d 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_selfcompletion'; // Full name of the plugin (used for diagnostics)
index f4cc04b..9540efc 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_settings';  // Full name of the plugin (used for diagnostics)
index 771b68e..48f164c 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_site_main_menu'; // Full name of the plugin (used for diagnostics)
index e48ede7..491fc5f 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_social_activities'; // Full name of the plugin (used for diagnostics)
index 08ac391..fb3673d 100644 (file)
 
 namespace block_tag_flickr\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;
+
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * Privacy Subsystem for block_tag_flickr implementing null_provider.
+ * Privacy Subsystem for block_tag_flickr implementing metadata and plugin 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 {
+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) : collection {
+        $collection->add_external_location_link(
+            'flickr.com',
+            [
+                'tags' => 'privacy:metadata:block_tag_flickr:tags'
+            ],
+            'privacy:metadata:block_tag_flickr'
+        );
+
+        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(int $userid) : contextlist {
+        return new contextlist();
+    }
 
     /**
-     * Get the language string identifier with the component's language
-     * file to explain why this plugin stores no data.
+     * Export all user data for the specified user, in the specified contexts.
      *
-     * @return  string
+     * @param   approved_contextlist $contextlist The approved contexts to export information for.
      */
-    public static function get_reason() : string {
-        return 'privacy:metadata';
+    public static function export_user_data(approved_contextlist $contextlist) {
     }
+
+    /**
+     * 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) {
+    }
+
+    /**
+     * 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) {
+    }
+
 }
index 660cd4a..637d015 100644 (file)
@@ -37,4 +37,5 @@ $string['pluginname'] = 'Flickr';
 $string['relevance'] = 'Relevance';
 $string['sortby'] = 'Sort by';
 $string['tag_flickr:addinstance'] = 'Add a new flickr block';
-$string['privacy:metadata'] = 'The Flickr block only shows data stored in other locations.';
+$string['privacy:metadata:block_tag_flickr'] = 'The Flickr block plugin does not store any personal data, but does transmit user data from Moodle to the remote system.';
+$string['privacy:metadata:block_tag_flickr:tags'] = 'The tag values sent as CSV format to search for Flickr images.';
index 94e0b69..36247e3 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_tag_flickr'; // Full name of the plugin (used for diagnostics)
index b9c146a..ae3bfef 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_tag_youtube'; // Full name of the plugin (used for diagnostics)
index 729270e..7a24646 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'block_tags';      // Full name of the plugin (used for diagnostics)
index 398d5a3..7fb7853 100644 (file)
@@ -72,7 +72,7 @@ class provider implements
             // coursemoduleid, courseid, moduleid, groupid, rating, usermodified.
         ], 'privacy:metadata:post');
 
-        $collection->link_subsystem('core_comments', 'privacy:metadata:core_comments');
+        $collection->link_subsystem('core_comment', 'privacy:metadata:core_comments');
         $collection->link_subsystem('core_files', 'privacy:metadata:core_files');
         $collection->link_subsystem('core_tag', 'privacy:metadata:core_tag');
 
index a9b7dfd..9142e90 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'cachelock_file';  // Full name of the plugin (used for diagnostics)
index c15411d..98f758a 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version = 2017111300;
-$plugin->requires = 2017110800;
+$plugin->version = 2018051400;
+$plugin->requires = 2018050800;
 $plugin->maturity = MATURITY_STABLE;
 $plugin->component = 'cachestore_apcu';
index 690f6fe..fe4d860 100644 (file)
@@ -27,6 +27,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version = 2017111300;    // The current module version (Date: YYYYMMDDXX)
-$plugin->requires = 2017110800;    // Requires this Moodle version.
+$plugin->version = 2018051400;    // The current module version (Date: YYYYMMDDXX)
+$plugin->requires = 2018050800;    // Requires this Moodle version.
 $plugin->component = 'cachestore_file';  // Full name of the plugin.
\ No newline at end of file
index 3fab186..fffc295 100644 (file)
@@ -26,6 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version = 2017111300;    // The current module version (Date: YYYYMMDDXX)
-$plugin->requires = 2017110800;    // Requires this Moodle version.
+$plugin->version = 2018051400;    // The current module version (Date: YYYYMMDDXX)
+$plugin->requires = 2018050800;    // Requires this Moodle version.
 $plugin->component = 'cachestore_memcache';  // Full name of the plugin.
index ed225f5..720794c 100644 (file)
@@ -26,6 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2017111300;    // The current module version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;    // Requires this Moodle version.
+$plugin->version   = 2018051400;    // The current module version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;    // Requires this Moodle version.
 $plugin->component = 'cachestore_memcached';  // Full name of the plugin.
\ No newline at end of file
index 1d339ba..34c5ec8 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2017111300;    // The current module version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;    // Requires this Moodle version.
+$plugin->version   = 2018051400;    // The current module version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;    // Requires this Moodle version.
 $plugin->component = 'cachestore_mongodb';  // Full name of the plugin.
\ No newline at end of file
index bb8b57d..65e6755 100644 (file)
@@ -24,8 +24,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version    = 2017111300;
-$plugin->requires   = 2017110800; // Requires this Moodle version.
+$plugin->version    = 2018051400;
+$plugin->requires   = 2018050800; // Requires this Moodle version.
 $plugin->maturity   = MATURITY_STABLE;
 $plugin->component  = 'cachestore_redis';
 $plugin->release    = '3.0.4 (Build: 20160509)';
index aa4e37c..1c28773 100644 (file)
@@ -27,6 +27,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version = 2017111300;    // The current module version (Date: YYYYMMDDXX)
-$plugin->requires = 2017110800;    // Requires this Moodle version.
+$plugin->version = 2018051400;    // The current module version (Date: YYYYMMDDXX)
+$plugin->requires = 2018050800;    // Requires this Moodle version.
 $plugin->component = 'cachestore_session';  // Full name of the plugin.
\ No newline at end of file
index 5098933..f004cdf 100644 (file)
@@ -27,6 +27,6 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2017111300;    // The current module version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;    // Requires this Moodle version.
+$plugin->version   = 2018051400;    // The current module version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;    // Requires this Moodle version.
 $plugin->component = 'cachestore_static';  // Full name of the plugin.
\ No newline at end of file
index be5e0c7..3881a1b 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800; // Requires this Moodle version.
+$plugin->version   = 2018051400; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800; // Requires this Moodle version.
 $plugin->component = 'calendartype_gregorian'; // Full name of the plugin (used for diagnostics).
index fc99649..686d6a3 100644 (file)
@@ -211,7 +211,7 @@ class provider implements
         ], 'privacy:metadata:competency_userevidencecomp');
 
         // Comments can be left on learning plans and competencies.
-        $collection->link_subsystem('core_comments', 'privacy:metadata:core_comments');
+        $collection->link_subsystem('core_comment', 'privacy:metadata:core_comments');
 
         return $collection;
     }
diff --git a/course/classes/privacy/provider.php b/course/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..41a8136
--- /dev/null
@@ -0,0 +1,220 @@
+<?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 class for requesting user data.
+ *
+ * @package    core_course
+ * @copyright  2018 Adrian Greeve <adrian@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_course\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\writer;
+use \core_privacy\local\request\transform;
+
+/**
+ * Privacy class for requesting user data.
+ *
+ * @copyright  2018 Adrian Greeve <adrian@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\context_aware_provider,
+        \core_privacy\local\request\plugin\provider,
+        \core_privacy\local\request\user_preference_provider {
+
+    /**
+     * Returns meta data about this system.
+     *
+     * @param   collection $collection The initialised collection to add items to.
+     * @return  collection A listing of user data stored through this system.
+     */
+    public static function get_metadata(collection $collection) : collection {
+        $collection->add_subsystem_link('core_completion', [], 'privacy:metadata:completionsummary');
+        $collection->add_user_preference('coursecat_management_perpage', 'privacy:perpage');
+        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(int $userid) : contextlist {
+        list($join, $where, $params) = \core_completion\privacy\provider::get_course_completion_join_sql($userid, 'cc', 'c.id');
+        $sql = "SELECT ctx.id
+                FROM {context} ctx
+                JOIN {course} c ON ctx.instanceid = c.id AND ctx.contextlevel = :contextcourse
+                {$join}
+                WHERE {$where}";
+        $params['contextcourse'] = CONTEXT_COURSE;
+        $contextlist = new contextlist();
+        $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;
+
+        // Get the course.
+        list($select, $params) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+        $params['contextcourse'] = CONTEXT_COURSE;
+
+        $sql = "SELECT c.*
+                FROM {course} c
+                JOIN {context} ctx ON c.id = ctx.instanceid AND ctx.contextlevel = :contextcourse
+                WHERE ctx.id $select";
+
+        $courses = $DB->get_recordset_sql($sql, $params);
+        foreach ($courses as $course) {
+            $coursecompletion = \core_completion\privacy\provider::get_course_completion_info($contextlist->get_user(), $course);
+            writer::with_context(\context_course::instance($course->id))->export_data(
+                    [get_string('privacy:completionpath', 'course')], (object) $coursecompletion);
+        }
+        $courses->close();
+    }
+
+    /**
+     * Give the component a chance to include any contextual information deemed relevant to any child contexts which are
+     * exporting personal data.
+     *
+     * By giving the component access to the full list of contexts being exported across all components, it can determine whether a
+     * descendant context is being exported, and decide whether to add relevant contextual information about itself. Having access
+     * to the full list of contexts being exported is what makes this component a context aware provider.
+     *
+     * E.g.
+     * If, during the core export process, a course module is included in the contextlist_collection but the course containing the
+     * module is not (perhaps there's no longer a user enrolment), then the course should include general contextual information in
+     * the export so we know basic details about which course the module belongs to. This method allows the course to make that
+     * decision, based on the existence of any decendant module contexts in the collection.
+     *
+     * @param \core_privacy\local\request\contextlist_collection $contextlistcollection
+     */
+    public static function export_context_data(\core_privacy\local\request\contextlist_collection $contextlistcollection) {
+        global $DB;
+
+        $coursecontextids = $DB->get_records_menu('context', ['contextlevel' => CONTEXT_COURSE], '', 'id, instanceid');
+        $courseids = [];
+        foreach ($contextlistcollection as $component) {
+            foreach ($component->get_contexts() as $context) {
+                // All course contexts have been accounted for, so skip all checks.
+                if (empty($coursecontextids)) {
+                    break;
+                }
+                // Only course, module, and block contexts are checked.
+                if (in_array($context->contextlevel, [CONTEXT_USER, CONTEXT_SYSTEM, CONTEXT_COURSECAT])) {
+                    continue;
+                }
+                // If the context is a course, then we just add it without the need to check context path.
+                if ($context->contextlevel == CONTEXT_COURSE) {
+                    $courseids[$context->id] = $context->instanceid;
+                    unset($coursecontextids[$context->id]);
+                    continue;
+                }
+                // Otherwise, we need to check all the course context paths, to see if this context is a descendant.
+                foreach ($coursecontextids as $contextid => $instanceid) {
+                    if (stripos($context->path, '/' . $contextid . '/') !== false) {
+                        $courseids[$contextid] = $instanceid;
+                        unset($coursecontextids[$contextid]);
+                    }
+                }
+            }
+        }
+        if (empty($courseids)) {
+            return;
+        }
+
+        // Export general data for these contexts.
+        list($sql, $params) = $DB->get_in_or_equal($courseids);
+        $sql = 'id ' . $sql;
+        $coursedata = $DB->get_records_select('course', $sql, $params);
+
+        foreach ($coursedata as $course) {
+            $context = \context_course::instance($course->id);
+            $data = (object) [
+                'fullname' => $course->fullname,
+                'shortname' => $course->shortname,
+                'idnumber' => $course->idnumber,
+                'summary' => writer::with_context($context)->rewrite_pluginfile_urls([], 'course', 'summary', 0,
+                                                                                     format_string($course->summary)),
+                'format' => get_string('pluginname', 'format_' . $course->format),
+                'startdate' => transform::datetime($course->startdate),
+                'enddate' => transform::datetime($course->enddate)
+            ];
+            writer::with_context($context)
+                    ->export_area_files([], 'course', 'summary', 0)
+                    ->export_area_files([], 'course', 'overviewfiles', 0)
+                    ->export_data([], $data);
+        }
+    }
+
+    /**
+     * Export all user preferences for the plugin.
+     *
+     * @param int $userid The userid of the user whose data is to be exported.
+     */
+    public static function export_user_preferences(int $userid) {
+        $perpage = get_user_preferences('coursecat_management_perpage', null, $userid);
+        if (isset($perpage)) {
+            writer::export_user_preference('core_course',
+                'coursecat_management_perpage',
+                $perpage,
+                get_string('privacy:perpage', 'course')
+            );
+        }
+    }
+
+    /**
+     * 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) {
+        // Check what context we've been delivered.
+        if ($context->contextlevel == CONTEXT_COURSE) {
+            // Delete course completion data.
+            \core_completion\privacy\provider::delete_completion(null, $context->instanceid);
+        }
+    }
+
+    /**
+     * 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) {
+        foreach ($contextlist as $context) {
+            if ($context->contextlevel == CONTEXT_COURSE) {
+                // Delete course completion data.
+                \core_completion\privacy\provider::delete_completion($contextlist->get_user(), $context->instanceid);
+            }
+        }
+    }
+}
index 39f46ce..784a596 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;              // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;              // Requires this Moodle version
+$plugin->version   = 2018051400;              // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;              // Requires this Moodle version
 $plugin->component = 'format_singleactivity'; // Full name of the plugin (used for diagnostics)
index 7c35770..c1556ed 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017111300;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017110800;        // Requires this Moodle version
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->requires  = 2018050800;        // Requires this Moodle version
 $plugin->component = 'format_social';   // Full name of the plugin (used for diagnostics)
index aa7210f..265bf3a 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2018030900;        // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;        // Requires this Moodle version.
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;        // Requires this Moodle version.
 $plugin->component = 'format_topics';    // Full name of the plugin (used for diagnostics).
index 3f1bb72..76dec02 100644 (file)
@@ -25,6 +25,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2018030900;        // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires  = 2017110800;        // Requires this Moodle version.
+$plugin->version   = 2018051400;        // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2018050800;        // Requires this Moodle version.
 $plugin->component = 'format_weeks';    // Full name of the plugin (used for diagnostics).
diff --git a/course/tests/privacy_test.php b/course/tests/privacy_test.php
new file mode 100644 (file)
index 0000000..b2d9033
--- /dev/null
@@ -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/>.
+/**
+ * Privacy tests for core_course.
+ *
+ * @package    core_course
+ * @category   test
+ * @copyright  2018 Adrian Greeve <adrian@moodle.com>