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

index 04db729..31fd319 100644 (file)
  */
 namespace enrol_meta\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_meta implementing null_provider.
+ * Privacy provider for enrol_meta.
  *
  * @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_meta'";
+
+        $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_meta',
+                    [get_string('pluginname', 'enrol_meta')]
+                );
+            }
+        }
+    }
+
+    /**
+     * 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_meta');
+        }
+    }
+    /**
+     * 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_meta');
     }
 }
\ No newline at end of file
index 92989d1..205a35f 100644 (file)
@@ -38,4 +38,4 @@ $string['pluginname'] = 'Course meta link';
 $string['pluginname_desc'] = 'Course meta link enrolment plugin synchronises enrolments and roles in two different courses.';
 $string['syncall'] = 'Synchronise all enrolled users';
 $string['syncall_desc'] = 'If enabled all enrolled users are synchronised even if they have no role in parent course, if disabled only users that have at least one synchronised role are enrolled in child course.';
-$string['privacy:metadata'] = 'The Course meta link enrolment plugin does not store any personal data.';
+$string['privacy:metadata:core_group'] = 'Enrol meta plugin can create a new group or use an existing group to add all the participants of the course linked.';
diff --git a/enrol/meta/tests/privacy_test.php b/enrol/meta/tests/privacy_test.php
new file mode 100644 (file)
index 0000000..4e1966d
--- /dev/null
@@ -0,0 +1,198 @@
+<?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_meta.
+ *
+ * @package    enrol_meta
+ * @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_meta\privacy\provider;
+/**
+ * Unit tests for the enrol_meta 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_meta_privacy_testcase extends \core_privacy\tests\provider_testcase {
+    /**
+     * Enable enrol_meta plugin.
+     */
+    protected function enable_plugin() {
+        $enabled = enrol_get_plugins(true);
+        $enabled['meta'] = true;
+        $enabled = array_keys($enabled);
+        set_config('enrol_plugins_enabled', implode(',', $enabled));
+    }
+    /**
+     * Test getting the context for the user ID related to this plugin.
+     */
+    public function test_get_contexts_for_userid() {
+        global $DB;
+
+        $this->resetAfterTest();
+        $metaplugin = enrol_get_plugin('meta');
+        $user1 = $this->getDataGenerator()->create_user();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+
+        $this->enable_plugin();
+        $metaplugin->add_instance($course1, array('customint1' => $course2->id, 'customint2' => $group1->id));
+        $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $studentrole->id);
+        // Check if user1 is enrolled into course1 in group 1.
+        $this->assertTrue(groups_is_member($group1->id, $user1->id));
+        $this->assertTrue($DB->record_exists('groups_members',
+            array(
+                'groupid' => $group1->id,
+                'userid' => $user1->id,
+                'component' => 'enrol_meta'
+            )
+        ));
+        // 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();
+        $metaplugin = enrol_get_plugin('meta');
+        $user1 = $this->getDataGenerator()->create_user();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+
+        $this->enable_plugin();
+        $metaplugin->add_instance($course1, array('customint1' => $course2->id, 'customint2' => $group1->id));
+        $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $studentrole->id);
+
+        $this->setUser($user1);
+        $contextlist = provider::get_contexts_for_userid($user1->id);
+        $approvedcontextlist = new approved_contextlist($user1, 'enrol_meta', $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_meta'),
+                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_meta.
+                $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();
+        $metaplugin = enrol_get_plugin('meta');
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+
+        $this->enable_plugin();
+        $metaplugin->add_instance($course1, array('customint1' => $course2->id, 'customint2' => $group1->id));
+        $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $studentrole->id);
+        $this->getDataGenerator()->enrol_user($user2->id, $course2->id, $studentrole->id);
+        $this->getDataGenerator()->enrol_user($user3->id, $course2->id, $studentrole->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();
+        $metaplugin = enrol_get_plugin('meta');
+        $user1 = $this->getDataGenerator()->create_user();
+        $user2 = $this->getDataGenerator()->create_user();
+        $user3 = $this->getDataGenerator()->create_user();
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
+        $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+
+        $this->enable_plugin();
+        $metaplugin->add_instance($course1, array('customint1' => $course2->id, 'customint2' => $group1->id));
+        $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $studentrole->id);
+        $this->getDataGenerator()->enrol_user($user2->id, $course2->id, $studentrole->id);
+        $this->getDataGenerator()->enrol_user($user3->id, $course2->id, $studentrole->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->setUser($user1);
+        $coursecontext1 = context_course::instance($course1->id);
+        $coursecontext2 = context_course::instance($course2->id);
+        $approvedcontextlist = new \core_privacy\tests\request\approved_contextlist($user1, 'enrol_meta',
+                [$coursecontext1->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])
+        );
+    }
+}
\ No newline at end of file