MDL-63657 tool_mobile: Add support for removal of context users
authorMichael Hawkins <michaelh@moodle.com>
Mon, 15 Oct 2018 05:27:59 +0000 (13:27 +0800)
committerMichael Hawkins <michaelh@moodle.com>
Tue, 23 Oct 2018 02:54:14 +0000 (10:54 +0800)
This issue is a part of the MDL-62560 Epic.

admin/tool/mobile/classes/privacy/provider.php
admin/tool/mobile/tests/privacy_provider_test.php

index c29c0a1..620060b 100644 (file)
@@ -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);
+    }
+}
index d553a10..ccfa644 100644 (file)
@@ -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);
+    }
+}