MDL-63688 core_tag: Add method that returns users in context
authorMihail Geshoski <mihail@moodle.com>
Wed, 24 Oct 2018 01:26:11 +0000 (09:26 +0800)
committerMihail Geshoski <mihail@moodle.com>
Wed, 24 Oct 2018 01:31:19 +0000 (09:31 +0800)
This issue is part of the MDL-62560 Epic.

tag/classes/privacy/provider.php
tag/tests/privacy_test.php

index 25379ce..212b27f 100644 (file)
@@ -31,6 +31,8 @@ use core_privacy\local\request\approved_contextlist;
 use core_privacy\local\request\contextlist;
 use core_privacy\local\request\transform;
 use core_privacy\local\request\writer;
+use core_privacy\local\request\userlist;
+use core_privacy\local\request\approved_userlist;
 
 /**
  * Privacy Subsystem implementation for core_tag.
@@ -45,6 +47,9 @@ class provider implements
         // The tag subsystem provides data to other components.
         \core_privacy\local\request\subsystem\plugin_provider,
 
+        // This plugin is capable of determining which users have data within it.
+        \core_privacy\local\request\core_userlist_provider,
+
         // The tag subsystem may have data that belongs to this user.
         \core_privacy\local\request\plugin\provider {
 
@@ -210,6 +215,24 @@ class provider implements
         return $contextlist;
     }
 
+    /**
+     * Get the list of users within a specific 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 (!$context instanceof \context_system) {
+            return;
+        }
+
+        $sql = "SELECT userid
+                  FROM {tag}";
+
+        $userlist->add_from_sql('userid', $sql, []);
+    }
+
     /**
      * Export all user data for the specified user, in the specified contexts.
      *
@@ -264,6 +287,25 @@ class provider implements
         }
     }
 
+    /**
+     * 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();
+
+        if ($context instanceof \context_system) {
+            // Do not delete tags themselves in case they are used by somebody else.
+            // If the user is the only one using the tag, it will be automatically deleted anyway during the
+            // next cron cleanup.
+            list($usersql, $userparams) = $DB->get_in_or_equal($userlist->get_userids(), SQL_PARAMS_NAMED);
+            $DB->set_field_select('tag', 'userid', 0, "userid {$usersql}", $userparams);
+        }
+    }
+
     /**
      * Delete all user data for the specified user, in the specified contexts.
      *
index 56c8ae9..7253764 100644 (file)
@@ -31,6 +31,7 @@ require_once($CFG->dirroot . '/tag/lib.php');
 use \core_privacy\tests\provider_testcase;
 use \core_privacy\local\request\writer;
 use \core_tag\privacy\provider;
+use \core_privacy\local\request\approved_userlist;
 
 /**
  * Unit tests for tag/classes/privacy/policy
@@ -271,4 +272,75 @@ class core_tag_privacy_testcase extends provider_testcase {
         $this->assertEquals('Computers', $data->rawname);
         $this->assertEquals(['computer.jpg'], array_keys($files));
     }
+
+    /**
+     * Test that only users within a system context are fetched.
+     */
+    public function test_get_users_in_context() {
+        $component = 'core_tag';
+
+        $user1 = $this->set_up_tags()[0];
+        $systemcontext = context_system::instance();
+
+        $userlist1 = new \core_privacy\local\request\userlist($systemcontext, $component);
+        provider::get_users_in_context($userlist1);
+        $this->assertCount(1, $userlist1);
+        $expected = [$user1->id];
+        $actual = $userlist1->get_userids();
+        $this->assertEquals($expected, $actual);
+
+        // The list of users within the a context other than system context should be empty.
+        $usercontext1 = context_user::instance($user1->id);
+        $userlist2 = new \core_privacy\local\request\userlist($usercontext1, $component);
+        provider::get_users_in_context($userlist2);
+        $this->assertCount(0, $userlist2);
+    }
+
+    /**
+     * Test that data for users in approved userlist is deleted.
+     */
+    public function test_delete_data_for_users() {
+        $component = 'core_tag';
+
+        list($user1, $user2) = $this->set_up_tags();
+        $usercontext1 = context_user::instance($user1->id);
+        $user3 = $this->getDataGenerator()->create_user();
+        $systemcontext = context_system::instance();
+
+        $this->setUser($user2);
+        useredit_update_interests($user2, ['basketball']);
+
+        $this->setUser($user3);
+        useredit_update_interests($user3, ['soccer']);
+
+        $userlist = new \core_privacy\local\request\userlist($systemcontext, $component);
+        provider::get_users_in_context($userlist);
+        $this->assertCount(3, $userlist);
+        $this->assertTrue(in_array($user1->id, $userlist->get_userids()));
+        $this->assertTrue(in_array($user2->id, $userlist->get_userids()));
+        $this->assertTrue(in_array($user3->id, $userlist->get_userids()));
+
+        // Data should not be deleted in contexts other than system context.
+        // Convert $userlist into an approved_contextlist.
+        $approvedlist = new approved_userlist($usercontext1, $component, $userlist->get_userids());
+        // Delete using delete_data_for_user.
+        provider::delete_data_for_users($approvedlist);
+        // Re-fetch users in systemcontext.
+        $userlist = new \core_privacy\local\request\userlist($systemcontext, $component);
+        provider::get_users_in_context($userlist);
+        // The user data in systemcontext should not be deleted.
+        $this->assertCount(3, $userlist);
+
+        // Add user1 and user2 into an approved_contextlist.
+        $approvedlist = new approved_userlist($systemcontext, $component, [$user1->id, $user2->id]);
+        // Delete using delete_data_for_user.
+        provider::delete_data_for_users($approvedlist);
+        // Re-fetch users in systemcontext.
+        $userlist = new \core_privacy\local\request\userlist($systemcontext, $component);
+        provider::get_users_in_context($userlist);
+        // The approved user data in systemcontext should be deleted.
+        // The user list should return user3.
+        $this->assertCount(1, $userlist);
+        $this->assertTrue(in_array($user3->id, $userlist->get_userids()));
+    }
 }