Skip to content

Commit

Permalink
Merge branch 'MDL-63690-34' of git://github.com/mihailges/moodle into…
Browse files Browse the repository at this point in the history
… MOODLE_34_STABLE
  • Loading branch information
andrewnicols committed Oct 31, 2018
2 parents 4b68132 + f41f2d5 commit f47eb43
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 7 deletions.
84 changes: 83 additions & 1 deletion blog/classes/privacy/provider.php
Expand Up @@ -49,7 +49,8 @@
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\provider {
\core_privacy\local\request\subsystem\provider,
\core_privacy\local\request\core_userlist_provider {

/**
* Returns metadata.
Expand Down Expand Up @@ -164,6 +165,51 @@ public static function get_contexts_for_userid(int $userid) : \core_privacy\loca
return $contextlist;
}

/**
* Get the list of contexts that contain user information for the specified user.
*
* @param \core_privacy\local\request\userlist $userlist The userlist containing the list of users who have
* data in this context/plugin combination.
*/
public static function get_users_in_context(\core_privacy\local\request\userlist $userlist) {
global $DB;
$context = $userlist->get_context();
if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_MODULE) {

$params = ['contextid' => $context->id];

$sql = "SELECT p.id, p.userid
FROM {post} p
JOIN {blog_association} ba ON ba.blogid = p.id AND ba.contextid = :contextid";

$posts = $DB->get_records_sql($sql, $params);
$userids = array_map(function($post) {
return $post->userid;
}, $posts);
$userlist->add_users($userids);

// Add any user's who posted on the blog.
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($posts), SQL_PARAMS_NAMED);
\core_comment\privacy\provider::get_users_in_context_from_sql($userlist, 'c', 'blog', 'format_blog', null, $insql,
$inparams);
} else if ($context->contextlevel == CONTEXT_USER) {
$params = ['userid' => $context->instanceid];

$sql = "SELECT userid
FROM {blog_external}
WHERE userid = :userid";
$userlist->add_from_sql('userid', $sql, $params);

$sql = "SELECT userid
FROM {post}
WHERE userid = :userid";
$userlist->add_from_sql('userid', $sql, $params);

// Add any user's who posted on the blog.
\core_comment\privacy\provider::get_users_in_context_from_sql($userlist, 'c', 'blog', 'format_blog', $context->id);
}
}

/**
* Export all user data for the specified user, in the specified contexts.
*
Expand Down Expand Up @@ -417,6 +463,42 @@ public static function delete_data_for_user(approved_contextlist $contextlist) {
}
}

/**
* 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(\core_privacy\local\request\approved_userlist $userlist) {
global $DB;

$context = $userlist->get_context();
$userids = $userlist->get_userids();

if ($context->contextlevel == CONTEXT_USER) {
// If one of the listed users matches this context then delete the blog, associations, and comments.
if (array_search($context->instanceid, $userids) !== false) {
self::delete_all_user_data($context);
\core_comment\privacy\provider::delete_comments_for_all_users($context, 'blog', 'format_blog');
return;
}
\core_comment\privacy\provider::delete_comments_for_users($userlist, 'blog', 'format_blog');
} else {
list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$sql = "SELECT ba.id
FROM {blog_association} ba
JOIN {post} p ON p.id = ba.blogid
WHERE ba.contextid = :contextid
AND p.userid $insql";
$inparams['contextid'] = $context->id;
$associds = $DB->get_fieldset_sql($sql, $inparams);

if (!empty($associds)) {
list($insql, $inparams) = $DB->get_in_or_equal($associds, SQL_PARAMS_NAMED, 'param', true);
$DB->delete_records_select('blog_association', "id $insql", $inparams);
}
}
}

/**
* Helper method to delete all user data.
*
Expand Down
202 changes: 202 additions & 0 deletions blog/tests/privacy_test.php
Expand Up @@ -129,6 +129,79 @@ public function test_get_contexts_for_userid_with_one_associated_post_only() {
$this->assertTrue(in_array(context_course::instance($c1->id)->id, $contextids));
}

/**
* Test that user IDs are returned for a specificed course or module context.
*/
public function test_get_users_in_context_course_and_module() {
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$course = $this->getDataGenerator()->create_course();
$c1ctx = context_course::instance($course->id);

$post = $this->create_post(['userid' => $user1->id, 'courseid' => $course->id]);
$entry = new blog_entry($post->id);
$entry->add_association($c1ctx->id);

// Add a comment from user 2.
$comment = $this->get_comment_object(context_user::instance($user1->id), $entry->id);
$this->setUser($user2);
$comment->add('Nice blog post');

$userlist = new \core_privacy\local\request\userlist($c1ctx, 'core_blog');
provider::get_users_in_context($userlist);
$userids = $userlist->get_userids();
$this->assertCount(2, $userids);

// Add an association for a module.
$cm1a = $this->getDataGenerator()->create_module('page', ['course' => $course]);
$cm1ctx = context_module::instance($cm1a->cmid);

$post2 = $this->create_post(['userid' => $user2->id, 'courseid' => $course->id]);
$entry2 = new blog_entry($post2->id);
$entry2->add_association($cm1ctx->id);

$userlist = new \core_privacy\local\request\userlist($cm1ctx, 'core_blog');
provider::get_users_in_context($userlist);
$userids = $userlist->get_userids();
$this->assertCount(1, $userids);
}

