MDL-62357 enrol_cohort: Add privacy implementation for enrol_cohort
authorcescobedo <carlos.escobedo@gmail.com>
Mon, 14 May 2018 08:49:16 +0000 (10:49 +0200)
committercescobedo <carlos.escobedo@gmail.com>
Mon, 14 May 2018 08:49:16 +0000 (10:49 +0200)
enrol/cohort/classes/privacy/provider.php
enrol/cohort/lang/en/enrol_cohort.php
enrol/cohort/tests/privacy_test.php [new file with mode: 0644]

index 7f0b932..9380cb8 100644 (file)
  */
 namespace enrol_cohort\privacy;
 defined('MOODLE_INTERNAL') || die();
  */
 namespace enrol_cohort\privacy;
 defined('MOODLE_INTERNAL') || die();
+use \core_privacy\local\metadata\collection;
+use \core_privacy\local\request\contextlist;
+use \core_privacy\local\request\approved_contextlist;
+
 /**
 /**
- * Privacy Subsystem for enrol_cohort implementing null_provider.
+ * Privacy provider for enrol_cohort.
  *
  * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
  *
  * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class provider implements \core_privacy\local\metadata\null_provider {
+class provider implements
+    \core_privacy\local\metadata\provider,
+    \core_privacy\local\request\plugin\provider {
     /**
     /**
-     * Get the language string identifier with the component's language
-     * file to explain why this plugin stores no data.
+     * Returns meta data about this system.
      *
      *
-     * @return  string
+     * @param   collection     $collection The initialised item collection to add items to.
+     * @return  collection     A listing of user data stored through this system.
      */
      */
-    public static function get_reason() : string {
-        return 'privacy:metadata';
+    public static function get_metadata(collection $collection) : collection {
+
+        $collection->add_subsystem_link('core_group', [], 'privacy:metadata:core_group');
+        return $collection;
+    }
+    /**
+     * Get the list of contexts that contain user information for the specified user.
+     *
+     * @param int $userid The user to search.
+     * @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
+     */
+    public static function get_contexts_for_userid(int $userid) : contextlist {
+        $contextlist = new contextlist();
+
+        $sql = "SELECT ctx.id
+                  FROM {groups_members} gm
+                  JOIN {groups} g ON gm.groupid = g.id
+                  JOIN {context} ctx ON g.courseid = ctx.instanceid AND ctx.contextlevel = :contextlevel
+                 WHERE gm.userid = :userid
+                   AND gm.component = 'enrol_cohort'";
+
+        $params = [
+            'contextlevel' => CONTEXT_COURSE,
+            'userid'        => $userid
+        ];
+
+        $contextlist->add_from_sql($sql, $params);
+
+        return $contextlist;
+    }
+    /**
+     * Export all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts to export information for.
+     */
+    public static function export_user_data(approved_contextlist $contextlist) {
+        if (empty($contextlist)) {
+            return;
+        }
+        foreach ($contextlist as $context) {
+            if ($context->contextlevel == CONTEXT_COURSE) {
+                \core_group\privacy\provider::export_groups(
+                    $context,
+                    'enrol_cohort',
+                    [get_string('pluginname', 'enrol_cohort')]
+                );
+            }
+        }
+    }
+
+    /**
+     * Delete all use data which matches the specified deletion_criteria.
+     *
+     * @param context $context A user context.
+     */
+    public static function delete_data_for_all_users_in_context(\context $context) {
+        if (empty($context)) {
+            return;
+        }
+        if ($context->contextlevel == CONTEXT_COURSE) {
+            // Delete all the associated groups.
+            \core_group\privacy\provider::delete_groups_for_all_users($context, 'enrol_cohort');
+        }
+    }
+    /**
+     * Delete all user data for the specified user, in the specified contexts.
+     *
+     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
+     */
+    public static function delete_data_for_user(approved_contextlist $contextlist) {
+        if (empty($contextlist->count())) {
+            return;
+        }
+        \core_group\privacy\provider::delete_groups_for_user($contextlist, 'enrol_cohort');
     }
 }
\ No newline at end of file
     }
 }
\ No newline at end of file
index ffc0905..86e0426 100644 (file)
@@ -33,4 +33,4 @@ $string['pluginname'] = 'Cohort sync';
 $string['pluginname_desc'] = 'Cohort enrolment plugin synchronises cohort members with course participants.';
 $string['status'] = 'Active';
 $string['creategroup'] = 'Create new group';
 $string['pluginname_desc'] = 'Cohort enrolment plugin synchronises cohort members with course participants.';
 $string['status'] = 'Active';
 $string['creategroup'] = 'Create new group';
