From f6843ac96649e8cd7139015b6a916d271de1d2f3 Mon Sep 17 00:00:00 2001 From: Michael Hawkins Date: Tue, 16 Oct 2018 13:48:49 +0800 Subject: [PATCH] MDL-63664 tool_policy: Add support for removal of context users This issue is a part of the MDL-62560 Epic. --- .../tool/policy/classes/privacy/provider.php | 43 +++++++++ .../policy/tests/privacy_provider_test.php | 93 ++++++++++++++++++- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/admin/tool/policy/classes/privacy/provider.php b/admin/tool/policy/classes/privacy/provider.php index 67e4e515e5d..cf9116d7571 100644 --- a/admin/tool/policy/classes/privacy/provider.php +++ b/admin/tool/policy/classes/privacy/provider.php @@ -26,8 +26,10 @@ namespace tool_policy\privacy; use core_privacy\local\metadata\collection; use core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\approved_userlist; use core_privacy\local\request\contextlist; use core_privacy\local\request\moodle_content_writer; +use core_privacy\local\request\userlist; use core_privacy\local\request\transform; use core_privacy\local\request\writer; @@ -43,6 +45,9 @@ class provider implements // This tool stores user data. \core_privacy\local\metadata\provider, + // This plugin is capable of determining which users have data within it. + \core_privacy\local\request\core_userlist_provider, + // This tool may provide access to and deletion of user data. \core_privacy\local\request\plugin\provider { @@ -132,6 +137,33 @@ class provider implements return $contextlist; } + /** + * Get the list of users who have data within a context. + * + * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination. + */ + public static function get_users_in_context(userlist $userlist) { + $context = $userlist->get_context(); + + // Users that have modified any policies, if fetching for system context. + if (is_a($context, \context_system::class)) { + $sql = "SELECT v.usermodified AS userid + FROM {tool_policy_versions} v"; + $userlist->add_from_sql('userid', $sql, []); + } + + // Users that have accepted any policies, if fetching for user context. + if (is_a($context, \context_user::class)) { + $sql = "SELECT a.userid, a.usermodified + FROM {tool_policy_acceptances} a + WHERE a.userid = :instanceid"; + $params = ['instanceid' => $context->instanceid]; + + $userlist->add_from_sql('userid', $sql, $params); + $userlist->add_from_sql('usermodified', $sql, $params); + } + } + /** * Export personal data for the given approved_contextlist. User and context information is contained within the contextlist. * @@ -172,6 +204,17 @@ class provider implements public static function delete_data_for_user(approved_contextlist $contextlist) { } + /** + * Delete multiple users within a single context. + * + * We never delete user agreements to the policies because they are part of privacy data. + * We never delete policy versions because they are part of privacy data. + * + * @param approved_userlist $userlist The approved context and user information to delete information for. + */ + public static function delete_data_for_users(approved_userlist $userlist) { + } + /** * Export all policy agreements relating to the specified user context. * diff --git a/admin/tool/policy/tests/privacy_provider_test.php b/admin/tool/policy/tests/privacy_provider_test.php index 78556c9bd52..3e2b146f67d 100644 --- a/admin/tool/policy/tests/privacy_provider_test.php +++ b/admin/tool/policy/tests/privacy_provider_test.php @@ -45,6 +45,9 @@ class tool_policy_privacy_provider_testcase extends \core_privacy\tests\provider /** @var stdClass The manager user object. */ protected $manager; +/** @var context_system The system context instance. */ + protected $syscontext; + /** * Setup function. Will create a user. */ @@ -56,11 +59,11 @@ class tool_policy_privacy_provider_testcase extends \core_privacy\tests\provider // Create manager user. $this->manager = $generator->create_user(); - $syscontext = context_system::instance(); + $this->syscontext = context_system::instance(); $rolemanagerid = create_role('Policy manager', 'policymanager', 'Can manage policy documents'); - assign_capability('tool/policy:managedocs', CAP_ALLOW, $rolemanagerid, $syscontext->id); - assign_capability('tool/policy:acceptbehalf', CAP_ALLOW, $rolemanagerid, $syscontext->id); - role_assign($rolemanagerid, $this->manager->id, $syscontext->id); + assign_capability('tool/policy:managedocs', CAP_ALLOW, $rolemanagerid, $this->syscontext->id); + assign_capability('tool/policy:acceptbehalf', CAP_ALLOW, $rolemanagerid, $this->syscontext->id); + role_assign($rolemanagerid, $this->manager->id, $this->syscontext->id); accesslib_clear_all_caches_for_unit_testing(); } @@ -99,6 +102,88 @@ class tool_policy_privacy_provider_testcase extends \core_privacy\tests\provider $this->assertEquals(1, $contextlist->count()); } + /** + * Test getting the user IDs within the context related to this plugin. + */ + public function test_get_users_in_context() { + global $CFG; + $component = 'tool_policy'; + + // System context should have nothing before a policy is added. + $userlist = new \core_privacy\local\request\userlist($this->syscontext, $component); + provider::get_users_in_context($userlist); + $this->assertEmpty($userlist); + + // Create parent and child users. + $generator = $this->getDataGenerator(); + $parentuser = $generator->create_user(); + $childuser = $generator->create_user(); + + // Fetch relevant contexts. + $managercontext = \context_user::instance($this->manager->id); + $usercontext = $managercontext = \context_user::instance($this->user->id); + $parentcontext = $managercontext = \context_user::instance($parentuser->id); + $childcontext = $managercontext = \context_user::instance($childuser->id); + + // Assign parent to accept on behalf of the child. + $roleparentid = create_role('Parent', 'parent', 'Can accept policies on behalf of their child'); + assign_capability('tool/policy:acceptbehalf', CAP_ALLOW, $roleparentid, $this->syscontext->id); + role_assign($roleparentid, $parentuser->id, $childcontext->id); + + // Create a policy. + $this->setUser($this->manager); + $CFG->sitepolicyhandler = 'tool_policy'; + $policy = $this->add_policy(); + api::make_current($policy->get('id')); + + // Manager should exist in system context now they have created a policy. + $userlist = new \core_privacy\local\request\userlist($this->syscontext, $component); + provider::get_users_in_context($userlist); + $this->assertCount(1, $userlist); + $this->assertEquals([$this->manager->id], $userlist->get_userids()); + + // User contexts should be empty before policy acceptances. + $userlist = new \core_privacy\local\request\userlist($usercontext, $component); + provider::get_users_in_context($userlist); + $this->assertEmpty($userlist); + + $userlist = new \core_privacy\local\request\userlist($parentcontext, $component); + provider::get_users_in_context($userlist); + $this->assertEmpty($userlist); + + $userlist = new \core_privacy\local\request\userlist($childcontext, $component); + provider::get_users_in_context($userlist); + $this->assertEmpty($userlist); + + // User accepts policy, parent accepts on behalf of child only. + $this->setUser($this->user); + api::accept_policies([$policy->get('id')]); + + $this->setUser($parentuser); + api::accept_policies([$policy->get('id')], $childuser->id); + + // Ensure user is fetched within its user context. + $userlist = new \core_privacy\local\request\userlist($usercontext, $component); + provider::get_users_in_context($userlist); + $this->assertCount(1, $userlist); + $this->assertEquals([$this->user->id], $userlist->get_userids()); + + // Ensure parent and child are both found within child's user context. + $userlist = new \core_privacy\local\request\userlist($childcontext, $component); + provider::get_users_in_context($userlist); + $this->assertCount(2, $userlist); + $expected = [$parentuser->id, $childuser->id]; + $actual = $userlist->get_userids(); + sort($expected); + sort($actual); + $this->assertEquals($expected, $actual); + + // Parent has not accepted for itself, so should not be found within its user context. + $userlist = new \core_privacy\local\request\userlist($parentcontext, $component); + provider::get_users_in_context($userlist); + $this->assertCount(0, $userlist); + } + public function test_export_agreements() { global $CFG;