/**
* Test that user IDs are returned for a specificed user context.
*/
public function test_get_users_in_context_user_context() {
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$u1ctx = context_user::instance($user1->id);

$post = $this->create_post(['userid' => $user1->id]);
$entry = new blog_entry($post->id);

// Add a comment from user 2.
$comment = $this->get_comment_object($u1ctx, $entry->id);
$this->setUser($user2);
$comment->add('Another nice blog post');

$userlist = new \core_privacy\local\request\userlist($u1ctx, 'core_blog');
provider::get_users_in_context($userlist);
$userids = $userlist->get_userids();
$this->assertCount(2, $userids);
}

/**
* Test that user IDs are returned for a specificed user context for an external blog.
*/
public function test_get_users_in_context_external_blog() {
$user1 = $this->getDataGenerator()->create_user();
$u1ctx = context_user::instance($user1->id);
$extu1 = $this->create_external_blog(['userid' => $user1->id]);

$userlist = new \core_privacy\local\request\userlist($u1ctx, 'core_blog');
provider::get_users_in_context($userlist);
$userids = $userlist->get_userids();
$this->assertCount(1, $userids);
}

public function test_delete_data_for_user() {
global $DB;

Expand Down Expand Up @@ -629,6 +702,135 @@ public function test_export_data_for_user() {

}

/**
* Test that deleting of blog information in a user context works as desired.
*/
public function test_delete_data_for_users_user_context() {
global $DB;

$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$u4 = $this->getDataGenerator()->create_user();
$u5 = $this->getDataGenerator()->create_user();

$u1ctx = context_user::instance($u1->id);

$post = $this->create_post(['userid' => $u1->id]);
$entry = new blog_entry($post->id);

$comment = $this->get_comment_object($u1ctx, $entry->id);
$this->setUser($u1);
$comment->add('Hello, I created the blog');
$this->setUser($u2);
$comment->add('User 2 making a comment.');
$this->setUser($u3);
$comment->add('User 3 here.');
$this->setUser($u4);
$comment->add('User 4 is nice.');
$this->setUser($u5);
$comment->add('User 5 for the win.');

// This will only delete the comments made by user 4 and 5.
$this->assertCount(5, $DB->get_records('comments', ['contextid' => $u1ctx->id]));
$userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u4->id, $u5->id]);
provider::delete_data_for_users($userlist);
$this->assertCount(3, $DB->get_records('comments', ['contextid' => $u1ctx->id]));
$this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id]));

// As the owner of the post is here everything will be deleted.
$userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]);
provider::delete_data_for_users($userlist);
$this->assertEmpty($DB->get_records('comments', ['contextid' => $u1ctx->id]));
$this->assertEmpty($DB->get_records('post', ['userid' => $u1->id]));
}

