MDL-63668 core_course: Add support for removal of context users
authorMichael Hawkins <michaelh@moodle.com>
Wed, 17 Oct 2018 04:20:55 +0000 (12:20 +0800)
committerMichael Hawkins <michaelh@moodle.com>
Tue, 23 Oct 2018 02:06:26 +0000 (10:06 +0800)
This issue is a part of the MDL-62560 Epic.

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

index 4d1941a..a0808c1 100644 (file)
@@ -29,8 +29,10 @@ 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\writer;
+use \core_privacy\local\request\approved_userlist;
 use \core_privacy\local\request\transform;
+use \core_privacy\local\request\userlist;
+use \core_privacy\local\request\writer;
 
 /**
  * Privacy class for requesting user data.
@@ -41,6 +43,7 @@ use \core_privacy\local\request\transform;
 class provider implements
         \core_privacy\local\metadata\provider,
         \core_privacy\local\request\context_aware_provider,
+        \core_privacy\local\request\core_userlist_provider,
         \core_privacy\local\request\plugin\provider,
         \core_privacy\local\request\user_preference_provider {
 
@@ -75,6 +78,21 @@ 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_course::class)) {
+            return;
+        }
+
+        \core_completion\privacy\provider::add_course_completion_users_to_userlist($userlist);
+    }
+
     /**
      * Export all user data for the specified user, in the specified contexts.
      *
@@ -218,4 +236,19 @@ 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->contextlevel == CONTEXT_COURSE) {
+            // Delete course completion data.
+            \core_completion\privacy\provider::delete_completion_by_approved_userlist($userlist, $context->instanceid);
+        }
+    }
 }
index 3f4ecee..25f60f4 100644 (file)
@@ -50,6 +50,36 @@ class core_course_privacy_testcase extends \core_privacy\tests\provider_testcase
         $this->assertEquals($this->coursecontext->id, $contextlist->current()->id);
     }
 
+    /**
+     * Test fetching users within a context.
+     */
+    public function test_get_users_in_context() {
+        $this->resetAfterTest();
+        $component = 'core_course';
+
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+
+        // User1 and user2 complete course.
+        $this->create_course_completion();
+        $this->complete_course($user1);
+        $this->complete_course($user2);
+
+        // User3 is enrolled but has not completed course.
+        $this->getDataGenerator()->enrol_user($user3->id, $this->course->id, 'student');
+
+        // Ensure only users that have course completion are returned.
+        $userlist = new \core_privacy\local\request\userlist($this->coursecontext, $component);
+        \core_course\privacy\provider::get_users_in_context($userlist);
+        $expected = [$user1->id, $user2->id];
+        $actual = $userlist->get_userids();
+        sort($expected);
+        sort($actual);
+        $this->assertCount(2, $actual);
+        $this->assertEquals($expected, $actual);
+    }
+
     /**
      * Test that user data is exported.
      */
@@ -175,4 +205,42 @@ class core_course_privacy_testcase extends \core_privacy\tests\provider_testcase
         $records = $DB->get_records('course_completion_crit_compl');
         $this->assertCount(1, $records);
     }
+
+    /**
+     * Test deleting data within a context for an approved userlist.
+     */
+    public function test_delete_data_for_users() {
+        global $DB;
+        $this->resetAfterTest();
+
+        $component = 'core_course';
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+
+        $this->create_course_completion();
+        $this->complete_course($user1);
+        $this->complete_course($user2);
+        $this->complete_course($user3);
+
+        // Ensure records exist for all users before delete.
+        $records = $DB->get_records('course_modules_completion');
+        $this->assertCount(3, $records);
+        $records = $DB->get_records('course_completion_crit_compl');
+        $this->assertCount(3, $records);
+
+        $approveduserids = [$user1->id, $user3->id];
+        $approvedlist = new \core_privacy\local\request\approved_userlist($this->coursecontext, $component, $approveduserids);
+        \core_course\privacy\provider::delete_data_for_users($approvedlist);
+
+        // Ensure content is only deleted for approved userlist.
+        $records = $DB->get_records('course_modules_completion');
+        $this->assertCount(1, $records);
+        $record = reset($records);
+        $this->assertEquals($user2->id, $record->userid);
+        $records = $DB->get_records('course_completion_crit_compl');
+        $this->assertCount(1, $records);
+        $record = reset($records);
+        $this->assertEquals($user2->id, $record->userid);
+    }
 }