Merge branch 'MDL-61971-master' of git://github.com/mickhawkins/moodle
authorJake Dallimore <jake@moodle.com>
Thu, 10 May 2018 08:23:22 +0000 (16:23 +0800)
committerJake Dallimore <jake@moodle.com>
Thu, 10 May 2018 08:23:22 +0000 (16:23 +0800)
899 files changed:
admin/classes/privacy/provider.php [new file with mode: 0644]
admin/registration/index.php
admin/registration/renderer.php [deleted file]
admin/renderer.php
admin/roles/classes/define_role_table_advanced.php
admin/roles/classes/privacy/provider.php [new file with mode: 0644]
admin/roles/tests/privacy_test.php [new file with mode: 0644]
admin/settings/development.php
admin/settings/privacy.php [deleted file]
admin/settings/security.php
admin/settings/top.php
admin/settings/users.php
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/classes/expired_user_contexts.php
admin/tool/dataprivacy/settings.php
admin/tool/dataprivacy/styles.css
admin/tool/dataprivacy/templates/data_registry.mustache
admin/tool/dataprivacy/tests/expired_contexts_test.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/classes/local/privacy/helper.php [new file with mode: 0644]
admin/tool/log/classes/local/privacy/logstore_provider.php [new file with mode: 0644]
admin/tool/log/classes/local/privacy/moodle_database_export_and_delete.php [new file with mode: 0644]
admin/tool/log/classes/privacy/provider.php [new file with mode: 0644]
admin/tool/log/lang/en/tool_log.php
admin/tool/log/store/database/classes/privacy/provider.php [new file with mode: 0644]
admin/tool/log/store/database/lang/en/logstore_database.php
admin/tool/log/store/database/tests/privacy_test.php [new file with mode: 0644]
admin/tool/log/store/database/version.php
admin/tool/log/store/legacy/classes/privacy/provider.php [new file with mode: 0644]
admin/tool/log/store/legacy/lang/en/logstore_legacy.php
admin/tool/log/store/legacy/tests/privacy_test.php [new file with mode: 0644]
admin/tool/log/store/legacy/version.php
admin/tool/log/store/standard/classes/privacy/provider.php [new file with mode: 0644]
admin/tool/log/store/standard/lang/en/logstore_standard.php
admin/tool/log/store/standard/tests/privacy_test.php [new file with mode: 0644]
admin/tool/log/store/standard/version.php
admin/tool/log/tests/privacy_test.php [new file with mode: 0644]
admin/tool/log/version.php
admin/tool/lp/amd/build/planactions.min.js
admin/tool/lp/amd/src/planactions.js
admin/tool/lp/version.php
admin/tool/lpimportcsv/version.php
admin/tool/lpmigrate/version.php
admin/tool/messageinbound/classes/manager.php
admin/tool/messageinbound/classes/privacy/provider.php [new file with mode: 0644]
admin/tool/messageinbound/classes/task/cleanup_task.php
admin/tool/messageinbound/lang/en/tool_messageinbound.php
admin/tool/messageinbound/tests/manager_test.php [new file with mode: 0644]
admin/tool/messageinbound/tests/privacy_test.php [new file with mode: 0644]
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/accept.php
admin/tool/policy/amd/build/acceptmodal.min.js
admin/tool/policy/amd/src/acceptmodal.js
admin/tool/policy/classes/api.php
admin/tool/policy/classes/form/accept_policy.php
admin/tool/policy/classes/output/acceptances.php
admin/tool/policy/classes/output/page_agreedocs.php
admin/tool/policy/classes/output/page_viewalldoc.php
admin/tool/policy/classes/output/page_viewdoc.php
admin/tool/policy/classes/output/user_agreement.php
admin/tool/policy/lang/en/tool_policy.php
admin/tool/policy/lib.php
admin/tool/policy/templates/acceptances.mustache
admin/tool/policy/templates/page_viewalldoc.mustache
admin/tool/policy/templates/user_agreement.mustache
admin/tool/policy/tests/api_test.php
admin/tool/policy/tests/behat/acceptances.feature
admin/tool/policy/tests/behat/managepolicies.feature
admin/tool/policy/tests/privacy_provider_test.php
admin/tool/policy/version.php
admin/tool/profiling/settings.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
analytics/classes/local/analyser/base.php
analytics/classes/privacy/provider.php [new file with mode: 0644]
analytics/tests/fixtures/test_site_users_analyser.php [new file with mode: 0644]
analytics/tests/fixtures/test_target_course_users.php [new file with mode: 0644]
analytics/tests/fixtures/test_target_site_users.php [new file with mode: 0644]
analytics/tests/privacy_test.php [new file with mode: 0644]
analytics/upgrade.txt [new file with mode: 0644]
auth/cas/version.php
auth/classes/privacy/provider.php [new file with mode: 0644]
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/tests/privacy_test.php [new file with mode: 0644]
auth/webservice/version.php
availability/classes/privacy/provider.php [new file with mode: 0644]
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
backup/tests/privacy_provider_test.php [new file with mode: 0644]
backup/util/ui/classes/privacy/provider.php [new file with mode: 0644]
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/edit_form.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
blog/tests/privacy_test.php
cache/classes/privacy/provider.php [new file with mode: 0644]
cache/locks/file/classes/privacy/provider.php [new file with mode: 0644]
cache/locks/file/lang/en/cachelock_file.php
cache/locks/file/version.php
cache/stores/apcu/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/apcu/lang/en/cachestore_apcu.php
cache/stores/apcu/version.php
cache/stores/file/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/file/lang/en/cachestore_file.php
cache/stores/file/version.php
cache/stores/memcache/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/memcache/lang/en/cachestore_memcache.php
cache/stores/memcache/version.php
cache/stores/memcached/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/memcached/lang/en/cachestore_memcached.php
cache/stores/memcached/version.php
cache/stores/mongodb/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/mongodb/lang/en/cachestore_mongodb.php
cache/stores/mongodb/version.php
cache/stores/redis/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/redis/lang/en/cachestore_redis.php
cache/stores/redis/version.php
cache/stores/session/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/session/lang/en/cachestore_session.php
cache/stores/session/version.php
cache/stores/static/classes/privacy/provider.php [new file with mode: 0644]
cache/stores/static/lang/en/cachestore_static.php
cache/stores/static/version.php
calendar/classes/privacy/provider.php [new file with mode: 0644]
calendar/lib.php
calendar/tests/privacy_test.php [new file with mode: 0644]
calendar/type/gregorian/version.php
comment/classes/privacy/provider.php
comment/tests/privacy_test.php
competency/classes/external/performance_helper.php
competency/classes/privacy/provider.php [new file with mode: 0644]
competency/tests/privacy_test.php [new file with mode: 0644]
completion/classes/privacy/provider.php [new file with mode: 0644]
completion/tests/fixtures/completion_creation.php [new file with mode: 0644]
completion/tests/privacy_test.php [new file with mode: 0644]
course/classes/privacy/provider.php [new file with mode: 0644]
course/externallib.php
course/format/singleactivity/version.php
course/format/social/version.php
course/format/topics/version.php
course/format/weeks/version.php
course/publish/backup.php
course/publish/index.php
course/publish/metadata.php
course/publish/renderer.php [deleted file]
course/renderer.php
course/tests/externallib_test.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/classes/privacy/provider.php [new file with mode: 0644]
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
grade/tests/privacy_test.php [new file with mode: 0644]
group/classes/privacy/provider.php [new file with mode: 0644]
group/tests/privacy_provider_test.php [new file with mode: 0644]
index.php
install/lang/tl/moodle.php
lang/en/admin.php
lang/en/analytics.php
lang/en/antivirus.php
lang/en/auth.php
lang/en/availability.php
lang/en/backup.php
lang/en/cache.php
lang/en/calendar.php
lang/en/competency.php
lang/en/completion.php
lang/en/course.php [new file with mode: 0644]
lang/en/enrol.php
lang/en/form.php
lang/en/grades.php
lang/en/group.php
lang/en/message.php
lang/en/mnet.php
lang/en/portfolio.php
lang/en/question.php
lang/en/role.php
lang/en/search.php
lang/en/user.php [new file with mode: 0644]
lang/en/webservice.php
lib/amd/build/modal.min.js
lib/amd/src/modal.js
lib/antivirus/clamav/version.php
lib/antivirus/classes/privacy/provider.php [new file with mode: 0644]
lib/classes/analytics/analyser/student_enrolments.php
lib/classes/event/notification_sent.php
lib/classes/output/icon_system_fontawesome.php
lib/cronlib.php
lib/editor/atto/db/upgrade.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/lang/en/atto_image.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/lang/en/atto_media.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/lang/en/atto_recordrtc.php
lib/editor/atto/plugins/recordrtc/lib.php
lib/editor/atto/plugins/recordrtc/pix/i/audiortc.png
lib/editor/atto/plugins/recordrtc/pix/i/videortc.png
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/settings.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/form/classes/privacy/provider.php [new file with mode: 0644]
lib/form/modgrade.php
lib/form/tests/privacy_provider_test.php [new file with mode: 0644]
lib/mlbackend/php/classes/privacy/provider.php [new file with mode: 0644]
lib/mlbackend/php/lang/en/mlbackend_php.php
lib/mlbackend/php/version.php
lib/mlbackend/python/classes/privacy/provider.php [new file with mode: 0644]
lib/mlbackend/python/lang/en/mlbackend_python.php
lib/mlbackend/python/version.php
lib/modinfolib.php
lib/moodlelib.php
lib/portfolio/exporter.php
lib/portfoliolib.php
lib/questionlib.php
lib/templates/modal.mustache
lib/tests/moodlelib_test.php
lib/upgrade.txt
lib/xhprof/xhprof_moodle.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/classes/privacy/provider.php [new file with mode: 0644]
message/output/airnotifier/version.php
message/output/email/version.php
message/output/jabber/version.php
message/output/popup/version.php
message/templates/message_area_message.mustache
message/tests/events_test.php
message/tests/privacy_provider_test.php [new file with mode: 0644]
mnet/classes/privacy/provider.php [new file with mode: 0644]
mnet/service/enrol/classes/privacy/provider.php [new file with mode: 0644]
mnet/service/enrol/lang/en/mnetservice_enrol.php
mnet/service/enrol/tests/privacy_test.php [new file with mode: 0644]
mnet/service/enrol/version.php
mod/assign/feedback/comments/version.php
mod/assign/feedback/editpdf/classes/document_services.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/locallib.php
mod/assign/submission/comments/version.php
mod/assign/submission/file/version.php
mod/assign/submission/onlinetext/version.php
mod/assign/tests/portfolio_caller_test.php [new file with mode: 0644]
mod/assign/version.php
mod/assignment/classes/privacy/provider.php [new file with mode: 0644]
mod/assignment/lang/en/assignment.php
mod/assignment/tests/privacy_test.php [new file with mode: 0644]
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/classes/privacy/provider.php [new file with mode: 0644]
mod/book/lang/en/book.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/styles.css
mod/chat/version.php
mod/choice/version.php
mod/data/classes/privacy/datafield_provider.php [new file with mode: 0644]
mod/data/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/checkbox/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/checkbox/lang/en/datafield_checkbox.php
mod/data/field/checkbox/version.php
mod/data/field/date/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/date/lang/en/datafield_date.php
mod/data/field/date/version.php
mod/data/field/file/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/file/field.class.php
mod/data/field/file/lang/en/datafield_file.php
mod/data/field/file/version.php
mod/data/field/latlong/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/latlong/lang/en/datafield_latlong.php
mod/data/field/latlong/version.php
mod/data/field/menu/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/menu/lang/en/datafield_menu.php
mod/data/field/menu/version.php
mod/data/field/multimenu/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/multimenu/lang/en/datafield_multimenu.php
mod/data/field/multimenu/version.php
mod/data/field/number/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/number/lang/en/datafield_number.php
mod/data/field/number/version.php
mod/data/field/picture/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/picture/field.class.php
mod/data/field/picture/lang/en/datafield_picture.php
mod/data/field/picture/version.php
mod/data/field/radiobutton/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/radiobutton/lang/en/datafield_radiobutton.php
mod/data/field/radiobutton/version.php
mod/data/field/text/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/text/lang/en/datafield_text.php
mod/data/field/text/version.php
mod/data/field/textarea/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/textarea/lang/en/datafield_textarea.php
mod/data/field/textarea/version.php
mod/data/field/url/classes/privacy/provider.php [new file with mode: 0644]
mod/data/field/url/lang/en/datafield_url.php
mod/data/field/url/version.php
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/preset/imagegallery/version.php
mod/data/tests/generator/lib.php
mod/data/tests/generator_test.php
mod/data/tests/privacy_provider_test.php [new file with mode: 0644]
mod/data/version.php
mod/feedback/version.php
mod/folder/lib.php
mod/folder/renderer.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/classes/privacy/provider.php [new file with mode: 0644]
mod/lti/lang/en/lti.php
mod/lti/service/gradebookservices/classes/privacy/provider.php [new file with mode: 0644]
mod/lti/service/gradebookservices/lang/en/ltiservice_gradebookservices.php
mod/lti/service/gradebookservices/tests/privacy_provider_test.php [new file with mode: 0644]
mod/lti/service/gradebookservices/version.php
mod/lti/service/memberships/classes/privacy/provider.php [new file with mode: 0644]
mod/lti/service/memberships/lang/en/ltiservice_memberships.php
mod/lti/service/memberships/tests/privacy_provider_test.php [new file with mode: 0644]
mod/lti/service/memberships/version.php
mod/lti/service/profile/classes/privacy/provider.php [new file with mode: 0644]
mod/lti/service/profile/lang/en/ltiservice_profile.php
mod/lti/service/profile/version.php
mod/lti/service/toolproxy/classes/privacy/provider.php [new file with mode: 0644]
mod/lti/service/toolproxy/lang/en/ltiservice_toolproxy.php
mod/lti/service/toolproxy/version.php
mod/lti/service/toolsettings/classes/privacy/provider.php [new file with mode: 0644]
mod/lti/service/toolsettings/lang/en/ltiservice_toolsettings.php
mod/lti/service/toolsettings/version.php
mod/lti/tests/privacy_provider_test.php [new file with mode: 0644]
mod/lti/version.php
mod/page/version.php
mod/quiz/accessrule/delaybetweenattempts/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/delaybetweenattempts/lang/en/quizaccess_delaybetweenattempts.php
mod/quiz/accessrule/delaybetweenattempts/version.php
mod/quiz/accessrule/ipaddress/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/ipaddress/lang/en/quizaccess_ipaddress.php
mod/quiz/accessrule/ipaddress/version.php
mod/quiz/accessrule/numattempts/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/numattempts/lang/en/quizaccess_numattempts.php
mod/quiz/accessrule/numattempts/version.php
mod/quiz/accessrule/offlineattempts/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/offlineattempts/lang/en/quizaccess_offlineattempts.php
mod/quiz/accessrule/offlineattempts/version.php
mod/quiz/accessrule/openclosedate/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/openclosedate/lang/en/quizaccess_openclosedate.php
mod/quiz/accessrule/openclosedate/version.php
mod/quiz/accessrule/password/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/password/lang/en/quizaccess_password.php
mod/quiz/accessrule/password/version.php
mod/quiz/accessrule/safebrowser/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/safebrowser/lang/en/quizaccess_safebrowser.php
mod/quiz/accessrule/safebrowser/version.php
mod/quiz/accessrule/securewindow/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/securewindow/lang/en/quizaccess_securewindow.php
mod/quiz/accessrule/securewindow/version.php
mod/quiz/accessrule/timelimit/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/accessrule/timelimit/lang/en/quizaccess_timelimit.php
mod/quiz/accessrule/timelimit/version.php
mod/quiz/classes/output/edit_renderer.php
mod/quiz/classes/privacy/helper.php [new file with mode: 0644]
mod/quiz/classes/privacy/legacy_quizaccess_polyfill.php [new file with mode: 0644]
mod/quiz/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/classes/privacy/quizaccess_provider.php [new file with mode: 0644]
mod/quiz/classes/structure.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/report/grading/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/report/grading/lang/en/quiz_grading.php
mod/quiz/report/grading/version.php
mod/quiz/report/overview/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/report/overview/lang/en/quiz_overview.php
mod/quiz/report/overview/tests/privacy_provider_test.php [new file with mode: 0644]
mod/quiz/report/overview/version.php
mod/quiz/report/responses/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/report/responses/lang/en/quiz_responses.php
mod/quiz/report/responses/tests/privacy_provider_test.php [new file with mode: 0644]
mod/quiz/report/responses/version.php
mod/quiz/report/statistics/classes/privacy/provider.php [new file with mode: 0644]
mod/quiz/report/statistics/lang/en/quiz_statistics.php
mod/quiz/report/statistics/version.php
mod/quiz/tests/locallib_test.php
mod/quiz/tests/privacy_legacy_quizaccess_polyfill_test.php [new file with mode: 0644]
mod/quiz/tests/privacy_provider_test.php [new file with mode: 0644]
mod/quiz/tests/structure_test.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/upgrade.txt
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
phpunit.xml.dist
pix/e/insert_edit_video.png
pix/e/insert_edit_video.svg
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/local/request/contextlist.php
privacy/classes/local/request/helper.php
privacy/classes/local/request/moodle_content_writer.php
privacy/classes/manager.php
privacy/classes/tests/request/content_writer.php
privacy/tests/moodle_content_writer_test.php
privacy/tests/provider_test.php
privacy/tests/tests_content_writer_test.php
privacy/tests/writer_test.php
question/behaviour/adaptive/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/adaptive/lang/en/qbehaviour_adaptive.php
question/behaviour/adaptive/version.php
question/behaviour/adaptivenopenalty/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/adaptivenopenalty/lang/en/qbehaviour_adaptivenopenalty.php
question/behaviour/adaptivenopenalty/version.php
question/behaviour/deferredcbm/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/deferredcbm/lang/en/qbehaviour_deferredcbm.php
question/behaviour/deferredcbm/version.php
question/behaviour/deferredfeedback/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/deferredfeedback/lang/en/qbehaviour_deferredfeedback.php
question/behaviour/deferredfeedback/version.php
question/behaviour/immediatecbm/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/immediatecbm/lang/en/qbehaviour_immediatecbm.php
question/behaviour/immediatecbm/version.php
question/behaviour/immediatefeedback/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/immediatefeedback/lang/en/qbehaviour_immediatefeedback.php
question/behaviour/immediatefeedback/version.php
question/behaviour/informationitem/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/informationitem/lang/en/qbehaviour_informationitem.php
question/behaviour/informationitem/version.php
question/behaviour/interactive/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/interactive/lang/en/qbehaviour_interactive.php
question/behaviour/interactive/version.php
question/behaviour/interactivecountback/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/interactivecountback/lang/en/qbehaviour_interactivecountback.php
question/behaviour/interactivecountback/version.php
question/behaviour/manualgraded/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/manualgraded/lang/en/qbehaviour_manualgraded.php
question/behaviour/manualgraded/version.php
question/behaviour/missing/classes/privacy/provider.php [new file with mode: 0644]
question/behaviour/missing/lang/en/qbehaviour_missing.php
question/behaviour/missing/version.php
question/classes/privacy/provider.php [new file with mode: 0644]
question/format.php
question/format/aiken/classes/privacy/provider.php [new file with mode: 0644]
question/format/aiken/lang/en/qformat_aiken.php
question/format/aiken/version.php
question/format/blackboard_six/classes/privacy/provider.php [new file with mode: 0644]
question/format/blackboard_six/lang/en/qformat_blackboard_six.php
question/format/blackboard_six/version.php
question/format/examview/classes/privacy/provider.php [new file with mode: 0644]
question/format/examview/lang/en/qformat_examview.php
question/format/examview/version.php
question/format/gift/classes/privacy/provider.php [new file with mode: 0644]
question/format/gift/lang/en/qformat_gift.php
question/format/gift/version.php
question/format/missingword/classes/privacy/provider.php [new file with mode: 0644]
question/format/missingword/lang/en/qformat_missingword.php
question/format/missingword/version.php
question/format/multianswer/classes/privacy/provider.php [new file with mode: 0644]
question/format/multianswer/lang/en/qformat_multianswer.php
question/format/multianswer/version.php
question/format/webct/classes/privacy/provider.php [new file with mode: 0644]
question/format/webct/lang/en/qformat_webct.php
question/format/webct/version.php
question/format/xhtml/classes/privacy/provider.php [new file with mode: 0644]
question/format/xhtml/lang/en/qformat_xhtml.php
question/format/xhtml/version.php
question/format/xml/classes/privacy/provider.php [new file with mode: 0644]
question/format/xml/lang/en/qformat_xml.php
question/format/xml/version.php
question/tests/generator/lib.php
question/tests/privacy_helper.php [new file with mode: 0644]
question/tests/privacy_provider_test.php [new file with mode: 0644]
question/type/calculated/classes/privacy/provider.php [new file with mode: 0644]
question/type/calculated/lang/en/qtype_calculated.php
question/type/calculated/version.php
question/type/calculatedmulti/classes/privacy/provider.php [new file with mode: 0644]
question/type/calculatedmulti/lang/en/qtype_calculatedmulti.php
question/type/calculatedmulti/version.php
question/type/calculatedsimple/classes/privacy/provider.php [new file with mode: 0644]
question/type/calculatedsimple/lang/en/qtype_calculatedsimple.php
question/type/calculatedsimple/version.php
question/type/ddimageortext/classes/privacy/provider.php [new file with mode: 0644]
question/type/ddimageortext/lang/en/qtype_ddimageortext.php
question/type/ddimageortext/version.php
question/type/ddmarker/classes/privacy/provider.php [new file with mode: 0644]
question/type/ddmarker/lang/en/qtype_ddmarker.php
question/type/ddmarker/version.php
question/type/ddwtos/classes/privacy/provider.php [new file with mode: 0644]
question/type/ddwtos/lang/en/qtype_ddwtos.php
question/type/ddwtos/version.php
question/type/description/classes/privacy/provider.php [new file with mode: 0644]
question/type/description/lang/en/qtype_description.php
question/type/description/version.php
question/type/essay/classes/privacy/provider.php [new file with mode: 0644]
question/type/essay/lang/en/qtype_essay.php
question/type/essay/version.php
question/type/gapselect/classes/privacy/provider.php [new file with mode: 0644]
question/type/gapselect/lang/en/qtype_gapselect.php
question/type/gapselect/renderer.php
question/type/gapselect/rendererbase.php
question/type/gapselect/version.php
question/type/match/classes/privacy/provider.php [new file with mode: 0644]
question/type/match/lang/en/qtype_match.php
question/type/match/version.php
question/type/missingtype/classes/privacy/provider.php [new file with mode: 0644]
question/type/missingtype/lang/en/qtype_missingtype.php
question/type/missingtype/version.php
question/type/multianswer/classes/privacy/provider.php [new file with mode: 0644]
question/type/multianswer/lang/en/qtype_multianswer.php
question/type/multianswer/version.php
question/type/multichoice/classes/privacy/provider.php [new file with mode: 0644]
question/type/multichoice/lang/en/qtype_multichoice.php
question/type/multichoice/version.php
question/type/numerical/classes/privacy/provider.php [new file with mode: 0644]
question/type/numerical/lang/en/qtype_numerical.php
question/type/numerical/version.php
question/type/random/classes/privacy/provider.php [new file with mode: 0644]
question/type/random/lang/en/qtype_random.php
question/type/random/version.php
question/type/randomsamatch/classes/privacy/provider.php [new file with mode: 0644]
question/type/randomsamatch/lang/en/qtype_randomsamatch.php
question/type/randomsamatch/version.php
question/type/shortanswer/classes/privacy/provider.php [new file with mode: 0644]
question/type/shortanswer/lang/en/qtype_shortanswer.php
question/type/shortanswer/version.php
question/type/truefalse/classes/privacy/provider.php [new file with mode: 0644]
question/type/truefalse/lang/en/qtype_truefalse.php
question/type/truefalse/version.php
question/type/upgrade.txt
question/upgrade.txt
rating/classes/privacy/provider.php
rating/tests/privacy_provider_test.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/privacy/provider.php
tag/classes/tests/privacy_helper.php [new file with mode: 0644]
tag/tests/privacy_test.php
theme/boost/scss/moodle/blocks.scss
theme/boost/scss/moodle/bs4alphacompat.scss
theme/boost/scss/moodle/chat.scss
theme/boost/scss/moodle/core.scss
theme/boost/scss/moodle/forms.scss
theme/boost/scss/moodle/message.scss
theme/boost/scss/moodle/modules.scss
theme/boost/scss/moodle/undo.scss
theme/boost/templates/columns2.mustache
theme/boost/templates/core/custom_menu_item.mustache
theme/boost/templates/core/filemanager_modal_generallayout.mustache
theme/boost/templates/core/modal.mustache
theme/boost/templates/core/paging_bar.mustache
theme/boost/templates/core_form/element-duration-inline.mustache
theme/boost/templates/footer.mustache
theme/boost/tests/behat/behat_theme_boost_behat_repository_upload.php
theme/boost/version.php
theme/bootstrapbase/less/moodle/undo.less
theme/bootstrapbase/style/moodle.css
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/classes/privacy/provider.php
user/profile/field/checkbox/version.php
user/profile/field/datetime/classes/privacy/provider.php [new file with mode: 0644]
user/profile/field/datetime/lang/en/profilefield_datetime.php
user/profile/field/datetime/tests/privacy_test.php [new file with mode: 0644]
user/profile/field/datetime/version.php
user/profile/field/menu/classes/privacy/provider.php [new file with mode: 0644]
user/profile/field/menu/lang/en/profilefield_menu.php
user/profile/field/menu/tests/privacy_test.php [new file with mode: 0644]
user/profile/field/menu/version.php
user/profile/field/text/classes/privacy/provider.php [new file with mode: 0644]
user/profile/field/text/lang/en/profilefield_text.php
user/profile/field/text/tests/privacy_test.php [new file with mode: 0644]
user/profile/field/text/version.php
user/profile/field/textarea/classes/privacy/provider.php [new file with mode: 0644]
user/profile/field/textarea/lang/en/profilefield_textarea.php
user/profile/field/textarea/tests/privacy_test.php [new file with mode: 0644]
user/profile/field/textarea/version.php
user/tests/privacy_test.php [new file with mode: 0644]
version.php
webservice/classes/privacy/provider.php [new file with mode: 0644]
webservice/rest/version.php
webservice/soap/version.php
webservice/tests/privacy_test.php [new file with mode: 0644]
webservice/xmlrpc/version.php

