From b03e9322bfc940f9d90ef00fa4bb0f8f67955f3f Mon Sep 17 00:00:00 2001 From: Michael Hawkins Date: Fri, 26 Oct 2018 11:21:41 +0800 Subject: [PATCH 1/2] MDL-63764 core_competency: Support bulk user delete course competencies This issue is a part of the MDL-62560 Epic. Also made user IDs optional, so user course competencies can be deleted by course ID only. --- competency/classes/privacy/provider.php | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/competency/classes/privacy/provider.php b/competency/classes/privacy/provider.php index 39ff45c5048..dd0191d15ff 100644 --- a/competency/classes/privacy/provider.php +++ b/competency/classes/privacy/provider.php @@ -478,8 +478,7 @@ class provider implements break; case CONTEXT_COURSE: - $courseid = $context->instanceid; - $DB->delete_records(user_competency_course::TABLE, ['courseid' => $courseid]); + static::delete_user_competencies_in_course($context->instanceid); break; } } @@ -511,7 +510,7 @@ class provider implements break; case CONTEXT_COURSE: - static::delete_user_competencies_in_course($userid, $context->instanceid); + static::delete_user_competencies_in_course($context->instanceid, [$userid]); break; } } @@ -602,15 +601,26 @@ class provider implements } /** - * Delete the record of competencies for a user in a course. + * Delete the record of competencies for user(s) in a course. * - * @param int $userid The user ID. * @param int $courseid The course ID. + * @param int[] $userids The user IDs, if deleting for specific user(s). * @return void */ - protected static function delete_user_competencies_in_course($userid, $courseid) { + protected static function delete_user_competencies_in_course($courseid, $userids = []) { global $DB; - $DB->delete_records(user_competency_course::TABLE, ['userid' => $userid, 'courseid' => $courseid]); + + $params = ['courseid' => $courseid]; + $where = "courseid = :courseid"; + + if (!empty($userids)) { + list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); + $params = $params + $inparams; + + $where .= " AND userid {$insql}"; + } + + $DB->delete_records_select(user_competency_course::TABLE, $where, $params); } /** From cabea2fc045a104ff0ae8030227a2ece8a7bb0d5 Mon Sep 17 00:00:00 2001 From: Michael Hawkins Date: Thu, 25 Oct 2018 17:08:29 +0800 Subject: [PATCH 2/2] MDL-63764 core_competency: Add support for removal of context users This issue is a part of the MDL-62560 Epic. --- competency/classes/privacy/provider.php | 194 ++++++++ competency/tests/privacy_test.php | 599 ++++++++++++++++++++++++ 2 files changed, 793 insertions(+) diff --git a/competency/classes/privacy/provider.php b/competency/classes/privacy/provider.php index dd0191d15ff..2e12b20e645 100644 --- a/competency/classes/privacy/provider.php +++ b/competency/classes/privacy/provider.php @@ -53,9 +53,11 @@ use core_competency\user_evidence; use core_competency\user_evidence_competency; use core_competency\external\performance_helper; use core_privacy\local\metadata\collection; +use core_privacy\local\request\approved_userlist; use core_privacy\local\request\contextlist; use core_privacy\local\request\approved_contextlist; use core_privacy\local\request\transform; +use core_privacy\local\request\userlist; use core_privacy\local\request\writer; /** @@ -68,6 +70,7 @@ use core_privacy\local\request\writer; */ class provider implements \core_privacy\local\metadata\provider, + \core_privacy\local\request\core_userlist_provider, \core_privacy\local\request\subsystem\provider { /** @@ -418,6 +421,166 @@ 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(); + $params = ['contextid' => $context->id]; + + // Add users who have modified the frameworks and related data in the context. + $sql = " + SELECT cf.usermodified + FROM {" . competency_framework::TABLE . "} cf + WHERE cf.contextid = :contextid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT c.usermodified + FROM {" . competency_framework::TABLE . "} cf + JOIN {" . competency::TABLE . "} c + ON c.competencyframeworkid = cf.id + WHERE cf.contextid = :contextid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT cr.usermodified + FROM {" . competency_framework::TABLE . "} cf + JOIN {" . competency::TABLE . "} c + ON c.competencyframeworkid = cf.id + JOIN {" . related_competency::TABLE . "} cr + ON cr.competencyid = c.id + WHERE cf.contextid = :contextid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + // Add users who have modified the templates and related data in the context. + $sql = " + SELECT tpl.usermodified + FROM {" . template::TABLE . "} tpl + WHERE tpl.contextid = :contextid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT tch.usermodified + FROM {" . template::TABLE . "} tpl + JOIN {" . template_cohort::TABLE . "} tch + ON tch.templateid = tpl.id + WHERE tpl.contextid = :contextid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT tc.usermodified + FROM {" . template::TABLE . "} tpl + JOIN {" . template_competency::TABLE . "} tc + ON tc.templateid = tpl.id + WHERE tpl.contextid = :contextid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + // Add users if userlist is in course context. + if (is_a($context, \context_course::class)) { + $params = ['courseid' => $context->instanceid]; + + $sql = " + SELECT cc.usermodified + FROM {" . course_competency::TABLE . "} cc + WHERE cc.courseid = :courseid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT ccs.usermodified + FROM {" . course_competency_settings::TABLE . "} ccs + WHERE ccs.courseid = :courseid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT ucc.userid, ucc.usermodified + FROM {" . user_competency_course::TABLE . "} ucc + WHERE ucc.courseid = :courseid"; + $userlist->add_from_sql('userid', $sql, $params); + $userlist->add_from_sql('usermodified', $sql, $params); + + } else if (is_a($context, \context_module::class)) { + // Add users if userlist is in module context. + $params = ['moduleid' => $context->instanceid]; + + $sql = " + SELECT cmc.usermodified + FROM {" . course_module_competency::TABLE . "} cmc + WHERE cmc.cmid = :moduleid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + } else if (is_a($context, \context_user::class)) { + $params = ['userid' => $context->instanceid]; + + // Add users through plan related data. + $sql = " + SELECT p.userid, p.usermodified, p.reviewerid + FROM {" . plan::TABLE . "} p + WHERE p.userid = :userid"; + $userlist->add_from_sql('userid', $sql, $params); + $userlist->add_from_sql('usermodified', $sql, $params); + $userlist->add_from_sql('reviewerid', $sql, $params); + + $sql = " + SELECT pc.usermodified + FROM {" . plan::TABLE . "} p + JOIN {" . plan_competency::TABLE . "} pc + ON pc.planid = p.id + WHERE p.userid = :userid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT upc.usermodified + FROM {" . user_competency_plan::TABLE . "} upc + WHERE upc.userid = :userid"; + $userlist->add_from_sql('usermodified', $sql, $params); + + // Add users through competency data. + $sql = " + SELECT uc.userid, uc.usermodified, uc.reviewerid + FROM {" . user_competency::TABLE . "} uc + WHERE uc.userid = :userid"; + $userlist->add_from_sql('userid', $sql, $params); + $userlist->add_from_sql('usermodified', $sql, $params); + $userlist->add_from_sql('reviewerid', $sql, $params); + + $sql = " + SELECT e.usermodified, e.actionuserid + FROM {" . user_competency::TABLE . "} uc + JOIN {" . evidence::TABLE . "} e + ON e.usercompetencyid = uc.id + WHERE uc.userid = :userid"; + $userlist->add_from_sql('usermodified', $sql, $params); + $userlist->add_from_sql('actionuserid', $sql, $params); + + // Add users through evidence data. + $sql = " + SELECT ue.userid, ue.usermodified + FROM {" . user_evidence::TABLE . "} ue + WHERE ue.userid = :userid"; + $userlist->add_from_sql('userid', $sql, $params); + $userlist->add_from_sql('usermodified', $sql, $params); + + $sql = " + SELECT ue.usermodified + FROM {" . user_evidence::TABLE . "} ue + JOIN {" . user_evidence_competency::TABLE . "} uec + ON uec.userevidenceid = ue.id + WHERE ue.userid = :userid"; + $userlist->add_from_sql('usermodified', $sql, $params); + } + + // Add users who commented in the context. + // Note: Comment component must be competency and not core_competency. + \core_comment\privacy\provider::get_users_in_context_from_sql( + $userlist, 'com', 'competency', 'plan', $context->id); + + \core_comment\privacy\provider::get_users_in_context_from_sql( + $userlist, 'com', 'competency', 'user_competency', $context->id); + } + /** * Export all user data for the specified user, in the specified contexts. * @@ -516,6 +679,37 @@ class provider implements } } + /** + * Delete multiple users within a single context. + * + * Here we only delete the private data of users, not whether they modified, are reviewing, + * or are associated with the record on at a second level. Only data directly linked to the + * user will be affected. + * + * @param approved_userlist $userlist The approved context and user information to delete information for. + */ + public static function delete_data_for_users(approved_userlist $userlist) { + $context = $userlist->get_context(); + $userids = $userlist->get_userids(); + + switch ($context->contextlevel) { + case CONTEXT_USER: + // Only delete the user's information when their context is being deleted. + // We do not take any action on other user's contexts because we don't own the data there. + if (in_array($context->instanceid, $userids)) { + static::delete_user_evidence_of_prior_learning($context->instanceid); + static::delete_user_plans($context->instanceid); + static::delete_user_competencies($context->instanceid); + } + + break; + + case CONTEXT_COURSE: + static::delete_user_competencies_in_course($context->instanceid, $userids); + break; + } + } + /** * Delete evidence of prior learning. * diff --git a/competency/tests/privacy_test.php b/competency/tests/privacy_test.php index 2ac2247f786..05c463e42a4 100644 --- a/competency/tests/privacy_test.php +++ b/competency/tests/privacy_test.php @@ -30,7 +30,9 @@ global $CFG, $DB; use core_privacy\tests\provider_testcase; use core_privacy\local\request\contextlist; use core_privacy\local\request\approved_contextlist; +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; use core_competency\api; use core_competency\privacy\provider; @@ -111,6 +113,62 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist($contextlist, [$sysctx, $cat1ctx]); } + public function test_get_users_in_context_with_usermodified_for_framework() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + + $cat1 = $dg->create_category(); + $cat2 = $dg->create_category(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $u3 = $dg->create_user(); + $u4 = $dg->create_user(); + + $sysctx = context_system::instance(); + $cat1ctx = context_coursecat::instance($cat1->id); + $cat2ctx = context_coursecat::instance($cat2->id); + + // Add frameworks. + $this->setUser($u1); + $f1 = $ccg->create_framework(); + $f2 = $ccg->create_framework(['contextid' => $cat1ctx->id]); + + $this->setUser($u2); + $ccg->create_framework(['contextid' => $cat2ctx->id]); + + // Add competencies. + $this->setUser($u3); + $c1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]); + $c2 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]); + $c3 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]); + $c4 = $ccg->create_competency(['competencyframeworkid' => $f2->get('id')]); + $c5 = $ccg->create_competency(['competencyframeworkid' => $f2->get('id')]); + $c6 = $ccg->create_competency(['competencyframeworkid' => $f2->get('id')]); + + // Add related competencies. + $this->setUser($u4); + $cr = $ccg->create_related_competency(['competencyid' => $c1->get('id'), 'relatedcompetencyid' => $c2->get('id')]); + $cr = $ccg->create_related_competency(['competencyid' => $c4->get('id'), 'relatedcompetencyid' => $c5->get('id')]); + + // Test correct users appear in each context. + $component = 'core_competency'; + + $userlist = new userlist($sysctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u1->id, $u3->id, $u4->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + + $userlist = new userlist($cat1ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u1->id, $u3->id, $u4->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + + $userlist = new userlist($cat2ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u2->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + } + public function test_get_contexts_for_userid_with_usermodified_for_template() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -174,6 +232,69 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist($contextlist, [$sysctx, $cat1ctx]); } + public function test_get_users_in_context_with_usermodified_for_template() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + + $cat1 = $dg->create_category(); + $cat2 = $dg->create_category(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $u3 = $dg->create_user(); + $u4 = $dg->create_user(); + $cohort = $dg->create_cohort(); + + $sysctx = context_system::instance(); + $cat1ctx = context_coursecat::instance($cat1->id); + $cat2ctx = context_coursecat::instance($cat2->id); + + $f1 = $ccg->create_framework(); + $f2 = $ccg->create_framework(['contextid' => $cat1ctx->id]); + $f3 = $ccg->create_framework(['contextid' => $cat2ctx->id]); + $cs = []; + + foreach ([$f1, $f2, $f3] as $f) { + $cs[$f->get('id')] = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + } + + // Create template context. + $this->setUser($u1); + $t1 = $ccg->create_template(); + $t2 = $ccg->create_template(['contextid' => $cat1ctx->id]); + + // Add to category context. + $this->setUser($u2); + $ccg->create_template(['contextid' => $cat2ctx->id]); + + // Create template competencies. + $this->setUser($u3); + $c1 = $ccg->create_template_competency(['competencyid' => $cs[$f1->get('id')]->get('id'), 'templateid' => $t1->get('id')]); + $c4 = $ccg->create_template_competency(['competencyid' => $cs[$f2->get('id')]->get('id'), 'templateid' => $t2->get('id')]); + + // Create template cohorts. + $this->setUser($u4); + $c1 = $ccg->create_template_cohort(['cohortid' => $cohort->id, 'templateid' => $t1->get('id')]); + $c4 = $ccg->create_template_cohort(['cohortid' => $cohort->id, 'templateid' => $t2->get('id')]); + + // Test correct users appear in each context. + $component = 'core_competency'; + + $userlist = new userlist($sysctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u1->id, $u3->id, $u4->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + + $userlist = new userlist($cat1ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u1->id, $u3->id, $u4->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + + $userlist = new userlist($cat2ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u2->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + } + public function test_get_contexts_for_userid_with_usermodified_for_course() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -225,6 +346,51 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist(provider::get_contexts_for_userid($u4->id), [$c2ctx]); } + public function test_get_users_in_context_with_usermodified_for_course() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + $c1 = $dg->create_course(); + $c2 = $dg->create_course(); + $u0 = $dg->create_user(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $u3 = $dg->create_user(); + $u4 = $dg->create_user(); + $c1ctx = context_course::instance($c1->id); + $c2ctx = context_course::instance($c2->id); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + $comp2 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + $this->setUser($u1); + $ccg->create_course_competency(['courseid' => $c1->id, 'competencyid' => $comp1->get('id')]); + + $this->setUser($u2); + $ccg->create_course_competency(['courseid' => $c2->id, 'competencyid' => $comp2->get('id')]); + $ccg->create_course_competency(['courseid' => $c1->id, 'competencyid' => $comp2->get('id')]); + + $this->setUser($u3); + $ccs = new \core_competency\course_competency_settings(null, (object) ['courseid' => $c1->id]); + $ccs->create(); + + $this->setUser($u4); + $ccg->create_user_competency_course(['courseid' => $c2->id, 'userid' => $u0->id, 'competencyid' => $comp1->get('id')]); + + // Test correct users appear in each context. + $component = 'core_competency'; + + $userlist = new userlist($c1ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u1->id, $u2->id, $u3->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + + $userlist = new userlist($c2ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u0->id, $u2->id, $u4->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + } + public function test_get_contexts_for_userid_with_usermodified_for_module() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -258,6 +424,42 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist(provider::get_contexts_for_userid($u2->id), [$m1ctx, $m2ctx]); } + public function test_get_users_in_context_with_usermodified_for_module() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + $c1 = $dg->create_course(); + $m1 = $dg->create_module('choice', ['course' => $c1]); + $m2 = $dg->create_module('choice', ['course' => $c1]); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $m1ctx = context_module::instance($m1->cmid); + $m2ctx = context_module::instance($m2->cmid); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + $comp2 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + $this->setUser($u1); + $ccg->create_course_module_competency(['cmid' => $m1->cmid, 'competencyid' => $comp1->get('id')]); + + $this->setUser($u2); + $ccg->create_course_module_competency(['cmid' => $m2->cmid, 'competencyid' => $comp2->get('id')]); + $ccg->create_course_module_competency(['cmid' => $m1->cmid, 'competencyid' => $comp2->get('id')]); + + // Test correct users appear in each context. + $component = 'core_competency'; + + $userlist = new userlist($m1ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u1->id, $u2->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + + $userlist = new userlist($m2ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u2->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + } + public function test_get_contexts_for_userid_with_usermodified_for_plan() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -294,6 +496,38 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist(provider::get_contexts_for_userid($u3->id), [$u0ctx]); } + public function test_get_users_in_context_with_usermodified_for_plan() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + $u0 = $dg->create_user(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $u3 = $dg->create_user(); + $u0ctx = context_user::instance($u0->id); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + $comp2 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + $this->setUser($u1); + $plan = $ccg->create_plan(['userid' => $u0->id]); + + $this->setUser($u2); + $ccg->create_plan_competency(['planid' => $plan->get('id'), 'competencyid' => $comp1->get('id')]); + + $this->setUser($u3); + $ccg->create_user_competency_plan(['planid' => $plan->get('id'), 'competencyid' => $comp1->get('id'), + 'userid' => $u0->id]); + + // Test correct users appear in the context. + $component = 'core_competency'; + + $userlist = new userlist($u0ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u0->id, $u1->id, $u2->id, $u3->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + } + public function test_get_contexts_for_userid_with_usermodified_for_competency_data() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -372,6 +606,57 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist(provider::get_contexts_for_userid($u8->id), [$u0ctx]); } + public function test_get_users_in_context_with_usermodified_for_competency_data() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + $u0 = $dg->create_user(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $u3 = $dg->create_user(); + $u4 = $dg->create_user(); + $u5 = $dg->create_user(); + $u6 = $dg->create_user(); + $u7 = $dg->create_user(); + $u8 = $dg->create_user(); + $u0ctx = context_user::instance($u0->id); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + $this->setUser($u1); + $uc = $ccg->create_user_competency(['userid' => $u0->id, 'competencyid' => $comp1->get('id'), + 'reviewerid' => $u6->id]); + + $this->setUser($u2); + $e = $ccg->create_evidence(['usercompetencyid' => $uc->get('id'), 'actionuserid' => $u5->id]); + + $this->setUser($u3); + $ccg->create_user_evidence(['userid' => $u0->id]); + + $this->setUser($u4); + $ccg->create_user_evidence(['userid' => $u0->id]); + + // Comment on competency. + $this->allow_anyone_to_comment_anywhere(); + $this->setUser($u7); + $comments = $uc->get_comment_object(); + $comments->add('Hello there!'); + + // Comment on plan. + $this->setUser($u8); + $plan = $ccg->create_plan(['userid' => $u0->id]); + $comments = $plan->get_comment_object(); + $comments->add('Hi, planet!'); + + // Test correct users appear in the context. + $component = 'core_competency'; + + $userlist = new userlist($u0ctx, $component); + provider::get_users_in_context($userlist); + $expected = [$u0->id, $u1->id, $u2->id, $u3->id, $u4->id, $u5->id, $u6->id, $u7->id, $u8->id]; + $this->assert_array_match($expected, $userlist->get_userids()); + } + public function test_get_contexts_for_userid_with_actual_data_and_actual_data_is_goooood() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -421,6 +706,53 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assert_contextlist(provider::get_contexts_for_userid($u4->id), [$u4ctx]); } + public function test_get_users_in_context_with_actual_data_and_actual_data_is_goooood() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + $c1 = $dg->create_course(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + $u3 = $dg->create_user(); + $u4 = $dg->create_user(); + + $c1ctx = context_course::instance($c1->id); + $u1ctx = context_user::instance($u1->id); + $u2ctx = context_user::instance($u2->id); + $u3ctx = context_user::instance($u3->id); + $u4ctx = context_user::instance($u4->id); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + $comp2 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + $ccg->create_plan(['userid' => $u1->id]); + + $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $comp1->get('id')]); + + $ccg->create_user_competency_course(['userid' => $u3->id, 'competencyid' => $comp1->get('id'), 'courseid' => $c1->id]); + + $ccg->create_user_evidence(['userid' => $u4->id]); + + // Test correct users appear in each context. + $component = 'core_competency'; + + $userlist = new userlist($u1ctx, $component); + provider::get_users_in_context($userlist); + $this->assert_array_match([$u1->id], $userlist->get_userids()); + + $userlist = new userlist($u2ctx, $component); + provider::get_users_in_context($userlist); + $this->assert_array_match([$u2->id], $userlist->get_userids()); + + $userlist = new userlist($c1ctx, $component); + provider::get_users_in_context($userlist); + $this->assert_array_match([$u3->id], $userlist->get_userids()); + + $userlist = new userlist($u4ctx, $component); + provider::get_users_in_context($userlist); + $this->assert_array_match([$u4->id], $userlist->get_userids()); + } + public function test_delete_data_for_user() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency'); @@ -687,6 +1019,273 @@ class core_competency_privacy_testcase extends provider_testcase { $this->assertEquals(1, $this->get_comments_count($uc1a->get_comment_object(), $u2->id)); } + public function test_delete_data_for_users() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + + $c1 = $dg->create_course(); + $c2 = $dg->create_course(); + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + + $c1ctx = context_course::instance($c1->id); + $u1ctx = context_user::instance($u1->id); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + $comp2 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + $ue1a = $ccg->create_user_evidence(['userid' => $u1->id]); + $ue1b = $ccg->create_user_evidence(['userid' => $u1->id]); + $ue2 = $ccg->create_user_evidence(['userid' => $u2->id]); + $uec1a = $ccg->create_user_evidence_competency(['userevidenceid' => $ue1a->get('id'), + 'competencyid' => $comp1->get('id')]); + $uec1b = $ccg->create_user_evidence_competency(['userevidenceid' => $ue1b->get('id'), + 'competencyid' => $comp2->get('id')]); + $uec2 = $ccg->create_user_evidence_competency(['userevidenceid' => $ue2->get('id'), + 'competencyid' => $comp1->get('id')]); + + $p1a = $ccg->create_plan(['userid' => $u1->id]); + $p1b = $ccg->create_plan(['userid' => $u1->id]); + $p2 = $ccg->create_plan(['userid' => $u2->id]); + $pc1a = $ccg->create_plan_competency(['planid' => $p1a->get('id'), 'competencyid' => $comp1->get('id')]); + $pc1b = $ccg->create_plan_competency(['planid' => $p1b->get('id'), 'competencyid' => $comp2->get('id')]); + $pc2 = $ccg->create_plan_competency(['planid' => $p2->get('id'), 'competencyid' => $comp1->get('id')]); + $ucp1a = $ccg->create_user_competency_plan(['userid' => $u1->id, 'planid' => $p1a->get('id'), + 'competencyid' => $comp1->get('id')]); + $ucp1b = $ccg->create_user_competency_plan(['userid' => $u1->id, 'planid' => $p1b->get('id'), + 'competencyid' => $comp2->get('id')]); + $ucp2 = $ccg->create_user_competency_plan(['userid' => $u2->id, 'planid' => $p2->get('id'), + 'competencyid' => $comp1->get('id')]); + + $uc1a = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp1->get('id')]); + $uc1b = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp2->get('id')]); + $uc2 = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $comp2->get('id')]); + $e1a = $ccg->create_evidence(['usercompetencyid' => $uc1a->get('id')]); + $e1b = $ccg->create_evidence(['usercompetencyid' => $uc1b->get('id')]); + $e2 = $ccg->create_evidence(['usercompetencyid' => $uc2->get('id')]); + + $ucc1a = $ccg->create_user_competency_course(['userid' => $u1->id, 'courseid' => $c1->id, + 'competencyid' => $comp1->get('id')]); + $ucc1b = $ccg->create_user_competency_course(['userid' => $u1->id, 'courseid' => $c2->id, + 'competencyid' => $comp1->get('id')]); + $ucc2 = $ccg->create_user_competency_course(['userid' => $u2->id, 'courseid' => $c1->id, + 'competencyid' => $comp1->get('id')]); + + // User 1 comments on both plans. + $this->allow_anyone_to_comment_anywhere(); + $this->setUser($u1); + $p1a->get_comment_object()->add('Hi...'); + $p1a->get_comment_object()->add('mister'); + $p2->get_comment_object()->add('Ahoy!'); + + // User 2 comments on both competencies. + $this->setUser($u2); + $uc1a->get_comment_object()->add('Hi, too!'); + $uc1a->get_comment_object()->add('How are you?'); + $uc2->get_comment_object()->add('Ahoy, too!'); + + $p1acommentobj = $p1a->get_comment_object(); + $p2commentobj = $p2->get_comment_object(); + $uc1acommentobj = $uc1a->get_comment_object(); + $uc2commentobj = $uc2->get_comment_object(); + + $this->setAdminUser(); + $this->assertTrue(\core_competency\user_evidence::record_exists($ue1a->get('id'))); + $this->assertTrue(\core_competency\user_evidence::record_exists($ue1b->get('id'))); + $this->assertTrue(\core_competency\user_evidence::record_exists($ue2->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec1a->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec1b->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec2->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p1a->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p1b->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p2->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc1a->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc1b->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc2->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp1a->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp1b->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp2->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc1a->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc1b->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc2->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e1a->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e1b->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e2->get('id'))); + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc1a->get('id'))); + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc1b->get('id'))); + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc2->get('id'))); + $this->assert_has_comments($p1acommentobj); + $this->assertEquals(2, $this->get_comments_count($p1acommentobj, $u1->id)); + $this->assertEquals(0, $this->get_comments_count($p1acommentobj, $u2->id)); + $this->assert_has_comments($p2commentobj); + $this->assertEquals(1, $this->get_comments_count($p2commentobj, $u1->id)); + $this->assertEquals(0, $this->get_comments_count($p2commentobj, $u2->id)); + $this->assert_has_comments($uc1acommentobj); + $this->assertEquals(0, $this->get_comments_count($uc1acommentobj, $u1->id)); + $this->assertEquals(2, $this->get_comments_count($uc1acommentobj, $u2->id)); + $this->assert_has_comments($uc2commentobj); + $this->assertEquals(0, $this->get_comments_count($uc2commentobj, $u1->id)); + $this->assertEquals(1, $this->get_comments_count($uc2commentobj, $u2->id)); + + // Deleting user context. + $userlist = new approved_userlist($u1ctx, 'core_competency', [$u1->id, $u2->id]); + provider::delete_data_for_users($userlist); + + $this->assertFalse(\core_competency\user_evidence::record_exists($ue1a->get('id'))); + $this->assertFalse(\core_competency\user_evidence::record_exists($ue1b->get('id'))); + $this->assertFalse(\core_competency\user_evidence_competency::record_exists($uec1a->get('id'))); + $this->assertFalse(\core_competency\user_evidence_competency::record_exists($uec1b->get('id'))); + $this->assertFalse(\core_competency\plan::record_exists($p1a->get('id'))); + $this->assertFalse(\core_competency\plan::record_exists($p1b->get('id'))); + $this->assertFalse(\core_competency\plan_competency::record_exists($pc1a->get('id'))); + $this->assertFalse(\core_competency\plan_competency::record_exists($pc1b->get('id'))); + $this->assertFalse(\core_competency\user_competency_plan::record_exists($ucp1a->get('id'))); + $this->assertFalse(\core_competency\user_competency_plan::record_exists($ucp1b->get('id'))); + $this->assertFalse(\core_competency\user_competency::record_exists($uc1a->get('id'))); + $this->assertFalse(\core_competency\user_competency::record_exists($uc1b->get('id'))); + $this->assertFalse(\core_competency\evidence::record_exists($e1a->get('id'))); + $this->assertFalse(\core_competency\evidence::record_exists($e1b->get('id'))); + + $this->assert_has_no_comments($p1acommentobj); + $this->assertEquals(0, $this->get_comments_count($p1acommentobj, $u1->id)); + $this->assertEquals(0, $this->get_comments_count($p1acommentobj, $u2->id)); + $this->assert_has_no_comments($uc1acommentobj); + $this->assertEquals(0, $this->get_comments_count($uc1acommentobj, $u1->id)); + $this->assertEquals(0, $this->get_comments_count($uc1acommentobj, $u2->id)); + + // This should not have been affected. + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc1a->get('id'))); + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc1b->get('id'))); + + $this->assertTrue(\core_competency\user_evidence::record_exists($ue2->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec2->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p2->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc2->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp2->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc2->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e2->get('id'))); + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc2->get('id'))); + $this->assert_has_comments($p2commentobj); + $this->assertEquals(1, $this->get_comments_count($p2commentobj, $u1->id)); + $this->assertEquals(0, $this->get_comments_count($p2commentobj, $u2->id)); + $this->assert_has_comments($uc2commentobj); + $this->assertEquals(0, $this->get_comments_count($uc2commentobj, $u1->id)); + $this->assertEquals(1, $this->get_comments_count($uc2commentobj, $u2->id)); + + // Deleting course context as well. + $userlist = new approved_userlist($c1ctx, 'core_competency', [$u1->id]); + provider::delete_data_for_users($userlist); + + $this->assertFalse(\core_competency\user_competency_course::record_exists($ucc1a->get('id'))); + + // The rest belongs to another course, or the other user. + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc1b->get('id'))); + $this->assertTrue(\core_competency\user_evidence::record_exists($ue2->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec2->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p2->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc2->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp2->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc2->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e2->get('id'))); + $this->assertTrue(\core_competency\user_competency_course::record_exists($ucc2->get('id'))); + } + + public function test_delete_data_for_users_with_other_user_context() { + $dg = $this->getDataGenerator(); + $ccg = $dg->get_plugin_generator('core_competency'); + + $u1 = $dg->create_user(); + $u2 = $dg->create_user(); + + $u1ctx = context_user::instance($u1->id); + $u2ctx = context_user::instance($u2->id); + + $f = $ccg->create_framework(); + $comp1 = $ccg->create_competency(['competencyframeworkid' => $f->get('id')]); + + // Create a bunch of data for user 1. + $ue1a = $ccg->create_user_evidence(['userid' => $u1->id]); + $uec1a = $ccg->create_user_evidence_competency(['userevidenceid' => $ue1a->get('id'), + 'competencyid' => $comp1->get('id')]); + $p1a = $ccg->create_plan(['userid' => $u1->id]); + $pc1a = $ccg->create_plan_competency(['planid' => $p1a->get('id'), 'competencyid' => $comp1->get('id')]); + $ucp1a = $ccg->create_user_competency_plan(['userid' => $u1->id, 'planid' => $p1a->get('id'), + 'competencyid' => $comp1->get('id')]); + $uc1a = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp1->get('id')]); + $e1a = $ccg->create_evidence(['usercompetencyid' => $uc1a->get('id')]); + + $p2a = $ccg->create_plan(['userid' => $u2->id]); + + // User 2 comments. + $this->allow_anyone_to_comment_anywhere(); + $this->setUser($u2); + $p1a->get_comment_object()->add('Hi...'); + $p2a->get_comment_object()->add('Hi, hi!'); + $uc1a->get_comment_object()->add('Hi, too!'); + + // Confirm state. + $this->setAdminUser(); + $this->assertTrue(\core_competency\user_evidence::record_exists($ue1a->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec1a->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p1a->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc1a->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp1a->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc1a->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e1a->get('id'))); + $this->assert_has_comments($p1a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($p1a->get_comment_object(), $u2->id)); + $this->assert_has_comments($p2a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($p2a->get_comment_object(), $u2->id)); + $this->assert_has_comments($uc1a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($uc1a->get_comment_object(), $u2->id)); + + $this->assertTrue(\core_competency\plan::record_exists($p2a->get('id'))); + + // Delete for user 2, but we pass u1 context. + $userlist = new approved_userlist($u1ctx, 'core_competency', [$u2->id]); + provider::delete_data_for_users($userlist); + + // Nothing should have happened. + $this->assertTrue(\core_competency\user_evidence::record_exists($ue1a->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec1a->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p1a->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc1a->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp1a->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc1a->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e1a->get('id'))); + $this->assert_has_comments($p1a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($p1a->get_comment_object(), $u2->id)); + $this->assert_has_comments($p2a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($p2a->get_comment_object(), $u2->id)); + $this->assert_has_comments($uc1a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($uc1a->get_comment_object(), $u2->id)); + + $this->assertTrue(\core_competency\plan::record_exists($p2a->get('id'))); + + // Delete for user 2, in user 2 context. + $p2acommentobj = $p2a->get_comment_object(); + $userlist = new approved_userlist($u2ctx, 'core_competency', [$u2->id]); + provider::delete_data_for_users($userlist); + + // The plan got deleted. + $this->assertFalse(\core_competency\plan::record_exists($p2a->get('id'))); + $this->assert_has_no_comments($p2acommentobj); + + // Nothing should have happened for u1. + $this->assertTrue(\core_competency\user_evidence::record_exists($ue1a->get('id'))); + $this->assertTrue(\core_competency\user_evidence_competency::record_exists($uec1a->get('id'))); + $this->assertTrue(\core_competency\plan::record_exists($p1a->get('id'))); + $this->assertTrue(\core_competency\plan_competency::record_exists($pc1a->get('id'))); + $this->assertTrue(\core_competency\user_competency_plan::record_exists($ucp1a->get('id'))); + $this->assertTrue(\core_competency\user_competency::record_exists($uc1a->get('id'))); + $this->assertTrue(\core_competency\evidence::record_exists($e1a->get('id'))); + $this->assert_has_comments($p1a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($p1a->get_comment_object(), $u2->id)); + $this->assert_has_comments($uc1a->get_comment_object()); + $this->assertEquals(1, $this->get_comments_count($uc1a->get_comment_object(), $u2->id)); + } + public function test_delete_data_for_all_users_in_context() { $dg = $this->getDataGenerator(); $ccg = $dg->get_plugin_generator('core_competency');