/**
* Test that deleting of an external blog in a user context works as desired.
*/
public function test_delete_data_for_users_external_blog() {
global $DB;

$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();

$u1ctx = context_user::instance($u1->id);
$u2ctx = context_user::instance($u2->id);

$post = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']);
$post2 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://moodle.com', 'name' => 'Some other thing']);

// Check that we have two external blogs created.
$this->assertCount(2, $DB->get_records('blog_external'));
// This will only delete the external blog for user 1.
$userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]);
provider::delete_data_for_users($userlist);
$this->assertCount(1, $DB->get_records('blog_external'));
}

public function test_delete_data_for_users_course_and_module_context() {
global $DB;

$u1 = $this->getDataGenerator()->create_user();
$u2 = $this->getDataGenerator()->create_user();
$u3 = $this->getDataGenerator()->create_user();
$u4 = $this->getDataGenerator()->create_user();
$u5 = $this->getDataGenerator()->create_user();

$course = $this->getDataGenerator()->create_course();
$module = $this->getDataGenerator()->create_module('page', ['course' => $course]);

$u1ctx = context_user::instance($u1->id);
$u3ctx = context_user::instance($u3->id);
$c1ctx = context_course::instance($course->id);
$cm1ctx = context_module::instance($module->cmid);

// Blog with course association.
$post1 = $this->create_post(['userid' => $u1->id, 'courseid' => $course->id]);
$entry1 = new blog_entry($post1->id);
$entry1->add_association($c1ctx->id);

// Blog with module association.
$post2 = $this->create_post(['userid' => $u3->id, 'courseid' => $course->id]);
$entry2 = new blog_entry($post2->id);
$entry2->add_association($cm1ctx->id);

$comment = $this->get_comment_object($u1ctx, $entry1->id);
$this->setUser($u1);
$comment->add('Hello, I created the blog');
$this->setUser($u2);
$comment->add('comment on first course blog');
$this->setUser($u4);
$comment->add('user 4 on course blog');

$comment = $this->get_comment_object($u3ctx, $entry2->id);
$this->setUser($u3);
$comment->add('Hello, I created the module blog');
$this->setUser($u2);
$comment->add('I am commenting on both');
$this->setUser($u5);
$comment->add('User 5 for modules');

$this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
$this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
$this->assertCount(2, $DB->get_records('blog_association'));

// When using the course or module context we are only removing the blog associations and the comments.
$userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'core_blog', [$u2->id, $u1->id, $u5->id]);
provider::delete_data_for_users($userlist);
// Only one of the blog_associations should be removed. Everything else should be as before.
$this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
$this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
$this->assertCount(1, $DB->get_records('blog_association'));

$userlist = new \core_privacy\local\request\approved_userlist($cm1ctx, 'core_blog', [$u2->id, $u1->id, $u3->id]);
provider::delete_data_for_users($userlist);
// Now we've removed the other association.
$this->assertCount(6, $DB->get_records('comments', ['component' => 'blog']));
$this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id]));
$this->assertEmpty($DB->get_records('blog_association'));
}

/**
* Create a blog post.
*
Expand Down
13 changes: 7 additions & 6 deletions privacy/classes/local/request/userlist.php
Expand Up @@ -80,12 +80,13 @@ public function add_user(int $userid) : userlist {
public function add_users(array $userids) : userlist {
global $DB;

list($useridsql, $useridparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$sql = "SELECT DISTINCT u.id
FROM {user} u
WHERE u.id {$useridsql}";
$this->add_from_sql('id', $sql, $useridparams);

if (!empty($userids)) {
list($useridsql, $useridparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$sql = "SELECT DISTINCT u.id
FROM {user} u
WHERE u.id {$useridsql}";
$this->add_from_sql('id', $sql, $useridparams);
}
return $this;
}

Expand Down

0 comments on commit f47eb43

Please sign in to comment.