diff --git a/admin/classes/privacy/provider.php b/admin/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..118308d
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+/**
+ * Privacy Subsystem implementation for core_admin.
+ *
+ * @package    core_admin
+ * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+namespace core_admin\privacy;
+defined('MOODLE_INTERNAL') || die();
+/**
+ * Privacy Subsystem for core_admin implementing null_provider.
+ *
+ * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class provider implements \core_privacy\local\metadata\null_provider {
+    /**
+     * Get the language string identifier with the component's language
+     * file to explain why this plugin stores no data.
+     *
+     * @return  string
+     */
+    public static function get_reason() : string {
+        return 'privacy:metadata';
+    }
+}
index dee1ba0..57d65a3 100644 (file)
@@ -110,7 +110,7 @@ if (\core\hub\registration::is_registered()) {
     echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
 }
 
-$renderer = $PAGE->get_renderer('core', 'register');
+$renderer = $PAGE->get_renderer('core', 'admin');
 echo $renderer->moodleorg_registration_message();
 
 $siteregistrationform->display();
diff --git a/admin/registration/renderer.php b/admin/registration/renderer.php
deleted file mode 100644 (file)
index b7414b4..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-///////////////////////////////////////////////////////////////////////////
-//                                                                       //
-// This file is part of Moodle - http://moodle.org/                      //
-// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
-//                                                                       //
-// Moodle is free software: you can redistribute it and/or modify        //
-// it under the terms of the GNU General Public License as published by  //
-// the Free Software Foundation, either version 3 of the License, or     //
-// (at your option) any later version.                                   //
-//                                                                       //
-// Moodle is distributed in the hope that it will be useful,             //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
-// GNU General Public License for more details.                          //
-//                                                                       //
-// You should have received a copy of the GNU General Public License     //
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.       //
-//                                                                       //
-///////////////////////////////////////////////////////////////////////////
-
-/**
- * Registration renderer.
- * @package   moodle
- * @subpackage registration
- * @copyright 2010 Moodle Pty Ltd (http://moodle.com)
- * @author    Jerome Mouneyrac
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class core_register_renderer extends plugin_renderer_base {
-
-    /**
-     * Display message about the benefits of registering on Moodle.org
-     *
-     * @return string
-     */
-    public function moodleorg_registration_message() {
-        return format_text(get_string('registermoodlenet', 'admin'), FORMAT_HTML, ['noclean' => true]);
-    }
-}
index dbd77f6..f22c6a2 100644 (file)
@@ -2084,4 +2084,13 @@ class core_admin_renderer extends plugin_renderer_base {
             return $this->warning(get_string('legacylogginginuse'));
         }
     }
