diff --git a/admin/tool/mobile/classes/privacy/provider.php b/admin/tool/mobile/classes/privacy/provider.php index c29c0a1c8bb..620060b4853 100644 --- a/admin/tool/mobile/classes/privacy/provider.php +++ b/admin/tool/mobile/classes/privacy/provider.php @@ -26,7 +26,9 @@ use \core_privacy\local\request\writer; use \core_privacy\local\metadata\collection; use \core_privacy\local\request\contextlist; use \core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\approved_userlist; use \core_privacy\local\request\transform; +use core_privacy\local\request\userlist; /** * Privacy provider for tool_mobile. @@ -36,6 +38,7 @@ use \core_privacy\local\request\transform; */ class provider implements \core_privacy\local\metadata\provider, + \core_privacy\local\request\core_userlist_provider, \core_privacy\local\request\user_preference_provider, \core_privacy\local\request\plugin\provider { /** @@ -70,6 +73,23 @@ 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(); + + if (!is_a($context, \context_user::class)) { + return; + } + + // Add users based on userkey. + \core_userkey\privacy\provider::get_user_contexts_with_script($userlist, $context, 'tool_mobile'); + } + /** * Export all user data for the specified user, in the specified contexts. * @@ -139,4 +159,24 @@ class provider implements // Delete all the userkeys. \core_userkey\privacy\provider::delete_userkeys('tool_mobile', $userid); } -} \ No newline at end of file + + /** + * Delete multiple users within a single context. + * + * @param approved_userlist $userlist The approved context and user information to delete information for. + */ + public static function delete_data_for_users(approved_userlist $userlist) { + global $DB; + $context = $userlist->get_context(); + $userids = $userlist->get_userids(); + $userid = reset($userids); + + // Only deleting data for the user ID in that user's user context should be valid. + if ($context->contextlevel !== CONTEXT_USER || count($userids) != 1 || $userid != $context->instanceid) { + return; + } + + // Delete all the userkeys. + \core_userkey\privacy\provider::delete_userkeys('tool_mobile', $userid); + } +} diff --git a/admin/tool/mobile/tests/privacy_provider_test.php b/admin/tool/mobile/tests/privacy_provider_test.php index d553a105bc3..ccfa64459fe 100644 --- a/admin/tool/mobile/tests/privacy_provider_test.php +++ b/admin/tool/mobile/tests/privacy_provider_test.php @@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die(); use \core_privacy\local\request\writer; use \core_privacy\local\request\transform; use \core_privacy\local\request\approved_contextlist; +use \core_privacy\local\request\approved_userlist; use \tool_mobile\privacy\provider; /** @@ -59,6 +60,7 @@ class tool_mobile_privacy_testcase extends \core_privacy\tests\provider_testcase $this->assertEquals(get_string('privacy:metadata:preference:tool_mobile_autologin_request_last', 'tool_mobile'), $prefs->tool_mobile_autologin_request_last->description); } + /** * Test getting the context for the user ID related to this plugin. */ @@ -70,6 +72,31 @@ class tool_mobile_privacy_testcase extends \core_privacy\tests\provider_testcase $contextlist = provider::get_contexts_for_userid($user->id); $this->assertEquals($context->id, $contextlist->current()->id); } + + /** + * Test getting the users for a context related to this plugin. + */ + public function test_get_users_in_context() { + $component = 'tool_mobile'; + + // Create users and Mobile user keys. + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $context1 = \context_user::instance($user1->id); + $context2 = \context_user::instance($user2->id); + $key1 = get_user_key('tool_mobile', $user1->id); + $key2 = get_user_key('tool_mobile', $user2->id); + + // Ensure only user1 is found in context1. + $userlist = new \core_privacy\local\request\userlist($context1, $component); + provider::get_users_in_context($userlist); + $userids = $userlist->get_userids(); + $userid = reset($userids); + + $this->assertCount(1, $userids); + $this->assertEquals($user1->id, $userid); + } + /** * Test that data is exported correctly for this plugin. */ @@ -89,6 +116,7 @@ class tool_mobile_privacy_testcase extends \core_privacy\tests\provider_testcase $this->assertCount(1, $userkeydata->keys); $this->assertEquals($key->script, reset($userkeydata->keys)->script); } + /** * Test for provider::delete_data_for_all_users_in_context(). */ @@ -108,6 +136,7 @@ class tool_mobile_privacy_testcase extends \core_privacy\tests\provider_testcase $count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']); $this->assertEquals(0, $count); } + /** * Test for provider::delete_data_for_user(). */ @@ -129,4 +158,46 @@ class tool_mobile_privacy_testcase extends \core_privacy\tests\provider_testcase $count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']); $this->assertEquals(0, $count); } -} \ No newline at end of file + + /** + * Test for provider::test_delete_data_for_users(). + */ + public function test_delete_data_for_users() { + global $DB; + $component = 'tool_mobile'; + + // Create users and Mobile user keys. + $user1 = $this->getDataGenerator()->create_user(); + $user2 = $this->getDataGenerator()->create_user(); + $context1 = \context_user::instance($user1->id); + $context2 = \context_user::instance($user2->id); + $keyvalue1 = get_user_key('tool_mobile', $user1->id); + $keyvalue2 = get_user_key('tool_mobile', $user2->id); + $key1 = $DB->get_record('user_private_key', ['value' => $keyvalue1]); + + // Before deletion, we should have 2 user_private_keys. + $count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']); + $this->assertEquals(2, $count); + + // Ensure deleting wrong user in the user context does nothing. + $approveduserids = [$user2->id]; + $approvedlist = new approved_userlist($context1, $component, $approveduserids); + provider::delete_data_for_users($approvedlist); + + $count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']); + $this->assertEquals(2, $count); + + // Delete for user1 in context1. + $approveduserids = [$user1->id]; + $approvedlist = new approved_userlist($context1, $component, $approveduserids); + provider::delete_data_for_users($approvedlist); + + // Ensure only user1's data is deleted, user2's remains. + $count = $DB->count_records('user_private_key', ['script' => 'tool_mobile']); + $this->assertEquals(1, $count); + + $params = ['script' => $component]; + $userid = $DB->get_field_select('user_private_key', 'userid', 'script = :script', $params); + $this->assertEquals($user2->id, $userid); + } +}