-$string['privacy:metadata'] = 'The Cohort sync enrolment plugin does not store any personal data.';
+$string['privacy:metadata:core_group'] = 'Enrol cohort plugin can create a new group or use an existing group to add all the members of the cohort.';
diff --git a/enrol/cohort/tests/privacy_test.php b/enrol/cohort/tests/privacy_test.php
new file mode 100644 (file)
index 0000000..abb38b0
--- /dev/null
@@ -0,0 +1,252 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+/**
+ * Base class for unit tests for enrol_cohort.
+ *
+ * @package    enrol_cohort
+ * @category   test
+ * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+defined('MOODLE_INTERNAL') || die();
+use \core_privacy\local\request\writer;
+use \core_privacy\local\request\approved_contextlist;
+use \enrol_cohort\privacy\provider;
+/**
+ * Unit tests for the enrol_cohort implementation of the privacy API.
+ *
+ * @copyright  2018 Carlos Escobedo <carlos@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class enrol_cohort_privacy_testcase extends \core_privacy\tests\provider_testcase {
+    /**
+     * Test getting the context for the user ID related to this plugin.
+     */
+    public function test_get_contexts_for_userid() {
+        global $DB;
+
+        $this->resetAfterTest();
+        $trace = new null_progress_trace();
+
+        $cohortplugin = enrol_get_plugin('cohort');
+        $user1 = $this->getDataGenerator()->create_user();
+        $cat1 = $this->getDataGenerator()->create_category();
+        $course1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id));
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $cohort1 = $this->getDataGenerator()->create_cohort(
+            array('contextid' => context_coursecat::instance($cat1->id)->id));
+        $cohortplugin->add_instance($course1, array(
+            'customint1' => $cohort1->id,
+            'roleid' => $studentrole->id,
+            'customint2' => $group1->id)
+        );
+
+        cohort_add_member($cohort1->id, $user1->id);
+        enrol_cohort_sync($trace, $course1->id);
+        // Check if user1 is enrolled into course1 in group 1.
+        $this->assertEquals(1, $DB->count_records('role_assignments', array()));
+        $this->assertTrue($DB->record_exists('groups_members', array(
+            'groupid' => $group1->id,
+            'userid' => $user1->id,
+            'component' => 'enrol_cohort')
+        ));
+        // Check context course fro provider to user1.
+        $context = \context_course::instance($course1->id);
+        $contextlist = provider::get_contexts_for_userid($user1->id);
+        $this->assertEquals($context->id, $contextlist->current()->id);
+    }
+
+    /**
+     * Test that user data is exported correctly.
+     */
+    public function test_export_user_data() {
+        global $DB;
+
+        $this->resetAfterTest();
+        $trace = new null_progress_trace();
+
+        $cohortplugin = enrol_get_plugin('cohort');
+        $user1 = $this->getDataGenerator()->create_user();
+        $cat1 = $this->getDataGenerator()->create_category();
+        $course1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id));
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $cohort1 = $this->getDataGenerator()->create_cohort(
+            array('contextid' => context_coursecat::instance($cat1->id)->id));
+        $cohortplugin->add_instance($course1, array(
+            'customint1' => $cohort1->id,
+            'roleid' => $studentrole->id,
+            'customint2' => $group1->id)
+        );
+
+        cohort_add_member($cohort1->id, $user1->id);
+        enrol_cohort_sync($trace, $course1->id);
+        // Check if user1 is enrolled into course1 in group 1.
+        $this->assertEquals(1, $DB->count_records('role_assignments', array()));
+        $this->assertTrue($DB->record_exists('groups_members', array(
+            'groupid' => $group1->id,
+            'userid' => $user1->id,
+            'component' => 'enrol_cohort')
+        ));
+
+        $this->setUser($user1);
+        $contextlist = provider::get_contexts_for_userid($user1->id);
+        $approvedcontextlist = new approved_contextlist($user1, 'enrol_cohort', $contextlist->get_contextids());
+        provider::export_user_data($approvedcontextlist);
+        foreach ($contextlist as $context) {
+            $writer = writer::with_context($context);
+            $data = $writer->get_data([
+                get_string('pluginname', 'enrol_cohort'),
+                get_string('groups', 'core_group')
+            ]);
+            $this->assertTrue($writer->has_any_data());
+            if ($context->contextlevel == CONTEXT_COURSE) {
+                $exportedgroups = $data->groups;
+                // User1 only belongs to group1 via enrol_cohort.
+                $this->assertCount(1, $exportedgroups);
+                $exportedgroup = reset($exportedgroups);
+                $this->assertEquals($group1->name, $exportedgroup->name);
+            }
+        }
+    }
+    /**
+     * Test for provider::delete_data_for_all_users_in_context().
+     */
+    public function test_delete_data_for_all_users_in_context() {
+        global $DB;
+
+        $this->resetAfterTest();
+        $trace = new null_progress_trace();
+
+        $cohortplugin = enrol_get_plugin('cohort');
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $cat1 = $this->getDataGenerator()->create_category();
+        $course1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id));
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $cohort1 = $this->getDataGenerator()->create_cohort(
+            array('contextid' => context_coursecat::instance($cat1->id)->id));
+        $cohortplugin->add_instance($course1, array(
+            'customint1' => $cohort1->id,
+            'roleid' => $studentrole->id,
+            'customint2' => $group1->id)
+        );
+
+        cohort_add_member($cohort1->id, $user1->id);
+        cohort_add_member($cohort1->id, $user2->id);
+        cohort_add_member($cohort1->id, $user3->id);
+        enrol_cohort_sync($trace, $course1->id);
+        $this->assertEquals(
+                3,
+                $DB->count_records_sql("SELECT COUNT(gm.id)
+                                      FROM {groups_members} gm
+                                      JOIN {groups} g ON gm.groupid = g.id
+                                     WHERE g.courseid = ?", [$course1->id])
+        );
+
+        $coursecontext1 = context_course::instance($course1->id);
+        provider::delete_data_for_all_users_in_context($coursecontext1);
+        $this->assertEquals(
+            0,
+            $DB->count_records_sql("SELECT COUNT(gm.id)
+                                      FROM {groups_members} gm
+                                      JOIN {groups} g ON gm.groupid = g.id
+                                     WHERE g.courseid = ?", [$course1->id])
+        );
+    }
+    /**
+     * Test for provider::delete_data_for_user().
+     */
+    public function test_delete_data_for_user() {
+        global $DB;
+
+        $this->resetAfterTest();
+        $trace = new null_progress_trace();
+
+        $cohortplugin = enrol_get_plugin('cohort');
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $cat1 = $this->getDataGenerator()->create_category();
+        $course1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id));
+        $course2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id));
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course2->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+        $cohort1 = $this->getDataGenerator()->create_cohort(
+            array('contextid' => context_coursecat::instance($cat1->id)->id));
+        $cohortplugin->add_instance($course1, array(
+            'customint1' => $cohort1->id,
+            'roleid' => $studentrole->id,
+            'customint2' => $group1->id)
+        );
+        $cohortplugin->add_instance($course2, array(
+            'customint1' => $cohort1->id,
+            'roleid' => $studentrole->id,
+            'customint2' => $group2->id)
+        );
+
+        $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
+        $this->getDataGenerator()->enrol_user($user3->id, $course1->id);
+        $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
+        $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user3->id));
+
+        cohort_add_member($cohort1->id, $user1->id);
+        enrol_cohort_sync($trace, $course1->id);
+
+        $this->assertEquals(
+                3,
+                $DB->count_records_sql("SELECT COUNT(gm.id)
+                                          FROM {groups_members} gm
+                                          JOIN {groups} g ON gm.groupid = g.id
+                                         WHERE g.courseid = ?", [$course1->id])
+        );
+
+        $this->assertEquals(
+                1,
+                $DB->count_records_sql("SELECT COUNT(gm.id)
+                                          FROM {groups_members} gm
+                                          JOIN {groups} g ON gm.groupid = g.id
+                                         WHERE g.courseid = ?", [$course2->id])
+        );
+
+        $this->setUser($user1);
+        $coursecontext1 = context_course::instance($course1->id);
+        $coursecontext2 = context_course::instance($course2->id);
+        $approvedcontextlist = new \core_privacy\tests\request\approved_contextlist($user1, 'enrol_cohort',
+                [$coursecontext1->id, $coursecontext2->id]);
+        provider::delete_data_for_user($approvedcontextlist);
+        // Check we have 2 users in groups because we are deleted user1.
+        $this->assertEquals(
+                2,
+                $DB->count_records_sql("SELECT COUNT(gm.id)
+                                          FROM {groups_members} gm
+                                          JOIN {groups} g ON gm.groupid = g.id
+                                         WHERE g.courseid = ?", [$course1->id])
+        );
+        // Check we have not users in groups.
+        $this->assertEquals(
+                0,
+                $DB->count_records_sql("SELECT COUNT(gm.id)
+                                          FROM {groups_members} gm
+                                          JOIN {groups} g ON gm.groupid = g.id
+                                         WHERE g.courseid = ?", [$course2->id])
+        );
+    }
+}
\ No newline at end of file