+
+    /**
+     * Display message about the benefits of registering on Moodle.org
+     *
+     * @return string
+     */
+    public function moodleorg_registration_message() {
+        return format_text(get_string('registermoodlenet', 'admin'), FORMAT_HTML, ['noclean' => true]);
+    }
 }
index 16e188b..354ba8c 100644 (file)
@@ -528,9 +528,11 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
             if (!$this->disabled) {
                 $output .= '<input type="hidden" name="contextlevel' . $cl . '" value="0" />';
             }
-            $output .= '<input type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
+            $output .= '<div class="form-check justify-content-start w-100">';
+            $output .= '<input class="form-check-input" type="checkbox" id="cl' . $cl . '" name="contextlevel' . $cl .
                 '" value="1" ' . $extraarguments . '/> ';
-            $output .= '<label for="cl' . $cl . '">' . $clname . "</label><br />\n";
+            $output .= '<label class="form-check-label" for="cl' . $cl . '">' . $clname . "</label>\n";
+            $output .= '</div>';
         }
         return $output;
     }
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 41d779f..f8dab27 100644 (file)
@@ -16,6 +16,9 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     $temp->add(new admin_setting_configexecutable('pathtosassc', new lang_string('pathtosassc', 'admin'), new lang_string('pathtosassc_help', 'admin'), ''));
 
