1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Data provider tests. 19 * 20 * @package core_blog 21 * @category test 22 * @copyright 2018 Frédéric Massart 23 * @author Frédéric Massart <fred@branchup.tech> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 namespace core_blog\privacy; 27 28 defined('MOODLE_INTERNAL') || die(); 29 global $CFG; 30 31 use core_privacy\tests\provider_testcase; 32 use core_privacy\local\request\approved_contextlist; 33 use core_privacy\local\request\transform; 34 use core_privacy\local\request\writer; 35 use core_blog\privacy\provider; 36 37 require_once($CFG->dirroot . '/blog/locallib.php'); 38 require_once($CFG->dirroot . '/comment/lib.php'); 39 40 /** 41 * Data provider testcase class. 42 * 43 * @package core_blog 44 * @category test 45 * @copyright 2018 Frédéric Massart 46 * @author Frédéric Massart <fred@branchup.tech> 47 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 48 */ 49 class provider_test extends provider_testcase { 50 51 public function setUp(): void { 52 $this->resetAfterTest(); 53 } 54 55 public function test_get_contexts_for_userid() { 56 $dg = $this->getDataGenerator(); 57 $c1 = $dg->create_course(); 58 $c2 = $dg->create_course(); 59 $c3 = $dg->create_course(); 60 $cm1a = $dg->create_module('page', ['course' => $c1]); 61 $cm1b = $dg->create_module('page', ['course' => $c1]); 62 $cm2a = $dg->create_module('page', ['course' => $c2]); 63 $u1 = $dg->create_user(); 64 $u2 = $dg->create_user(); 65 $u1ctx = \context_user::instance($u1->id); 66 67 // Blog share a table with notes, so throw data in there and make sure it doesn't get reported. 68 $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c3->id]); 69 70 $this->assertEmpty(provider::get_contexts_for_userid($u1->id)->get_contextids()); 71 $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids()); 72 73 // Gradually create blog posts for user 1. First system one. 74 $this->create_post(['userid' => $u1->id]); 75 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 76 $this->assertCount(1, $contextids); 77 $this->assertEquals($u1ctx->id, $contextids[0]); 78 $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids()); 79 80 // Create a blog post associated with c1. 81 $post = $this->create_post(['userid' => $u1->id, 'courseid' => $c1->id]); 82 $entry = new \blog_entry($post->id); 83 $entry->add_association(\context_course::instance($c1->id)->id); 84 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 85 $this->assertCount(2, $contextids); 86 $this->assertTrue(in_array($u1ctx->id, $contextids)); 87 $this->assertTrue(in_array(\context_course::instance($c1->id)->id, $contextids)); 88 $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids()); 89 90 // Create a blog post associated with cm2a. 91 $post = $this->create_post(['userid' => $u1->id, 'courseid' => $c2->id]); 92 $entry = new \blog_entry($post->id); 93 $entry->add_association(\context_module::instance($cm2a->cmid)->id); 94 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 95 $this->assertCount(3, $contextids); 96 $this->assertTrue(in_array($u1ctx->id, $contextids)); 97 $this->assertTrue(in_array(\context_course::instance($c1->id)->id, $contextids)); 98 $this->assertTrue(in_array(\context_module::instance($cm2a->cmid)->id, $contextids)); 99 $this->assertEmpty(provider::get_contexts_for_userid($u2->id)->get_contextids()); 100 101 // User 2 comments on u1's post. 102 $comment = $this->get_comment_object($u1ctx, $post->id); 103 $this->setUser($u2); 104 $comment->add('Hello, it\'s me!'); 105 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 106 $this->assertCount(3, $contextids); 107 $this->assertTrue(in_array($u1ctx->id, $contextids)); 108 $this->assertTrue(in_array(\context_course::instance($c1->id)->id, $contextids)); 109 $this->assertTrue(in_array(\context_module::instance($cm2a->cmid)->id, $contextids)); 110 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids(); 111 $this->assertCount(1, $contextids); 112 $this->assertTrue(in_array($u1ctx->id, $contextids)); 113 } 114 115 public function test_get_contexts_for_userid_with_one_associated_post_only() { 116 $dg = $this->getDataGenerator(); 117 $c1 = $dg->create_course(); 118 $u1 = $dg->create_user(); 119 $u1ctx = \context_user::instance($u1->id); 120 121 $this->assertEmpty(provider::get_contexts_for_userid($u1->id)->get_contextids()); 122 123 // Create a blog post associated with c1. It should always return both the course and user context. 124 $post = $this->create_post(['userid' => $u1->id, 'courseid' => $c1->id]); 125 $entry = new \blog_entry($post->id); 126 $entry->add_association(\context_course::instance($c1->id)->id); 127 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 128 $this->assertCount(2, $contextids); 129 $this->assertTrue(in_array($u1ctx->id, $contextids)); 130 $this->assertTrue(in_array(\context_course::instance($c1->id)->id, $contextids)); 131 } 132 133 /** 134 * Test that user IDs are returned for a specificed course or module context. 135 */ 136 public function test_get_users_in_context_course_and_module() { 137 $user1 = $this->getDataGenerator()->create_user(); 138 $user2 = $this->getDataGenerator()->create_user(); 139 $course = $this->getDataGenerator()->create_course(); 140 $c1ctx = \context_course::instance($course->id); 141 142 $post = $this->create_post(['userid' => $user1->id, 'courseid' => $course->id]); 143 $entry = new \blog_entry($post->id); 144 $entry->add_association($c1ctx->id); 145 146 // Add a comment from user 2. 147 $comment = $this->get_comment_object(\context_user::instance($user1->id), $entry->id); 148 $this->setUser($user2); 149 $comment->add('Nice blog post'); 150 151 $userlist = new \core_privacy\local\request\userlist($c1ctx, 'core_blog'); 152 provider::get_users_in_context($userlist); 153 $userids = $userlist->get_userids(); 154 $this->assertCount(2, $userids); 155 156 // Add an association for a module. 157 $cm1a = $this->getDataGenerator()->create_module('page', ['course' => $course]); 158 $cm1ctx = \context_module::instance($cm1a->cmid); 159 160 $post2 = $this->create_post(['userid' => $user2->id, 'courseid' => $course->id]); 161 $entry2 = new \blog_entry($post2->id); 162 $entry2->add_association($cm1ctx->id); 163 164 $userlist = new \core_privacy\local\request\userlist($cm1ctx, 'core_blog'); 165 provider::get_users_in_context($userlist); 166 $userids = $userlist->get_userids(); 167 $this->assertCount(1, $userids); 168 } 169 170 /** 171 * Test that user IDs are returned for a specificed user context. 172 */ 173 public function test_get_users_in_context_user_context() { 174 $user1 = $this->getDataGenerator()->create_user(); 175 $user2 = $this->getDataGenerator()->create_user(); 176 $u1ctx = \context_user::instance($user1->id); 177 178 $post = $this->create_post(['userid' => $user1->id]); 179 $entry = new \blog_entry($post->id); 180 181 // Add a comment from user 2. 182 $comment = $this->get_comment_object($u1ctx, $entry->id); 183 $this->setUser($user2); 184 $comment->add('Another nice blog post'); 185 186 $userlist = new \core_privacy\local\request\userlist($u1ctx, 'core_blog'); 187 provider::get_users_in_context($userlist); 188 $userids = $userlist->get_userids(); 189 $this->assertCount(2, $userids); 190 } 191 192 /** 193 * Test that user IDs are returned for a specificed user context for an external blog. 194 */ 195 public function test_get_users_in_context_external_blog() { 196 $user1 = $this->getDataGenerator()->create_user(); 197 $u1ctx = \context_user::instance($user1->id); 198 $extu1 = $this->create_external_blog(['userid' => $user1->id]); 199 200 $userlist = new \core_privacy\local\request\userlist($u1ctx, 'core_blog'); 201 provider::get_users_in_context($userlist); 202 $userids = $userlist->get_userids(); 203 $this->assertCount(1, $userids); 204 } 205 206 public function test_delete_data_for_user() { 207 global $DB; 208 209 $dg = $this->getDataGenerator(); 210 $c1 = $dg->create_course(); 211 $c2 = $dg->create_course(); 212 $cm1a = $dg->create_module('page', ['course' => $c1]); 213 $cm1b = $dg->create_module('page', ['course' => $c1]); 214 $cm2a = $dg->create_module('page', ['course' => $c2]); 215 $u1 = $dg->create_user(); 216 $u2 = $dg->create_user(); 217 $u3 = $dg->create_user(); 218 219 $c1ctx = \context_course::instance($c1->id); 220 $c2ctx = \context_course::instance($c2->id); 221 $cm1actx = \context_module::instance($cm1a->cmid); 222 $cm1bctx = \context_module::instance($cm1b->cmid); 223 $cm2actx = \context_module::instance($cm2a->cmid); 224 $u1ctx = \context_user::instance($u1->id); 225 $u2ctx = \context_user::instance($u2->id); 226 227 // Blog share a table with notes, so throw data in there and make sure it doesn't get deleted. 228 $this->assertFalse($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 229 $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id]); 230 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 231 232 // Create two external blogs. 233 $extu1 = $this->create_external_blog(['userid' => $u1->id]); 234 $extu2 = $this->create_external_blog(['userid' => $u2->id]); 235 236 // Create a set of posts. 237 $entry = new \blog_entry($this->create_post(['userid' => $u1->id])->id); 238 $commentedon = $entry; 239 $entry = new \blog_entry($this->create_post(['userid' => $u2->id])->id); 240 241 // Two course associations for u1. 242 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 243 $entry->add_association($c1ctx->id); 244 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 245 $entry->add_association($c1ctx->id); 246 247 // Two module associations with cm1a, and 1 with cm1b for u1. 248 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 249 $entry->add_association($cm1actx->id); 250 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 251 $entry->add_association($cm1actx->id); 252 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 253 $entry->add_association($cm1bctx->id); 254 255 // One association for u2 in c1, cm1a and cm2a. 256 $entry = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id); 257 $entry->add_association($c1ctx->id); 258 $entry = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id); 259 $entry->add_association($cm1actx->id); 260 $entry = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id); 261 $entry->add_association($cm2actx->id); 262 263 // One association for u1 in c2 and cm2a. 264 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id); 265 $entry->add_association($c2ctx->id); 266 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id); 267 $entry->add_association($cm2actx->id); 268 269 // Add comments. 270 $comment = $this->get_comment_object($u1ctx, $commentedon->id); 271 $this->setUser($u1); 272 $comment->add('Hello, it\'s me!'); 273 $comment->add('I was wondering...'); 274 $this->setUser($u2); 275 $comment->add('If after all these years'); 276 $this->setUser($u3); 277 $comment->add('You\'d like to meet'); 278 279 // Assert current setup. 280 $this->assertCount(6, provider::get_contexts_for_userid($u1->id)->get_contextids()); 281 $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id])); 282 $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids()); 283 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 284 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 285 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 286 $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id])); 287 $this->assertCount(1, $DB->get_records('comments', ['userid' => $u2->id])); 288 $this->assertCount(1, $DB->get_records('comments', ['userid' => $u3->id])); 289 290 // Delete for u1 in cm1a. 291 $appctxs = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]); 292 provider::delete_data_for_user($appctxs); 293 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 294 $this->assertCount(5, $contextids); 295 $this->assertFalse(in_array($cm1actx->id, $contextids)); 296 $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id])); 297 $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids()); 298 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 299 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 300 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 301 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 302 303 // Delete for u1 in c1. 304 $appctxs = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]); 305 provider::delete_data_for_user($appctxs); 306 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 307 $this->assertCount(4, $contextids); 308 $this->assertFalse(in_array($c1ctx->id, $contextids)); 309 $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id])); 310 $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids()); 311 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 312 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 313 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 314 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 315 316 // Delete for u1 in c2. 317 $appctxs = new approved_contextlist($u1, 'core_blog', [$c2ctx->id]); 318 provider::delete_data_for_user($appctxs); 319 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 320 $this->assertCount(3, $contextids); 321 $this->assertFalse(in_array($c2ctx->id, $contextids)); 322 $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id])); 323 $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids()); 324 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 325 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 326 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 327 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 328 329 // Delete for u1 in another user's context, shouldn't do anything. 330 provider::delete_data_for_user(new approved_contextlist($u1, 'core_blog', [$u2ctx->id])); 331 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 332 $this->assertCount(3, $contextids); 333 $this->assertFalse(in_array($c2ctx->id, $contextids)); 334 $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id])); 335 $this->assertCount(5, provider::get_contexts_for_userid($u2->id)->get_contextids()); 336 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 337 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 338 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 339 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 340 $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id])); 341 $this->assertCount(1, $DB->get_records('comments', ['userid' => $u2->id])); 342 343 // Delete for u2 in u1 context. 344 provider::delete_data_for_user(new approved_contextlist($u2, 'core_blog', [$u1ctx->id])); 345 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 346 $this->assertCount(3, $contextids); 347 $this->assertFalse(in_array($c2ctx->id, $contextids)); 348 $this->assertCount(9, $DB->get_records('post', ['userid' => $u1->id])); 349 $this->assertCount(4, provider::get_contexts_for_userid($u2->id)->get_contextids()); 350 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 351 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 352 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 353 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 354 $this->assertCount(2, $DB->get_records('comments', ['userid' => $u1->id])); 355 $this->assertCount(0, $DB->get_records('comments', ['userid' => $u2->id])); 356 $this->assertCount(1, $DB->get_records('comments', ['userid' => $u3->id])); 357 358 // Delete for u1 in their context. 359 $appctxs = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]); 360 provider::delete_data_for_user($appctxs); 361 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 362 $this->assertCount(0, $contextids); 363 $this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id])); 364 $this->assertCount(4, provider::get_contexts_for_userid($u2->id)->get_contextids()); 365 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 366 $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id])); 367 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 368 $this->assertCount(0, $DB->get_records('comments', ['userid' => $u1->id])); 369 $this->assertCount(0, $DB->get_records('comments', ['userid' => $u2->id])); 370 $this->assertCount(0, $DB->get_records('comments', ['userid' => $u3->id])); 371 $this->assertTrue($DB->record_exists('post', ['courseid' => $c1->id, 'userid' => $u1->id, 'module' => 'notes'])); 372 } 373 374 /** 375 * Test provider delete_data_for_user with a context that contains no entries 376 * 377 * @return void 378 */ 379 public function test_delete_data_for_user_empty_context() { 380 global $DB; 381 382 $user = $this->getDataGenerator()->create_user(); 383 $course = $this->getDataGenerator()->create_course(); 384 $context = \context_course::instance($course->id); 385 386 // Create a blog entry for user, associated with course. 387 $entry = new \blog_entry($this->create_post(['userid' => $user->id, 'courseid' => $course->id])->id); 388 $entry->add_association($context->id); 389 390 // Generate list of contexts for user. 391 $contexts = provider::get_contexts_for_userid($user->id); 392 $this->assertContainsEquals($context->id, $contexts->get_contextids()); 393 394 // Now delete the blog entry. 395 $entry->delete(); 396 397 // Try to delete user data using contexts obtained prior to entry deletion. 398 $contextlist = new approved_contextlist($user, 'core_blog', $contexts->get_contextids()); 399 provider::delete_data_for_user($contextlist); 400 401 // Sanity check to ensure blog_associations is really empty. 402 $this->assertEmpty($DB->get_records('blog_association', ['contextid' => $context->id])); 403 } 404 405 public function test_delete_data_for_all_users_in_context() { 406 global $DB; 407 408 $dg = $this->getDataGenerator(); 409 $c1 = $dg->create_course(); 410 $c2 = $dg->create_course(); 411 $cm1a = $dg->create_module('page', ['course' => $c1]); 412 $cm1b = $dg->create_module('page', ['course' => $c1]); 413 $cm2a = $dg->create_module('page', ['course' => $c2]); 414 $u1 = $dg->create_user(); 415 $u2 = $dg->create_user(); 416 417 $c1ctx = \context_course::instance($c1->id); 418 $c2ctx = \context_course::instance($c2->id); 419 $cm1actx = \context_module::instance($cm1a->cmid); 420 $cm1bctx = \context_module::instance($cm1b->cmid); 421 $cm2actx = \context_module::instance($cm2a->cmid); 422 $u1ctx = \context_user::instance($u1->id); 423 424 // Create two external blogs. 425 $extu1 = $this->create_external_blog(['userid' => $u1->id]); 426 $extu2 = $this->create_external_blog(['userid' => $u2->id]); 427 428 // Create a set of posts. 429 $entry = new \blog_entry($this->create_post(['userid' => $u1->id])->id); 430 $entry = new \blog_entry($this->create_post(['userid' => $u2->id])->id); 431 432 // Course associations for u1 and u2. 433 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 434 $entry->add_association($c1ctx->id); 435 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 436 $entry->add_association($c1ctx->id); 437 $entry = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id); 438 $entry->add_association($c1ctx->id); 439 440 // Module associations for u1 and u2. 441 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 442 $entry->add_association($cm1actx->id); 443 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 444 $entry->add_association($cm1actx->id); 445 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id])->id); 446 $entry->add_association($cm1bctx->id); 447 $entry = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id])->id); 448 $entry->add_association($cm1actx->id); 449 450 // Foreign associations for u1, u2. 451 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c2->id])->id); 452 $entry->add_association($c2ctx->id); 453 $entry = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c2->id])->id); 454 $entry->add_association($c2ctx->id); 455 $entry = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $cm2a->id])->id); 456 $entry->add_association($cm2actx->id); 457 458 // Validate what we've got. 459 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 460 $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id])); 461 $this->assertCount(6, $contextids); 462 $this->assertTrue(in_array($c1ctx->id, $contextids)); 463 $this->assertTrue(in_array($c2ctx->id, $contextids)); 464 $this->assertTrue(in_array($cm1actx->id, $contextids)); 465 $this->assertTrue(in_array($cm1bctx->id, $contextids)); 466 $this->assertTrue(in_array($cm2actx->id, $contextids)); 467 $this->assertTrue(in_array($u1ctx->id, $contextids)); 468 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids(); 469 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 470 $this->assertCount(4, $contextids); 471 $this->assertTrue(in_array($c1ctx->id, $contextids)); 472 $this->assertTrue(in_array($c2ctx->id, $contextids)); 473 $this->assertTrue(in_array($cm1actx->id, $contextids)); 474 475 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 476 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 477 478 // Delete cm1a context. 479 provider::delete_data_for_all_users_in_context($cm1actx); 480 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 481 $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id])); 482 $this->assertCount(5, $contextids); 483 $this->assertTrue(in_array($c1ctx->id, $contextids)); 484 $this->assertTrue(in_array($c2ctx->id, $contextids)); 485 $this->assertFalse(in_array($cm1actx->id, $contextids)); 486 $this->assertTrue(in_array($cm1bctx->id, $contextids)); 487 $this->assertTrue(in_array($cm2actx->id, $contextids)); 488 $this->assertTrue(in_array($u1ctx->id, $contextids)); 489 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids(); 490 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 491 $this->assertCount(3, $contextids); 492 $this->assertTrue(in_array($c1ctx->id, $contextids)); 493 $this->assertTrue(in_array($c2ctx->id, $contextids)); 494 $this->assertFalse(in_array($cm1actx->id, $contextids)); 495 496 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 497 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 498 499 // Delete c1 context. 500 provider::delete_data_for_all_users_in_context($c1ctx); 501 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 502 $this->assertCount(8, $DB->get_records('post', ['userid' => $u1->id])); 503 $this->assertCount(4, $contextids); 504 $this->assertFalse(in_array($c1ctx->id, $contextids)); 505 $this->assertTrue(in_array($c2ctx->id, $contextids)); 506 $this->assertFalse(in_array($cm1actx->id, $contextids)); 507 $this->assertTrue(in_array($cm1bctx->id, $contextids)); 508 $this->assertTrue(in_array($cm2actx->id, $contextids)); 509 $this->assertTrue(in_array($u1ctx->id, $contextids)); 510 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids(); 511 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 512 $this->assertCount(2, $contextids); 513 $this->assertFalse(in_array($c1ctx->id, $contextids)); 514 $this->assertTrue(in_array($c2ctx->id, $contextids)); 515 $this->assertFalse(in_array($cm1actx->id, $contextids)); 516 517 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u1->id])); 518 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 519 520 // Delete u1 context. 521 provider::delete_data_for_all_users_in_context($u1ctx); 522 $contextids = provider::get_contexts_for_userid($u1->id)->get_contextids(); 523 $this->assertCount(0, $DB->get_records('post', ['userid' => $u1->id])); 524 $this->assertCount(0, $contextids); 525 $this->assertFalse(in_array($c1ctx->id, $contextids)); 526 $this->assertFalse(in_array($c2ctx->id, $contextids)); 527 $this->assertFalse(in_array($cm1actx->id, $contextids)); 528 $this->assertFalse(in_array($cm1bctx->id, $contextids)); 529 $this->assertFalse(in_array($cm2actx->id, $contextids)); 530 $this->assertFalse(in_array($u1ctx->id, $contextids)); 531 $contextids = provider::get_contexts_for_userid($u2->id)->get_contextids(); 532 $this->assertCount(4, $DB->get_records('post', ['userid' => $u2->id])); 533 $this->assertCount(2, $contextids); 534 $this->assertFalse(in_array($c1ctx->id, $contextids)); 535 $this->assertTrue(in_array($c2ctx->id, $contextids)); 536 $this->assertFalse(in_array($cm1actx->id, $contextids)); 537 538 $this->assertCount(0, $DB->get_records('blog_external', ['userid' => $u1->id])); 539 $this->assertCount(1, $DB->get_records('blog_external', ['userid' => $u2->id])); 540 } 541 542 public function test_export_data_for_user() { 543 global $DB; 544 $dg = $this->getDataGenerator(); 545 546 $c1 = $dg->create_course(); 547 $cm1a = $dg->create_module('page', ['course' => $c1]); 548 $cm1b = $dg->create_module('page', ['course' => $c1]); 549 $u1 = $dg->create_user(); 550 $u2 = $dg->create_user(); 551 $c1ctx = \context_course::instance($c1->id); 552 $cm1actx = \context_module::instance($cm1a->cmid); 553 $cm1bctx = \context_module::instance($cm1b->cmid); 554 $u1ctx = \context_user::instance($u1->id); 555 $u2ctx = \context_user::instance($u2->id); 556 557 // System entries. 558 $e1 = new \blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hello world!', 559 'publishstate' => 'public'])->id); 560 $e2 = new \blog_entry($this->create_post(['userid' => $u1->id, 'subject' => 'Hi planet!', 561 'publishstate' => 'draft'])->id); 562 $e3 = new \blog_entry($this->create_post(['userid' => $u2->id, 'subject' => 'Ignore me'])->id); 563 564 // Create a blog entry associated with contexts. 565 $e4 = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc'])->id); 566 $e4->add_association($c1ctx->id); 567 $e4b = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Course assoc 2'])->id); 568 $e4b->add_association($c1ctx->id); 569 $e5 = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'Module assoc', 570 'publishstate' => 'public'])->id); 571 $e5->add_association($cm1actx->id); 572 $e5b = new \blog_entry($this->create_post(['userid' => $u1->id, 'courseid' => $c1->id, 'subject' => 'C/CM assoc'])->id); 573 $e5b->add_association($c1ctx->id); 574 $e5b->add_association($cm1actx->id); 575 $e6 = new \blog_entry($this->create_post(['userid' => $u2->id, 'courseid' => $c1->id, 'subject' => 'Module assoc'])->id); 576 $e6->add_association($cm1actx->id); 577 578 // External blogs. 579 $ex1 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']); 580 $ex2 = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://example.com', 'name' => 'Example']); 581 $ex3 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://example.com', 'name' => 'Ignore me']); 582 583 // Attach tags. 584 \core_tag_tag::set_item_tags('core', 'post', $e1->id, $u1ctx, ['Beer', 'Golf']); 585 \core_tag_tag::set_item_tags('core', 'blog_external', $ex1->id, $u1ctx, ['Car', 'Golf']); 586 \core_tag_tag::set_item_tags('core', 'post', $e3->id, $u2ctx, ['ITG']); 587 \core_tag_tag::set_item_tags('core', 'blog_external', $ex3->id, $u2ctx, ['DDR']); 588 \core_tag_tag::set_item_tags('core', 'dontfindme', $e1->id, $u1ctx, ['Lone tag']); 589 590 // Attach comments. 591 $comment = $this->get_comment_object($u1ctx, $e1->id); 592 $this->setUser($u1); 593 $comment->add('Hello, it\'s me!'); 594 $this->setUser($u2); 595 $comment->add('I was wondering if after'); 596 $this->setUser($u1); 597 $comment = $this->get_comment_object($u2ctx, $e3->id); 598 $comment->add('All these years'); 599 600 // Blog share a table with notes, so throw some data in there, it should not be exported. 601 $note = $dg->get_plugin_generator('core_notes')->create_instance(['userid' => $u1->id, 'courseid' => $c1->id, 602 'subject' => 'ABC']); 603 604 // Validate module associations. 605 $contextlist = new approved_contextlist($u1, 'core_blog', [$cm1actx->id]); 606 provider::export_user_data($contextlist); 607 $writer = writer::with_context($cm1actx); 608 $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]); 609 $this->assertCount(2, $assocs->associations); 610 $this->assertTrue(in_array('Module assoc', $assocs->associations)); 611 $this->assertTrue(in_array('C/CM assoc', $assocs->associations)); 612 613 // Validate course associations. 614 $contextlist = new approved_contextlist($u1, 'core_blog', [$c1ctx->id]); 615 provider::export_user_data($contextlist); 616 $writer = writer::with_context($c1ctx); 617 $assocs = $writer->get_data([get_string('privacy:path:blogassociations', 'core_blog')]); 618 $this->assertCount(3, $assocs->associations); 619 $this->assertTrue(in_array('Course assoc', $assocs->associations)); 620 $this->assertTrue(in_array('Course assoc 2', $assocs->associations)); 621 $this->assertTrue(in_array('C/CM assoc', $assocs->associations)); 622 623 // Confirm we're not exporting for another user. 624 $contextlist = new approved_contextlist($u2, 'core_blog', [$u2ctx->id]); 625 $writer = writer::with_context($u1ctx); 626 $this->assertFalse($writer->has_any_data()); 627 628 // Now export user context for u2. 629 $this->setUser($u2); 630 $contextlist = new approved_contextlist($u2, 'core_blog', [$u1ctx->id]); 631 provider::export_user_data($contextlist); 632 $writer = writer::with_context($u1ctx); 633 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'), 634 $ex1->name . " ({$ex1->id})"]); 635 $this->assertEmpty($data); 636 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), 637 $e2->subject . " ({$e2->id})"]); 638 $this->assertEmpty($data); 639 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), 640 $e1->subject . " ({$e1->id})"]); 641 $this->assertEmpty($data); 642 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), 643 $e1->subject . " ({$e1->id})", get_string('commentsubcontext', 'core_comment')]); 644 $this->assertNotEmpty($data); 645 $this->assertCount(1, $data->comments); 646 $comment = array_shift($data->comments); 647 $this->assertEquals('I was wondering if after', strip_tags($comment->content)); 648 649 // Now export user context data. 650 $this->setUser($u1); 651 $contextlist = new approved_contextlist($u1, 'core_blog', [$u1ctx->id]); 652 writer::reset(); 653 provider::export_user_data($contextlist); 654 $writer = writer::with_context($u1ctx); 655 656 // Check external blogs. 657 $externals = [$ex1, $ex2]; 658 foreach ($externals as $ex) { 659 $data = $writer->get_data([get_string('blog', 'core_blog'), get_string('externalblogs', 'core_blog'), 660 $ex->name . " ({$ex->id})"]); 661 $this->assertNotEmpty($data); 662 $this->assertEquals($data->name, $ex->name); 663 $this->assertEquals($data->description, $ex->description); 664 $this->assertEquals($data->url, $ex->url); 665 $this->assertEquals($data->filtertags, $ex->filtertags); 666 $this->assertEquals($data->modified, transform::datetime($ex->timemodified)); 667 $this->assertEquals($data->lastfetched, transform::datetime($ex->timefetched)); 668 } 669 670 // Check entries. 671 $entries = [$e1, $e2, $e4, $e4b, $e5, $e5b]; 672 $associations = [ 673 $e1->id => null, 674 $e2->id => null, 675 $e4->id => $c1ctx->get_context_name(), 676 $e4b->id => $c1ctx->get_context_name(), 677 $e5->id => $cm1actx->get_context_name(), 678 $e5b->id => [$c1ctx->get_context_name(), $cm1actx->get_context_name()], 679 ]; 680 foreach ($entries as $e) { 681 $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), $e->subject . " ({$e->id})"]; 682 $data = $writer->get_data($path); 683 $this->assertNotEmpty($data); 684 $this->assertEquals($data->subject, $e->subject); 685 $this->assertEquals($data->summary, $e->summary); 686 $this->assertEquals($data->publishstate, provider::transform_publishstate($e->publishstate)); 687 $this->assertEquals($data->created, transform::datetime($e->created)); 688 $this->assertEquals($data->lastmodified, transform::datetime($e->lastmodified)); 689 690 // We attached comments and tags to this entry. 691 $commentpath = array_merge($path, [get_string('commentsubcontext', 'core_comment')]); 692 if ($e->id == $e1->id) { 693 $tagdata = $writer->get_related_data($path, 'tags'); 694 $this->assertEqualsCanonicalizing(['Beer', 'Golf'], $tagdata); 695 696 $comments = $writer->get_data($commentpath); 697 $this->assertCount(2, $comments->comments); 698 699 $c0 = strip_tags($comments->comments[0]->content); 700 $c1 = strip_tags($comments->comments[1]->content); 701 $expectedcomments = [ 702 'Hello, it\'s me!', 703 'I was wondering if after', 704 ]; 705 706 $this->assertNotFalse(array_search($c0, $expectedcomments)); 707 $this->assertNotFalse(array_search($c1, $expectedcomments)); 708 $this->assertNotEquals($c0, $c1); 709 710 } else { 711 $tagdata = $writer->get_related_data($path, 'tags'); 712 $this->assertEmpty($tagdata); 713 $comments = $writer->get_data($commentpath); 714 $this->assertEmpty($comments); 715 } 716 717 if (isset($associations[$e->id])) { 718 $assocs = $associations[$e->id]; 719 if (is_array($assocs)) { 720 $this->assertCount(count($assocs), $data->associations); 721 foreach ($assocs as $v) { 722 $this->assertTrue(in_array($v, $data->associations)); 723 } 724 } else { 725 $this->assertCount(1, $data->associations); 726 $this->assertTrue(in_array($assocs, $data->associations)); 727 } 728 } 729 } 730 731 // The note was not exported. 732 $path = [get_string('blog', 'core_blog'), get_string('blogentries', 'core_blog'), "ABC ($note->id)"]; 733 $this->assertEmpty($writer->get_data($path)); 734 735 } 736 737 /** 738 * Test that deleting of blog information in a user context works as desired. 739 */ 740 public function test_delete_data_for_users_user_context() { 741 global $DB; 742 743 $u1 = $this->getDataGenerator()->create_user(); 744 $u2 = $this->getDataGenerator()->create_user(); 745 $u3 = $this->getDataGenerator()->create_user(); 746 $u4 = $this->getDataGenerator()->create_user(); 747 $u5 = $this->getDataGenerator()->create_user(); 748 749 $u1ctx = \context_user::instance($u1->id); 750 751 $post = $this->create_post(['userid' => $u1->id]); 752 $entry = new \blog_entry($post->id); 753 754 $comment = $this->get_comment_object($u1ctx, $entry->id); 755 $this->setUser($u1); 756 $comment->add('Hello, I created the blog'); 757 $this->setUser($u2); 758 $comment->add('User 2 making a comment.'); 759 $this->setUser($u3); 760 $comment->add('User 3 here.'); 761 $this->setUser($u4); 762 $comment->add('User 4 is nice.'); 763 $this->setUser($u5); 764 $comment->add('User 5 for the win.'); 765 766 // This will only delete the comments made by user 4 and 5. 767 $this->assertCount(5, $DB->get_records('comments', ['contextid' => $u1ctx->id])); 768 $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u4->id, $u5->id]); 769 provider::delete_data_for_users($userlist); 770 $this->assertCount(3, $DB->get_records('comments', ['contextid' => $u1ctx->id])); 771 $this->assertCount(1, $DB->get_records('post', ['userid' => $u1->id])); 772 773 // As the owner of the post is here everything will be deleted. 774 $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]); 775 provider::delete_data_for_users($userlist); 776 $this->assertEmpty($DB->get_records('comments', ['contextid' => $u1ctx->id])); 777 $this->assertEmpty($DB->get_records('post', ['userid' => $u1->id])); 778 } 779 780 /** 781 * Test that deleting of an external blog in a user context works as desired. 782 */ 783 public function test_delete_data_for_users_external_blog() { 784 global $DB; 785 786 $u1 = $this->getDataGenerator()->create_user(); 787 $u2 = $this->getDataGenerator()->create_user(); 788 789 $u1ctx = \context_user::instance($u1->id); 790 $u2ctx = \context_user::instance($u2->id); 791 792 $post = $this->create_external_blog(['userid' => $u1->id, 'url' => 'https://moodle.org', 'name' => 'Moodle RSS']); 793 $post2 = $this->create_external_blog(['userid' => $u2->id, 'url' => 'https://moodle.com', 'name' => 'Some other thing']); 794 795 // Check that we have two external blogs created. 796 $this->assertCount(2, $DB->get_records('blog_external')); 797 // This will only delete the external blog for user 1. 798 $userlist = new \core_privacy\local\request\approved_userlist($u1ctx, 'core_blog', [$u1->id, $u2->id]); 799 provider::delete_data_for_users($userlist); 800 $this->assertCount(1, $DB->get_records('blog_external')); 801 } 802 803 public function test_delete_data_for_users_course_and_module_context() { 804 global $DB; 805 806 $u1 = $this->getDataGenerator()->create_user(); 807 $u2 = $this->getDataGenerator()->create_user(); 808 $u3 = $this->getDataGenerator()->create_user(); 809 $u4 = $this->getDataGenerator()->create_user(); 810 $u5 = $this->getDataGenerator()->create_user(); 811 812 $course = $this->getDataGenerator()->create_course(); 813 $module = $this->getDataGenerator()->create_module('page', ['course' => $course]); 814 815 $u1ctx = \context_user::instance($u1->id); 816 $u3ctx = \context_user::instance($u3->id); 817 $c1ctx = \context_course::instance($course->id); 818 $cm1ctx = \context_module::instance($module->cmid); 819 820 // Blog with course association. 821 $post1 = $this->create_post(['userid' => $u1->id, 'courseid' => $course->id]); 822 $entry1 = new \blog_entry($post1->id); 823 $entry1->add_association($c1ctx->id); 824 825 // Blog with module association. 826 $post2 = $this->create_post(['userid' => $u3->id, 'courseid' => $course->id]); 827 $entry2 = new \blog_entry($post2->id); 828 $entry2->add_association($cm1ctx->id); 829 830 $comment = $this->get_comment_object($u1ctx, $entry1->id); 831 $this->setUser($u1); 832 $comment->add('Hello, I created the blog'); 833 $this->setUser($u2); 834 $comment->add('comment on first course blog'); 835 $this->setUser($u4); 836 $comment->add('user 4 on course blog'); 837 838 $comment = $this->get_comment_object($u3ctx, $entry2->id); 839 $this->setUser($u3); 840 $comment->add('Hello, I created the module blog'); 841 $this->setUser($u2); 842 $comment->add('I am commenting on both'); 843 $this->setUser($u5); 844 $comment->add('User 5 for modules'); 845 846 $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog'])); 847 $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id])); 848 $this->assertCount(2, $DB->get_records('blog_association')); 849 850 // When using the course or module context we are only removing the blog associations and the comments. 851 $userlist = new \core_privacy\local\request\approved_userlist($c1ctx, 'core_blog', [$u2->id, $u1->id, $u5->id]); 852 provider::delete_data_for_users($userlist); 853 // Only one of the blog_associations should be removed. Everything else should be as before. 854 $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog'])); 855 $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id])); 856 $this->assertCount(1, $DB->get_records('blog_association')); 857 858 $userlist = new \core_privacy\local\request\approved_userlist($cm1ctx, 'core_blog', [$u2->id, $u1->id, $u3->id]); 859 provider::delete_data_for_users($userlist); 860 // Now we've removed the other association. 861 $this->assertCount(6, $DB->get_records('comments', ['component' => 'blog'])); 862 $this->assertCount(2, $DB->get_records('post', ['courseid' => $course->id])); 863 $this->assertEmpty($DB->get_records('blog_association')); 864 } 865 866 /** 867 * Create a blog post. 868 * 869 * @param array $params The params. 870 * @return stdClass 871 */ 872 protected function create_post(array $params) { 873 global $DB; 874 $post = new \stdClass(); 875 $post->module = 'blog'; 876 $post->courseid = 0; 877 $post->subject = 'the test post'; 878 $post->summary = 'test post summary text'; 879 $post->summaryformat = FORMAT_PLAIN; 880 $post->publishstate = 'site'; 881 $post->created = time() - HOURSECS; 882 $post->lastmodified = time(); 883 foreach ($params as $key => $value) { 884 $post->{$key} = $value; 885 } 886 887 $post->id = $DB->insert_record('post', $post); 888 return $post; 889 } 890 891 /** 892 * Create an extenral blog. 893 * 894 * @param array $params The params. 895 * @return stdClass 896 */ 897 protected function create_external_blog(array $params) { 898 global $DB; 899 $post = new \stdClass(); 900 $post->name = 'test external'; 901 $post->description = 'the description'; 902 $post->url = 'http://example.com'; 903 $post->filtertags = 'a, c, b'; 904 $post->timefetched = time() - HOURSECS; 905 $post->timemodified = time(); 906 foreach ($params as $key => $value) { 907 $post->{$key} = $value; 908 } 909 $post->id = $DB->insert_record('blog_external', $post); 910 return $post; 911 } 912 913 /** 914 * Get the comment area. 915 * 916 * @param context $context The context. 917 * @param int $itemid The item ID. 918 * @param string $component The component. 919 * @param string $area The area. 920 * @return comment 921 */ 922 protected function get_comment_object(\context $context, $itemid) { 923 $args = new \stdClass(); 924 $args->context = $context; 925 $args->course = get_course(SITEID); 926 $args->area = 'format_blog'; 927 $args->itemid = $itemid; 928 $args->component = 'blog'; 929 $comment = new \comment($args); 930 $comment->set_post_permission(true); 931 return $comment; 932 } 933 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body