MDL-63497 mod_glossary: Add support for removal of context users
This issue is a part of the MDL-62560 Epic. Also added missing ratings include and test to mod_glossary unit tests.
This commit is contained in:
committed by
David Monllao
parent
dcdd4f1053
commit
55d1ef377c
@@ -24,9 +24,11 @@
|
||||
namespace mod_glossary\privacy;
|
||||
use core_privacy\local\metadata\collection;
|
||||
use core_privacy\local\request\approved_contextlist;
|
||||
use core_privacy\local\request\approved_userlist;
|
||||
use core_privacy\local\request\contextlist;
|
||||
use core_privacy\local\request\deletion_criteria;
|
||||
use core_privacy\local\request\helper;
|
||||
use core_privacy\local\request\userlist;
|
||||
use core_privacy\local\request\writer;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@@ -39,6 +41,8 @@ defined('MOODLE_INTERNAL') || die();
|
||||
class provider implements
|
||||
// This plugin stores personal data.
|
||||
\core_privacy\local\metadata\provider,
|
||||
// This plugin is capable of determining which users have data within it.
|
||||
\core_privacy\local\request\core_userlist_provider,
|
||||
// This plugin is a core_user_data_provider.
|
||||
\core_privacy\local\request\plugin\provider {
|
||||
|
||||
@@ -101,6 +105,72 @@ 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_module::class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find users with glossary entries.
|
||||
$sql = "SELECT ge.userid
|
||||
FROM {context} c
|
||||
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
|
||||
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||
JOIN {glossary} g ON g.id = cm.instance
|
||||
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
|
||||
WHERE c.id = :contextid";
|
||||
|
||||
$params = [
|
||||
'contextid' => $context->id,
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'modname' => 'glossary',
|
||||
];
|
||||
|
||||
$userlist->add_from_sql('userid', $sql, $params);
|
||||
|
||||
// Find users with glossary comments.
|
||||
$sql = "SELECT ge.id
|
||||
FROM {context} c
|
||||
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
|
||||
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||
JOIN {glossary} g ON g.id = cm.instance
|
||||
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
|
||||
WHERE c.id = :contextid";
|
||||
|
||||
$params = [
|
||||
'contextid' => $context->id,
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'modname' => 'glossary',
|
||||
];
|
||||
|
||||
\core_comment\privacy\provider::get_users_in_context_from_sql(
|
||||
$userlist, 'com', 'mod_glossary', 'glossary_entry', $sql, $params);
|
||||
|
||||
// Find users with glossary ratings.
|
||||
$sql = "SELECT ge.id
|
||||
FROM {context} c
|
||||
JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel
|
||||
JOIN {modules} m ON m.id = cm.module AND m.name = :modname
|
||||
JOIN {glossary} g ON g.id = cm.instance
|
||||
JOIN {glossary_entries} ge ON ge.glossaryid = g.id
|
||||
WHERE c.id = :contextid";
|
||||
|
||||
$params = [
|
||||
'contextid' => $context->id,
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'modname' => 'glossary',
|
||||
];
|
||||
|
||||
\core_rating\privacy\provider::get_users_in_context_from_sql($userlist, 'rat', 'mod_glossary', 'entry', $sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export personal data for the given approved_contextlist.
|
||||
*
|
||||
@@ -324,4 +394,59 @@ 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();
|
||||
$userids = $userlist->get_userids();
|
||||
$instanceid = $DB->get_field('course_modules', 'instance', ['id' => $context->instanceid], MUST_EXIST);
|
||||
list($userinsql, $userinparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
|
||||
|
||||
$glossaryentrieswhere = "glossaryid = :instanceid AND userid {$userinsql}";
|
||||
$userinstanceparams = $userinparams + ['instanceid' => $instanceid];
|
||||
|
||||
$entriesobject = $DB->get_recordset_select('glossary_entries', $glossaryentrieswhere, $userinstanceparams, 'id', 'id');
|
||||
$entries = [];
|
||||
|
||||
foreach ($entriesobject as $entry) {
|
||||
$entries[] = $entry->id;
|
||||
}
|
||||
|
||||
$entriesobject->close();
|
||||
|
||||
if (!$entries) {
|
||||
return;
|
||||
}
|
||||
|
||||
list($insql, $inparams) = $DB->get_in_or_equal($entries, SQL_PARAMS_NAMED);
|
||||
|
||||
// Delete related entry aliases.
|
||||
$DB->delete_records_list('glossary_alias', 'entryid', $entries);
|
||||
|
||||
// Delete related entry categories.
|
||||
$DB->delete_records_list('glossary_entries_categories', 'entryid', $entries);
|
||||
|
||||
// Delete related entry and attachment files.
|
||||
get_file_storage()->delete_area_files_select($context->id, 'mod_glossary', 'entry', $insql, $inparams);
|
||||
get_file_storage()->delete_area_files_select($context->id, 'mod_glossary', 'attachment', $insql, $inparams);
|
||||
|
||||
// Delete user tags related to this glossary.
|
||||
\core_tag\privacy\provider::delete_item_tags_select($context, 'mod_glossary', 'glossary_entries', $insql, $inparams);
|
||||
|
||||
// Delete related ratings.
|
||||
\core_rating\privacy\provider::delete_ratings_select($context, 'mod_glossary', 'entry', $insql, $inparams);
|
||||
|
||||
// Delete comments.
|
||||
\core_comment\privacy\provider::delete_comments_for_users($userlist, 'mod_glossary', 'glossary_entry');
|
||||
|
||||
// Now delete all user related entries.
|
||||
$deletewhere = "glossaryid = :instanceid AND userid {$userinsql}";
|
||||
$DB->delete_records_select('glossary_entries', $deletewhere, $userinstanceparams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/comment/lib.php');
|
||||
require_once($CFG->dirroot . '/rating/lib.php');
|
||||
|
||||
/**
|
||||
* Privacy provider tests class.
|
||||
@@ -131,6 +132,27 @@ class mod_glossary_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
$this->assertEquals($cmcontext->id, $contextforuser->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::get_users_in_context().
|
||||
*/
|
||||
public function test_get_users_in_context() {
|
||||
$component = 'mod_glossary';
|
||||
$cm = get_coursemodule_from_instance('glossary', $this->glossary->id);
|
||||
$cmcontext = context_module::instance($cm->id);
|
||||
|
||||
$userlist = new \core_privacy\local\request\userlist($cmcontext, $component);
|
||||
provider::get_users_in_context($userlist);
|
||||
|
||||
$this->assertCount(1, $userlist);
|
||||
|
||||
$expected = [$this->student->id];
|
||||
$actual = $userlist->get_userids();
|
||||
sort($expected);
|
||||
sort($actual);
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::export_user_data().
|
||||
*/
|
||||
@@ -212,6 +234,7 @@ class mod_glossary_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
global $DB;
|
||||
$generator = $this->getDataGenerator();
|
||||
|
||||
// Create another student who will add an entry to the first glossary.
|
||||
$student2 = $generator->create_user();
|
||||
$generator->enrol_user($student2->id, $this->course->id, 'student');
|
||||
|
||||
@@ -235,6 +258,11 @@ class mod_glossary_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
|
||||
core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context1, ['Pizza', 'Noodles']);
|
||||
|
||||
// As a teacher, rate student 2's entry.
|
||||
$this->setUser($this->teacher);
|
||||
$rating = $this->get_rating_object($context1, $ge3->id);
|
||||
$rating->update_rating(2);
|
||||
|
||||
// Before deletion, we should have 3 entries, one rating and 2 tag instances.
|
||||
$count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
|
||||
$this->assertEquals(3, $count);
|
||||
@@ -243,7 +271,10 @@ class mod_glossary_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
$this->assertEquals(2, $tagcount);
|
||||
$aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge3->id]);
|
||||
$this->assertEquals(1, $aliascount);
|
||||
// Create another student who will add an entry to the first glossary.
|
||||
$ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
|
||||
'itemid' => $ge3->id]);
|
||||
$this->assertEquals(1, $ratingcount);
|
||||
|
||||
$contextlist = new \core_privacy\local\request\approved_contextlist($student2, 'glossary',
|
||||
[$context1->id, $context2->id]);
|
||||
provider::delete_data_for_user($contextlist);
|
||||
@@ -274,6 +305,120 @@ class mod_glossary_privacy_provider_testcase extends \core_privacy\tests\provide
|
||||
$commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry',
|
||||
'userid' => $this->student->id]);
|
||||
$this->assertEquals(1, $commentcount);
|
||||
|
||||
$ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
|
||||
'itemid' => $ge3->id]);
|
||||
$this->assertEquals(0, $ratingcount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for provider::delete_data_for_users().
|
||||
*/
|
||||
public function test_delete_data_for_users() {
|
||||
global $DB;
|
||||
$generator = $this->getDataGenerator();
|
||||
|
||||
$student2 = $generator->create_user();
|
||||
$generator->enrol_user($student2->id, $this->course->id, 'student');
|
||||
|
||||
$cm1 = get_coursemodule_from_instance('glossary', $this->glossary->id);
|
||||
$glossary2 = $this->plugingenerator->create_instance(['course' => $this->course->id]);
|
||||
$cm2 = get_coursemodule_from_instance('glossary', $glossary2->id);
|
||||
|
||||
$ge1 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'first user glossary entry', 'approved' => 1]);
|
||||
$ge2 = $this->plugingenerator->create_content($glossary2, ['concept' => 'first user second glossary entry',
|
||||
'approved' => 1], ['two']);
|
||||
|
||||
$context1 = context_module::instance($cm1->id);
|
||||
$context2 = context_module::instance($cm2->id);
|
||||
core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge1->id, $context1, ['Parmi', 'Sushi']);
|
||||
|
||||
$this->setUser($student2);
|
||||
$ge3 = $this->plugingenerator->create_content($this->glossary, ['concept' => 'second user glossary entry',
|
||||
'approved' => 1], ['three']);
|
||||
|
||||
$comment = $this->get_comment_object($context1, $ge3->id);
|
||||
$comment->add('User 2 comment 1');
|
||||
$comment = $this->get_comment_object($context2, $ge2->id);
|
||||
$comment->add('User 2 comment 2');
|
||||
|
||||
core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge3->id, $context1, ['Pizza', 'Noodles']);
|
||||
core_tag_tag::set_item_tags('mod_glossary', 'glossary_entries', $ge2->id, $context2, ['Potato', 'Kumara']);
|
||||
|
||||
// As a teacher, rate student 2's entry.
|
||||
$this->setUser($this->teacher);
|
||||
$rating = $this->get_rating_object($context1, $ge3->id);
|
||||
$rating->update_rating(2);
|
||||
|
||||
// Check correct glossary 1 record counts before deletion.
|
||||
$count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
|
||||
// Note: There is an additional student entry from setUp().
|
||||
$this->assertEquals(3, $count);
|
||||
|
||||
list($context1itemsql, $context1itemparams) = $DB->get_in_or_equal([$ge1->id, $ge3->id], SQL_PARAMS_NAMED);
|
||||
$geparams = [
|
||||
'component' => 'mod_glossary',
|
||||
'itemtype' => 'glossary_entries',
|
||||
];
|
||||
$geparams += $context1itemparams;
|
||||
$wheresql = "component = :component AND itemtype = :itemtype AND itemid {$context1itemsql}";
|
||||
|
||||
$tagcount = $DB->count_records_select('tag_instance', $wheresql, $geparams);
|
||||
$this->assertEquals(4, $tagcount);
|
||||
|
||||
$aliascount = $DB->count_records_select('glossary_alias', "entryid {$context1itemsql}", $context1itemparams);
|
||||
$this->assertEquals(1, $aliascount);
|
||||
|
||||
$commentparams = [
|
||||
'component' => 'mod_glossary',
|
||||
'commentarea' => 'glossary_entry',
|
||||
];
|
||||
$commentparams += $context1itemparams;
|
||||
$commentwhere = "component = :component AND commentarea = :commentarea AND itemid {$context1itemsql}";
|
||||
|
||||
$commentcount = $DB->count_records_select('comments', $commentwhere, $commentparams);
|
||||
$this->assertEquals(1, $commentcount);
|
||||
|
||||
$ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
|
||||
'itemid' => $ge3->id]);
|
||||
$this->assertEquals(1, $ratingcount);
|
||||
|
||||
// Perform deletion within context 1 for both students.
|
||||
$approveduserlist = new core_privacy\local\request\approved_userlist($context1, 'mod_glossary',
|
||||
[$this->student->id, $student2->id]);
|
||||
provider::delete_data_for_users($approveduserlist);
|
||||
|
||||
// After deletion, all context 1 entries, tags and comment should be deleted.
|
||||
$count = $DB->count_records('glossary_entries', ['glossaryid' => $this->glossary->id]);
|
||||
$this->assertEquals(0, $count);
|
||||
|
||||
$tagcount = $DB->count_records_select('tag_instance', $wheresql, $geparams);
|
||||
$this->assertEquals(0, $tagcount);
|
||||
|
||||
$aliascount = $DB->count_records_select('glossary_alias', "entryid {$context1itemsql}", $context1itemparams);
|
||||
$this->assertEquals(0, $aliascount);
|
||||
|
||||
$commentcount = $DB->count_records_select('comments', $commentwhere, $commentparams);
|
||||
$this->assertEquals(0, $commentcount);
|
||||
|
||||
// Context 2 entries should remain intact.
|
||||
$count = $DB->count_records('glossary_entries', ['glossaryid' => $glossary2->id]);
|
||||
$this->assertEquals(1, $count);
|
||||
|
||||
$tagcount = $DB->count_records('tag_instance', ['component' => 'mod_glossary', 'itemtype' => 'glossary_entries',
|
||||
'itemid' => $ge2->id]);
|
||||
$this->assertEquals(2, $tagcount);
|
||||
|
||||
$aliascount = $DB->count_records('glossary_alias', ['entryid' => $ge2->id]);
|
||||
$this->assertEquals(1, $aliascount);
|
||||
|
||||
$commentcount = $DB->count_records('comments', ['component' => 'mod_glossary', 'commentarea' => 'glossary_entry',
|
||||
'itemid' => $ge2->id]);
|
||||
$this->assertEquals(1, $commentcount);
|
||||
|
||||
$ratingcount = $DB->count_records('rating', ['component' => 'mod_glossary', 'ratingarea' => 'entry',
|
||||
'itemid' => $ge3->id]);
|
||||
$this->assertEquals(0, $ratingcount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user