From bcc08d3b5e6921dbf688b8fa54d1a2d8962bdc0e Mon Sep 17 00:00:00 2001 From: Zig Tan Date: Mon, 16 Apr 2018 13:49:26 +0800 Subject: [PATCH] MDL-61979 tool_cohortroles: Implemented privacy providers --- .../tool/cohortroles/classes/privacy/provider.php | 200 ++++++++++++++++++++ .../tool/cohortroles/lang/en/tool_cohortroles.php | 8 + admin/tool/cohortroles/tests/privacy_test.php | 206 +++++++++++++++++++++ 3 files changed, 414 insertions(+) create mode 100644 admin/tool/cohortroles/classes/privacy/provider.php create mode 100644 admin/tool/cohortroles/tests/privacy_test.php diff --git a/admin/tool/cohortroles/classes/privacy/provider.php b/admin/tool/cohortroles/classes/privacy/provider.php new file mode 100644 index 00000000000..bc38e7c4ba7 --- /dev/null +++ b/admin/tool/cohortroles/classes/privacy/provider.php @@ -0,0 +1,200 @@ +. + +/** + * Privacy Subsystem implementation for tool_cohortroles. + * + * @package tool_cohortroles + * @copyright 2018 Zig Tan + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace tool_cohortroles\privacy; + +use core_privacy\local\metadata\collection; +use core_privacy\local\request\approved_contextlist; +use core_privacy\local\request\context; +use core_privacy\local\request\contextlist; +use core_privacy\local\request\transform; +use core_privacy\local\request\writer; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Privacy Subsystem for tool_cohortroles implementing metadata and plugin providers. + * + * @copyright 2018 Zig Tan + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements \core_privacy\local\metadata\provider, \core_privacy\local\request\plugin\provider { + + /** + * Returns meta data about this system. + * + * @param collection $collection The initialised collection to add items to. + * @return collection A listing of user data stored through this system. + */ + public static function get_metadata(collection $collection) : collection { + // The tool_cohortroles plugin utilises the mdl_tool_cohortroles table. + $collection->add_database_table( + 'tool_cohortroles', + [ + 'id' => 'privacy:metadata:tool_cohortroles:id', + 'cohortid' => 'privacy:metadata:tool_cohortroles:cohortid', + 'roleid' => 'privacy:metadata:tool_cohortroles:roleid', + 'userid' => 'privacy:metadata:tool_cohortroles:userid', + 'timecreated' => 'privacy:metadata:tool_cohortroles:timecreated', + 'timemodified' => 'privacy:metadata:tool_cohortroles:timemodified', + 'usermodified' => 'privacy:metadata:tool_cohortroles:usermodified' + ], + 'privacy:metadata:tool_cohortroles' + ); + + 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(); + + // Retrieve the User context associated with tool_cohortroles records. + $sql = "SELECT DISTINCT c.id + FROM {context} c + JOIN {tool_cohortroles} cr ON cr.userid = c.instanceid AND c.contextlevel = :contextuser + WHERE cr.userid = :userid"; + + $params = [ + 'contextuser' => CONTEXT_USER, + '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) { + global $DB; + + // If the user has tool_cohortroles data, then only the User context should be present so get the first context. + $contexts = $contextlist->get_contexts(); + if (count($contexts) == 0) { + return; + } + $context = reset($contexts); + + // Sanity check that context is at the User context level, then get the userid. + if ($context->contextlevel !== CONTEXT_USER) { + return; + } + $userid = $context->instanceid; + + // Retrieve the tool_cohortroles records created for the user. + $sql = 'SELECT cr.id as cohortroleid, + c.name as cohortname, + c.idnumber as cohortidnumber, + c.description as cohortdescription, + r.shortname as roleshortname, + cr.userid as userid, + cr.timecreated as timecreated, + cr.timemodified as timemodified + FROM {tool_cohortroles} cr + JOIN {cohort} c ON c.id = cr.cohortid + JOIN {role} r ON r.id = cr.roleid + WHERE cr.userid = :userid'; + + $params = [ + 'userid' => $userid + ]; + + $cohortroles = $DB->get_records_sql($sql, $params); + foreach ($cohortroles as $cohortrole) { + // The tool_cohortroles data export is organised in: + // {User Context}/Cohort roles management/{cohort name}/{role shortname}/data.json. + $subcontext = [ + get_string('pluginname', 'tool_cohortroles'), + $cohortrole->cohortname, + $cohortrole->roleshortname + ]; + + $data = (object) [ + 'cohortname' => $cohortrole->cohortname, + 'cohortidnumber' => $cohortrole->cohortidnumber, + 'cohortdescription' => $cohortrole->cohortdescription, + 'roleshortname' => $cohortrole->roleshortname, + 'userid' => transform::user($cohortrole->userid), + 'timecreated' => transform::datetime($cohortrole->timecreated), + 'timemodified' => transform::datetime($cohortrole->timemodified) + ]; + + writer::with_context($context)->export_data($subcontext, $data); + } + } + + /** + * Delete all data for all users in the specified context. + * + * @param context $context The specific context to delete data for. + */ + public static function delete_data_for_all_users_in_context(\context $context) { + global $DB; + + // Sanity check that context is at the User context level, then get the userid. + if ($context->contextlevel !== CONTEXT_USER) { + return; + } + $userid = $context->instanceid; + + // Delete the tool_cohortroles records created for the userid. + $DB->delete_records('tool_cohortroles', ['userid' => $userid]); + } + + /** + * 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) { + global $DB; + + // If the user has tool_cohortroles data, then only the User context should be present so get the first context. + $contexts = $contextlist->get_contexts(); + if (count($contexts) == 0) { + return; + } + $context = reset($contexts); + + // Sanity check that context is at the User context level, then get the userid. + if ($context->contextlevel !== CONTEXT_USER) { + return; + } + $userid = $context->instanceid; + + // Delete the tool_cohortroles records created for the userid. + $DB->delete_records('tool_cohortroles', ['userid' => $userid]); + } + +} diff --git a/admin/tool/cohortroles/lang/en/tool_cohortroles.php b/admin/tool/cohortroles/lang/en/tool_cohortroles.php index 08f00c95afd..a8afe835e84 100644 --- a/admin/tool/cohortroles/lang/en/tool_cohortroles.php +++ b/admin/tool/cohortroles/lang/en/tool_cohortroles.php @@ -42,3 +42,11 @@ $string['selectrole'] = 'Select role'; $string['selectusers'] = 'Select users to assign role'; $string['taskname'] = 'Sync cohort role assignments'; $string['thisuserroles'] = 'Roles assigned relative to this user'; +$string['privacy:metadata:tool_cohortroles'] = 'The Cohort roles management plugin stores user cohort role mappings.'; +$string['privacy:metadata:tool_cohortroles:id'] = 'The ID of the cohort role mapping record.'; +$string['privacy:metadata:tool_cohortroles:cohortid'] = 'The ID of the cohort.'; +$string['privacy:metadata:tool_cohortroles:roleid'] = 'The ID of the role.'; +$string['privacy:metadata:tool_cohortroles:userid'] = 'The ID of the user.'; +$string['privacy:metadata:tool_cohortroles:timecreated'] = 'The date/time of when the cohort role mapping was created.'; +$string['privacy:metadata:tool_cohortroles:timemodified'] = 'The date/time of when the cohort role mapping was modified.'; +$string['privacy:metadata:tool_cohortroles:usermodified'] = 'The ID of the user who last modified the cohort role mapping.'; diff --git a/admin/tool/cohortroles/tests/privacy_test.php b/admin/tool/cohortroles/tests/privacy_test.php new file mode 100644 index 00000000000..f118b74a099 --- /dev/null +++ b/admin/tool/cohortroles/tests/privacy_test.php @@ -0,0 +1,206 @@ +. + +/** + * Unit tests for the tool_cohortroles implementation of the privacy API. + * + * @package tool_cohortroles + * @category test + * @copyright 2018 Zig Tan + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); +global $CFG; + +use \core_privacy\local\request\writer; +use \core_privacy\local\request\approved_contextlist; +use \tool_cohortroles\api; +use \tool_cohortroles\privacy\provider; + +/** + * Unit tests for the tool_cohortroles implementation of the privacy API. + * + * @copyright 2018 Zig Tan + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_cohortroles_privacy_testcase extends \core_privacy\tests\provider_testcase { + + /** + * Overriding setUp() function to always reset after tests. + */ + public function setUp() { + $this->resetAfterTest(true); + } + + /** + * Test for provider::get_contexts_for_userid(). + */ + public function test_get_contexts_for_userid() { + global $DB; + + // Test setup. + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + $this->setAdminUser(); + + $nocohortroles = 3; + $this->setup_test_scenario_data($user->id, $nocohortroles); + + // Test the User's assigned cohortroles matches 3. + $cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]); + $this->assertCount($nocohortroles, $cohortroles); + + // Test the User's retrieved contextlist contains only one context. + $contextlist = provider::get_contexts_for_userid($user->id); + $contexts = $contextlist->get_contexts(); + $this->assertCount(1, $contexts); + + // Test the User's contexts equal the User's own context. + $context = reset($contexts); + $this->assertEquals(CONTEXT_USER, $context->contextlevel); + $this->assertEquals($user->id, $context->instanceid); + } + + /** + * Test for provider::export_user_data(). + */ + public function test_export_user_data() { + // Test setup. + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + $this->setAdminUser(); + + $nocohortroles = 3; + $this->setup_test_scenario_data($user->id, $nocohortroles); + + // Test the User's retrieved contextlist contains only one context. + $contextlist = provider::get_contexts_for_userid($user->id); + $contexts = $contextlist->get_contexts(); + $this->assertCount(1, $contexts); + + // Test the User's contexts equal the User's own context. + $context = reset($contexts); + $this->assertEquals(CONTEXT_USER, $context->contextlevel); + $this->assertEquals($user->id, $context->instanceid); + + // Retrieve the User's tool_cohortroles data. + $approvedcontextlist = new approved_contextlist($user, 'tool_cohortroles', $contextlist->get_contextids()); + provider::export_user_data($approvedcontextlist); + + // Test the tool_cohortroles data is exported at the User context level. + $writer = writer::with_context($context); + $this->assertTrue($writer->has_any_data()); + } + + /** + * Test for provider::delete_data_for_all_users_in_context(). + */ + public function test_delete_data_for_all_users_in_context() { + global $DB; + + // Test setup. + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + $this->setAdminUser(); + + $nocohortroles = 4; + $this->setup_test_scenario_data($user->id, $nocohortroles); + + // Test the User's assigned cohortroles matches 4. + $cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]); + $this->assertCount($nocohortroles, $cohortroles); + + // Test the User's retrieved contextlist contains only one context. + $contextlist = provider::get_contexts_for_userid($user->id); + $contexts = $contextlist->get_contexts(); + $this->assertCount(1, $contexts); + + // Test the User's contexts equal the User's own context. + $context = reset($contexts); + $this->assertEquals(CONTEXT_USER, $context->contextlevel); + $this->assertEquals($user->id, $context->instanceid); + + // Delete all the User's records in mdl_tool_cohortroles table by the specified User context. + provider::delete_data_for_all_users_in_context($context); + + // Test the cohort roles records in mdl_tool_cohortroles table is equals zero. + $cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]); + $this->assertCount(0, $cohortroles); + } + + /** + * Test for provider::delete_data_for_user(). + */ + public function test_delete_data_for_user() { + global $DB; + + // Test setup. + $user = $this->getDataGenerator()->create_user(); + $this->setUser($user); + $this->setAdminUser(); + + $nocohortroles = 4; + $this->setup_test_scenario_data($user->id, $nocohortroles); + + // Test the User's assigned cohortroles matches 4. + $cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]); + $this->assertCount($nocohortroles, $cohortroles); + + // Test the User's retrieved contextlist contains only one context. + $contextlist = provider::get_contexts_for_userid($user->id); + $contexts = $contextlist->get_contexts(); + $this->assertCount(1, $contexts); + + // Test the User's contexts equal the User's own context. + $context = reset($contexts); + $this->assertEquals(CONTEXT_USER, $context->contextlevel); + $this->assertEquals($user->id, $context->instanceid); + + // Delete all the User's records in mdl_tool_cohortroles table by the specified User approved context list. + $approvedcontextlist = new approved_contextlist($user, 'tool_cohortroles', $contextlist->get_contextids()); + provider::delete_data_for_user($approvedcontextlist); + + // Test the records in mdl_tool_cohortroles table is equals zero. + $cohortroles = $DB->get_records('tool_cohortroles', ['userid' => $user->id]); + $this->assertCount(0, $cohortroles); + } + + /** + * Helper function to setup tool_cohortroles records for testing a specific user. + * + * @param int $userid The ID of the user used for testing. + * @param int $nocohortroles The number of tool_cohortroles to create for the user. + * @throws \core_competency\invalid_persistent_exception + * @throws coding_exception + */ + protected function setup_test_scenario_data($userid, $nocohortroles) { + $roleid = create_role('Sausage Roll', 'sausageroll', 'mmmm'); + + for ($c = 0; $c < $nocohortroles; $c++) { + $cohort = $this->getDataGenerator()->create_cohort(); + + $params = (object)array( + 'userid' => $userid, + 'roleid' => $roleid, + 'cohortid' => $cohort->id + ); + + api::create_cohort_role_assignment($params); + } + } + +} -- 2.11.4.GIT