+    $temp->add(new admin_setting_configcheckbox('forceclean', new lang_string('forceclean', 'core_admin'),
+        new lang_string('forceclean_desc', 'core_admin'), 0));
+
     $ADMIN->add('experimental', $temp);
 
     // "debugging" settingpage
@@ -30,7 +33,9 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $ADMIN->add('development', $temp);
 
     // "Profiling" settingpage (conditionally if the 'xhprof' extension is available only).
-    $xhprofenabled = extension_loaded('xhprof') || extension_loaded('tideways');
+    $xhprofenabled = extension_loaded('tideways_xhprof');
+    $xhprofenabled = $xhprofenabled || extension_loaded('tideways');
+    $xhprofenabled = $xhprofenabled || extension_loaded('xhprof');
     $temp = new admin_settingpage('profiling', new lang_string('profiling', 'admin'), 'moodle/site:config', !$xhprofenabled);
     // Main profiling switch.
     $temp->add(new admin_setting_configcheckbox('profilingenabled', new lang_string('profilingenabled', 'admin'), new lang_string('profilingenabled_help', 'admin'), false));
diff --git a/admin/settings/privacy.php b/admin/settings/privacy.php
deleted file mode 100644 (file)
index 87f8c52..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Adds privacy and policies links to admin tree.
- *
- * @package   core_privacy
- * @copyright 2018 Marina Glancy
- * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-defined('MOODLE_INTERNAL') || die();
-
-if ($hassiteconfig) {
-    // Privacy settings.
-    $temp = new admin_settingpage('privacysettings', new lang_string('privacysettings', 'admin'));
-
-    $options = array(
-        0 => get_string('no'),
-        1 => get_string('yes')
-    );
-    $url = new moodle_url('/admin/settings.php?section=supportcontact');
-    $url = $url->out();
-    $setting = new admin_setting_configselect('agedigitalconsentverification',
-        new lang_string('agedigitalconsentverification', 'admin'),
-        new lang_string('agedigitalconsentverification_desc', 'admin', $url), 0, $options);
-    $setting->set_force_ltr(true);
-    $temp->add($setting);
-
-    $setting = new admin_setting_agedigitalconsentmap('agedigitalconsentmap',
-        new lang_string('ageofdigitalconsentmap', 'admin'),
-        new lang_string('ageofdigitalconsentmap_desc', 'admin'),
-        // See {@link https://gdpr-info.eu/art-8-gdpr/}.
-        implode(PHP_EOL, [
-            '*, 16',
-            'AT, 14',
-            'CZ, 13',
-            'DE, 14',
-            'DK, 13',
-            'ES, 13',
-            'FI, 15',
-            'GB, 13',
-            'HU, 14',
-            'IE, 13',
-            'LT, 16',
-            'LU, 16',
-            'NL, 16',
-            'PL, 13',
-            'SE, 13',
-        ]),
-        PARAM_RAW
-    );
-    $temp->add($setting);
-
-    $ADMIN->add('privacy', $temp);
-
-    // Policy settings.
-    $temp = new admin_settingpage('policysettings', new lang_string('policysettings', 'admin'));
-    $temp->add(new admin_settings_sitepolicy_handler_select('sitepolicyhandler', new lang_string('sitepolicyhandler', 'core_admin'),
-        new lang_string('sitepolicyhandler_desc', 'core_admin')));
-    $temp->add(new admin_setting_configtext('sitepolicy', new lang_string('sitepolicy', 'core_admin'),
-        new lang_string('sitepolicy_help', 'core_admin'), '', PARAM_RAW));
-    $temp->add(new admin_setting_configtext('sitepolicyguest', new lang_string('sitepolicyguest', 'core_admin'),
-        new lang_string('sitepolicyguest_help', 'core_admin'), (isset($CFG->sitepolicy) ? $CFG->sitepolicy : ''), PARAM_RAW));
-
-    $ADMIN->add('privacy', $temp);
-}
index b6a9f89..a6ac61f 100644 (file)
@@ -43,9 +43,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configtext('userquota', new lang_string('userquota', 'admin'),
                 new lang_string('configuserquota', 'admin', $params), $defaultuserquota, PARAM_INT, 30));
 
-    $temp->add(new admin_setting_configcheckbox('forceclean', new lang_string('forceclean', 'core_admin'),
-        new lang_string('forceclean_desc', 'core_admin'), 0));
-
     $temp->add(new admin_setting_configcheckbox('allowobjectembed', new lang_string('allowobjectembed', 'admin'), new lang_string('configallowobjectembed', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('enabletrusttext', new lang_string('enabletrusttext', 'admin'), new lang_string('configenabletrusttext', 'admin'), 0));
     $temp->add(new admin_setting_configselect('maxeditingtime', new lang_string('maxeditingtime','admin'), new lang_string('configmaxeditingtime','admin'), 1800,
index a049ce9..17621cb 100644 (file)
@@ -29,7 +29,6 @@ $ADMIN->add('root', new admin_category('badges', new lang_string('badges'), empt
 $ADMIN->add('root', new admin_category('location', new lang_string('location','admin')));
 $ADMIN->add('root', new admin_category('language', new lang_string('language')));
 $ADMIN->add('root', new admin_category('modules', new lang_string('plugins', 'admin')));
-$ADMIN->add('root', new admin_category('privacy', new lang_string('privacyandpolicies', 'admin')));
 $ADMIN->add('root', new admin_category('security', new lang_string('security','admin')));
 $ADMIN->add('root', new admin_category('appearance', new lang_string('appearance','admin')));
 $ADMIN->add('root', new admin_category('frontpage', new lang_string('frontpage','admin')));
index d444961..465a9d7 100644 (file)
@@ -4,6 +4,7 @@
 
 $ADMIN->add('users', new admin_category('accounts', new lang_string('accounts', 'admin')));
 $ADMIN->add('users', new admin_category('roles', new lang_string('permissions', 'role')));
+$ADMIN->add('users', new admin_category('privacy', new lang_string('privacyandpolicies', 'admin')));
 
 if ($hassiteconfig
  or has_capability('moodle/user:create', $systemcontext)
@@ -210,3 +211,58 @@ if ($hassiteconfig
     $ADMIN->add('roles', new admin_externalpage('checkpermissions', new lang_string('checkglobalpermissions', 'role'), "$CFG->wwwroot/$CFG->admin/roles/check.php?contextid=".$systemcontext->id, array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:manage')));
 
 } // end of speedup
+
+// Privacy settings.
+if ($hassiteconfig) {
+    $temp = new admin_settingpage('privacysettings', new lang_string('privacysettings', 'admin'));
+
+    $options = array(
+        0 => get_string('no'),
+        1 => get_string('yes')
+    );
+    $url = new moodle_url('/admin/settings.php?section=supportcontact');
+    $url = $url->out();
+    $setting = new admin_setting_configselect('agedigitalconsentverification',
+        new lang_string('agedigitalconsentverification', 'admin'),
+        new lang_string('agedigitalconsentverification_desc', 'admin', $url), 0, $options);
+    $setting->set_force_ltr(true);
+    $temp->add($setting);
+
+    $setting = new admin_setting_agedigitalconsentmap('agedigitalconsentmap',
+        new lang_string('ageofdigitalconsentmap', 'admin'),
+        new lang_string('ageofdigitalconsentmap_desc', 'admin'),
+        // See {@link https://gdpr-info.eu/art-8-gdpr/}.
+        implode(PHP_EOL, [
+            '*, 16',
+            'AT, 14',
+            'CZ, 13',
+            'DE, 14',
+            'DK, 13',
+            'ES, 13',
+            'FI, 15',
+            'GB, 13',
+            'HU, 14',
+            'IE, 13',
+            'LT, 16',
+            'LU, 16',
+            'NL, 16',
+            'PL, 13',
+            'SE, 13',
+        ]),
+        PARAM_RAW
+    );
+    $temp->add($setting);
+
+    $ADMIN->add('privacy', $temp);
+
+    // Policy settings.
+    $temp = new admin_settingpage('policysettings', new lang_string('policysettings', 'admin'));
+    $temp->add(new admin_settings_sitepolicy_handler_select('sitepolicyhandler', new lang_string('sitepolicyhandler', 'core_admin'),
+        new lang_string('sitepolicyhandler_desc', 'core_admin')));
+    $temp->add(new admin_setting_configtext('sitepolicy', new lang_string('sitepolicy', 'core_admin'),
+        new lang_string('sitepolicy_help', 'core_admin'), '', PARAM_RAW));
+    $temp->add(new admin_setting_configtext('sitepolicyguest', new lang_string('sitepolicyguest', 'core_admin'),
+        new lang_string('sitepolicyguest_help', 'core_admin'), (isset($CFG->sitepolicy) ? $CFG->sitepolicy : ''), PARAM_RAW));
+
+    $ADMIN->add('privacy', $temp);
+}
\ 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 62d9485..e4b40e8 100644 (file)
@@ -115,12 +115,35 @@ class expired_user_contexts extends \tool_dataprivacy\expired_contexts_manager {
      * @return \context|false
      */
     protected function delete_expired_context(\core_privacy\manager $privacymanager, \tool_dataprivacy\expired_context $expiredctx) {
-        if (!$context = parent::delete_expired_context($privacymanager, $expiredctx)) {
+        $context = \context::instance_by_id($expiredctx->get('contextid'), IGNORE_MISSING);
+        if (!$context) {
+            api::delete_expired_context($expiredctx->get('contextid'));
             return false;
         }
 
-        // Delete the user.
+        if (!PHPUNIT_TEST) {
+            mtrace('Deleting context ' . $context->id . ' - ' .
+                shorten_text($context->get_context_name(true, true)));
+        }
+
+        // To ensure that all user data is deleted, instead of deleting by context, we run through and collect any stray
+        // contexts for the user that may still exist and call delete_data_for_user().
         $user = \core_user::get_user($context->instanceid, '*', MUST_EXIST);
+        $approvedlistcollection = new \core_privacy\local\request\contextlist_collection($user->id);
+        $contextlistcollection = $privacymanager->get_contexts_for_userid($user->id);
+
+        foreach ($contextlistcollection as $contextlist) {
+            $approvedlistcollection->add_contextlist(new \core_privacy\local\request\approved_contextlist(
+                $user,
+                $contextlist->get_component(),
+                $contextlist->get_contextids()
+            ));
+        }
+
+        $privacymanager->delete_data_for_user($approvedlistcollection);
+        api::set_expired_context_status($expiredctx, expired_context::STATUS_CLEANED);
+
+        // Delete the user.
         delete_user($user);
 
         return $context;
index 3f28b00..f04fc10 100644 (file)
@@ -49,7 +49,7 @@ if ($hassiteconfig) {
             }
         }
         if (!empty($roles)) {
-            $privacysettings->add(new admin_setting_configmultiselect('tool_dataprivacy/dporoles',
+            $privacysettings->add(new admin_setting_configmulticheckbox('tool_dataprivacy/dporoles',
                     new lang_string('dporolemapping', 'tool_dataprivacy'),
                     new lang_string('dporolemapping_desc', 'tool_dataprivacy'), null, $roles)
             );
index bff49a7..a72cf5e 100644 (file)
@@ -1,7 +1,9 @@
 .nav-pills .nav-pills {
     margin-left: 1rem;
 }
-
+.data-registry > .top-nav > * {
+    margin-right: 0.5rem;
+}
 /*Extra attribute selection to have preference over bs2's .moodle-actionmenu[data-enhance] */
 .data-registry > .top-nav > .singlebutton,
 .data-registry > .top-nav > .moodle-actionmenu[data-owner='dataregistry-actions'] {
index 203510b..e4aa0c6 100644 (file)
@@ -33,7 +33,7 @@
     }
 }}
 <div class="data-registry">
-    <div class="top-nav">
+    <div class="top-nav d-flex">
         {{#defaultsbutton}}
             {{> core/action_link}}
         {{/defaultsbutton}}
index 7e62cc4..1e434a7 100644 (file)
@@ -84,6 +84,22 @@ class tool_dataprivacy_expired_contexts_testcase extends advanced_testcase {
         $this->getDataGenerator()->enrol_user($user3->id, $course2->id, 'student');
         $this->getDataGenerator()->enrol_user($user4->id, $course3->id, 'student');
 
+        // Add an activity and some data for user 2.
+        $assignmod = $this->getDataGenerator()->create_module('assign', ['course' => $course2->id]);
+        $data = (object) [
+            'assignment' => $assignmod->id,
+            'userid' => $user2->id,
+            'timecreated' => time(),
+            'timemodified' => time(),
+            'status' => 'new',
+            'groupid' => 0,
+            'attemptnumber' => 0,
+            'latest' => 1,
+        ];
+        $DB->insert_record('assign_submission', $data);
+        // We should have one record in the assign submission table.
+        $this->assertEquals(1, $DB->count_records('assign_submission'));
+
         // Users without lastaccess are skipped as well as users enroled in courses with no end date.
         $expired = new \tool_dataprivacy\expired_user_contexts();
         $numexpired = $expired->flag_expired();
@@ -109,6 +125,9 @@ class tool_dataprivacy_expired_contexts_testcase extends advanced_testcase {
         $deleted = $expired->delete();
         $this->assertEquals(0, $deleted);
 
+        // No user data left in mod_assign.
+        $this->assertEquals(0, $DB->count_records('assign_submission'));
+
         // The user is deleted.
         $deleteduser = \core_user::get_user($user2->id, 'id, deleted', IGNORE_MISSING);
         $this->assertEquals(1, $deleteduser->deleted);
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)
diff --git a/admin/tool/log/classes/local/privacy/helper.php b/admin/tool/log/classes/local/privacy/helper.php
new file mode 100644 (file)
index 0000000..4aa17d1
--- /dev/null
@@ -0,0 +1,148 @@
+<?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 helper.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\local\privacy;
+defined('MOODLE_INTERNAL') || die();
+
+use core_privacy\local\request\transform;
+
+/**
+ * Privacy helper class.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class helper {
+
+    /**
+     * Returns an event from a standard record.
+     *
+     * @see \logstore_standard\log\store::get_log_event()
+     * @param object $data Log data.
+     * @return \core\event\base
+     */
+    protected static function restore_event_from_standard_record($data) {
+        $extra = ['origin' => $data->origin, 'ip' => $data->ip, 'realuserid' => $data->realuserid];
+        $data = (array) $data;
+        $id = $data['id'];
+        $data['other'] = unserialize($data['other']);
+        if ($data['other'] === false) {
+            $data['other'] = [];
+        }
+        unset($data['origin']);
+        unset($data['ip']);
+        unset($data['realuserid']);
+        unset($data['id']);
+
+        if (!$event = \core\event\base::restore($data, $extra)) {
+            return null;
+        }
+
+        return $event;
+    }
+
+    /**
+     * Transform a standard log record for a user.
+     *
+     * @param object $record The record.
+     * @param int $userid The user ID.
+     * @return array
+     */
+    public static function transform_standard_log_record_for_userid($record, $userid) {
+
+        // Restore the event to try to get the name, description and other field.
+        $restoredevent = static::restore_event_from_standard_record($record);
+        if ($restoredevent) {
+            $name = $restoredevent->get_name();
+            $description = $restoredevent->get_description();
+            $other = $restoredevent->other;
+
+        } else {
+            $name = $record->eventname;
+            $description = "Unknown event ({$name})";
+            $other = unserialize($record->other);
+        }
+
+        $realuserid = $record->realuserid;
+        $isauthor = $record->userid == $userid;
+        $isrelated = $record->relateduserid == $userid;
+        $isrealuser = $realuserid == $userid;
+        $ismasqueraded = $realuserid !== null && $record->userid != $realuserid;
+        $ismasquerading = $isrealuser && !$isauthor;
+        $isanonymous = $record->anonymous;
+
+        $data = [
+            'name' => $name,
+            'description' => $description,
+            'timecreated' => transform::datetime($record->timecreated),
+            'ip' => $record->ip,
+            'origin' => static::transform_origin($record->origin),
+            'other' => $other ? $other : []
+        ];
+
+        if ($isanonymous) {
+            $data['action_was_done_anonymously'] = transform::yesno($isanonymous);
+        }
+        if ($isauthor || !$isanonymous) {
+            $data['authorid'] = transform::user($record->userid);
+            $data['author_of_the_action_was_you'] = transform::yesno($isauthor);
+        }
+
+        if ($record->relateduserid) {
+            $data['relateduserid'] = transform::user($record->relateduserid);
+            $data['related_user_was_you'] = transform::yesno($isrelated);
+        }
+
+        if ($ismasqueraded) {
+            $data['author_of_the_action_was_masqueraded'] = transform::yesno(true);
+            if ($ismasquerading || !$isanonymous) {
+                $data['masqueradinguserid'] = transform::user($realuserid);
+                $data['masquerading_user_was_you'] = transform::yesno($ismasquerading);
+            }
+        }
+
+        return $data;
+    }
+
+    /**
+     * Transform origin.
+     *
+     * @param string $origin The page request origin.
+     * @return string
+     */
+    public static function transform_origin($origin) {
+        switch ($origin) {
+            case 'cli':
+            case 'restore':
+            case 'web':
+            case 'ws':
+                return get_string('privacy:request:origin:' . $origin, 'tool_log');
+                break;
+        }
+        return $origin;
+    }
+}
diff --git a/admin/tool/log/classes/local/privacy/logstore_provider.php b/admin/tool/log/classes/local/privacy/logstore_provider.php
new file mode 100644 (file)
index 0000000..cecc130
--- /dev/null
@@ -0,0 +1,78 @@
+<?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/>.
+
+/**
+ * Logstore provider interface.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\local\privacy;
+defined('MOODLE_INTERNAL') || die();
+
+use context;
+use core_privacy\local\request\contextlist;
+use core_privacy\local\request\approved_contextlist;
+
+/**
+ * Logstore provider interface.
+ *
+ * Logstore subplugins providers must implement this interface.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+interface logstore_provider extends \core_privacy\local\request\plugin\subplugin_provider {
+
+    /**
+     * Add contexts that contain user information for the specified user.
+     *
+     * @param contextlist $contextlist The contextlist to add the contexts to.
+     * @param int $userid The user to find the contexts for.
+     * @return void
+     */
+    public static function add_contexts_for_userid(contextlist $contextlist, $userid);
+
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts to export information for.
+     * @return void
+     */
+    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.
+     * @return void
+     */
+    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.
+     * @return void
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist);
+
+}
diff --git a/admin/tool/log/classes/local/privacy/moodle_database_export_and_delete.php b/admin/tool/log/classes/local/privacy/moodle_database_export_and_delete.php
new file mode 100644 (file)
index 0000000..da973ea
--- /dev/null
@@ -0,0 +1,123 @@
+<?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/>.
+
+/**
+ * Moodle database: export and delete.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\local\privacy;
+defined('MOODLE_INTERNAL') || die();
+
+use context;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\writer;
+
+/**
+ * Moodle database: export and delete trait.
+ *
+ * This is to be used with logstores which use a database and table with the same columns
+ * as the core plugin 'logstore_standard'.
+ *
+ * This trait expects the following methods to be present in the object:
+ *
+ * - public static function get_database_and_table(): [moodle_database|null, string|null]
+ * - public static function get_export_subcontext(): []
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+trait moodle_database_export_and_delete {
+
+    /**
+     * 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) {
+        list($db, $table) = static::get_database_and_table();
+        if (!$db || !$table) {
+            return;
+        }
+
+        $userid = $contextlist->get_user()->id;
+        list($insql, $inparams) = $db->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+
+        $sql = "(userid = :userid1 OR relateduserid = :userid2 OR realuserid = :userid3) AND contextid $insql";
+        $params = array_merge($inparams, [
+            'userid1' => $userid,
+            'userid2' => $userid,
+            'userid3' => $userid,
+        ]);
+
+        $path = static::get_export_subcontext();
+        $flush = function($lastcontextid, $data) use ($path) {
+            $context = context::instance_by_id($lastcontextid);
+            writer::with_context($context)->export_data($path, (object) ['logs' => $data]);
+        };
+
+        $lastcontextid = null;
+        $data = [];
+        $recordset = $db->get_recordset_select($table, $sql, $params, 'contextid, timecreated, id');
+        foreach ($recordset as $record) {
+            if ($lastcontextid && $lastcontextid != $record->contextid) {
+                $flush($lastcontextid, $data);
+                $data = [];
+            }
+            $data[] = helper::transform_standard_log_record_for_userid($record, $userid);
+            $lastcontextid = $record->contextid;
+        }
+        if ($lastcontextid) {
+            $flush($lastcontextid, $data);
+        }
+        $recordset->close();
+    }
+
+    /**
+     * 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) {
+        list($db, $table) = static::get_database_and_table();
+        if (!$db || !$table) {
+            return;
+        }
+        $db->delete_records($table, ['contextid' => $context->id]);
+    }
+
+    /**
+     * 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) {
+        list($db, $table) = static::get_database_and_table();
+        if (!$db || !$table) {
+            return;
+        }
+        list($insql, $inparams) = $db->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
+        $params = array_merge($inparams, ['userid' => $contextlist->get_user()->id]);
+        $db->delete_records_select($table, "userid = :userid AND contextid $insql", $params);
+    }
+
+}
diff --git a/admin/tool/log/classes/privacy/provider.php b/admin/tool/log/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..af91b8b
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Data provider.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_log\privacy;
+defined('MOODLE_INTERNAL') || die();
+
+use context;
+use core_privacy\local\metadata\collection;
+use core_privacy\local\request\approved_contextlist;
+use core_privacy\local\request\transform;
+use core_privacy\local\request\writer;
+use tool_log\log\manager;
+
+/**
+ * Data provider class.
+ *
+ * @package    tool_log
+ * @copyright  2018 Frédéric Massart
+ * @author     Frédéric Massart <fred@branchup.tech>
+ * @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 {
+
+    /**
+     * Returns metadata.
+     *
+     * @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_plugintype_link('logstore', [], 'privacy:metadata:logstore');
+        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) : \core_privacy\local\request\contextlist {
+        $contextlist = new \core_privacy\local\request\contextlist();
+        static::call_subplugins_method_with_args('add_contexts_for_userid', [$contextlist, $userid]);
+        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) {
+        static::call_subplugins_method_with_args('export_user_data', [$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) {
+        static::call_subplugins_method_with_args('delete_data_for_all_users_in_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) {
+        static::call_subplugins_method_with_args('delete_data_for_user', [$contextlist]);
+    }
+
+    /**
+     * Invoke the subplugins method with arguments.
+     *
+     * @param string $method The method name.
+     * @param array $args The arguments.
+     * @return void
+     */
+    protected static function call_subplugins_method_with_args($method, array $args = []) {
+        $interface = \tool_log\local\privacy\logstore_provider::class;
+        \core_privacy\manager::plugintype_class_callback('logstore', $interface, $method, $args);
+    }
+
+}
index c57c424..bfda300 100644 (file)
@@ -26,7 +26,13 @@ $string['actlogshdr'] = 'Available log stores';
 $string['configlogplugins'] = 'Please enable all required plugins and arrange them in appropriate order.';
 $string['logging'] = 'Logging';
 $string['managelogging'] = 'Manage log stores';
-$string['reportssupported'] = 'Reports supported';
 $string['pluginname'] = 'Log store manager';
+$string['privacy:metadata:logstore'] = 'The log stores';
+$string['privacy:path:logs'] = 'Logs';
+$string['privacy:request:origin:cli'] = 'Command line tool';
+$string['privacy:request:origin:restore'] = 'Backup being restored';
+$string['privacy:request:origin:web'] = 'Standard web request';
+$string['privacy:request:origin:ws'] = 'Mobile app or web service';
+$string['reportssupported'] = 'Reports supported';
 $string['subplugintype_logstore'] = 'Log store';
 $string['subplugintype_logstore_plural'] = 'Log stores';
diff --git a/admin/tool/log/store/database/classes/privacy/provider.php b/admin/tool/log/store/database/classes/privacy/provider.php
new file mode 100644 (file)
index 0000000..