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 * Unit tests for the block_html implementation of the privacy API. 19 * 20 * @package block_html 21 * @category test 22 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 use \core_privacy\local\request\writer; 29 use \core_privacy\local\request\approved_contextlist; 30 use \core_privacy\local\request\approved_userlist; 31 use \block_html\privacy\provider; 32 33 /** 34 * Unit tests for the block_html implementation of the privacy API. 35 * 36 * @copyright 2018 Andrew Nicols <andrew@nicols.co.uk> 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class block_html_privacy_testcase extends \core_privacy\tests\provider_testcase { 40 /** 41 * Get the list of standard format options for comparison. 42 * 43 * @return \stdClass 44 */ 45 protected function get_format_options() { 46 return (object) [ 47 'overflowdiv' => true, 48 'noclean' => true, 49 ]; 50 } 51 52 /** 53 * Creates an HTML block on a user. 54 * 55 * @param string $title 56 * @param string $body 57 * @param string $format 58 * @return \block_instance 59 */ 60 protected function create_user_block($title, $body, $format) { 61 global $USER; 62 63 $configdata = (object) [ 64 'title' => $title, 65 'text' => [ 66 'itemid' => 19, 67 'text' => $body, 68 'format' => $format, 69 ], 70 ]; 71 72 $this->create_block($this->construct_user_page($USER)); 73 $block = $this->get_last_block_on_page($this->construct_user_page($USER)); 74 $block = block_instance('html', $block->instance); 75 $block->instance_config_save((object) $configdata); 76 77 return $block; 78 } 79 80 /** 81 * Creates an HTML block on a course. 82 * 83 * @param \stdClass $course 84 * @param string $title 85 * @param string $body 86 * @param string $format 87 * @return \block_instance 88 */ 89 protected function create_course_block($course, $title, $body, $format) { 90 global $USER; 91 92 $configdata = (object) [ 93 'title' => $title, 94 'text' => [ 95 'itemid' => 19, 96 'text' => $body, 97 'format' => $format, 98 ], 99 ]; 100 101 $this->create_block($this->construct_course_page($course)); 102 $block = $this->get_last_block_on_page($this->construct_course_page($course)); 103 $block = block_instance('html', $block->instance); 104 $block->instance_config_save((object) $configdata); 105 106 return $block; 107 } 108 109 /** 110 * Creates an HTML block on a page. 111 * 112 * @param \page $page Page 113 */ 114 protected function create_block($page) { 115 $page->blocks->add_block_at_end_of_default_region('html'); 116 } 117 118 /** 119 * Get the last block on the page. 120 * 121 * @param \page $page Page 122 * @return \block_html Block instance object 123 */ 124 protected function get_last_block_on_page($page) { 125 $blocks = $page->blocks->get_blocks_for_region($page->blocks->get_default_region()); 126 $block = end($blocks); 127 128 return $block; 129 } 130 131 /** 132 * Constructs a Page object for the User Dashboard. 133 * 134 * @param \stdClass $user User to create Dashboard for. 135 * @return \moodle_page 136 */ 137 protected function construct_user_page(\stdClass $user) { 138 $page = new \moodle_page(); 139 $page->set_context(\context_user::instance($user->id)); 140 $page->set_pagelayout('mydashboard'); 141 $page->set_pagetype('my-index'); 142 $page->blocks->load_blocks(); 143 return $page; 144 } 145 146 /** 147 * Constructs a Page object for the User Dashboard. 148 * 149 * @param \stdClass $course Course to create Dashboard for. 150 * @return \moodle_page 151 */ 152 protected function construct_course_page(\stdClass $course) { 153 $page = new \moodle_page(); 154 $page->set_context(\context_course::instance($course->id)); 155 $page->set_pagelayout('standard'); 156 $page->set_pagetype('course-view'); 157 $page->set_course($course); 158 $page->blocks->load_blocks(); 159 return $page; 160 } 161 162 /** 163 * Test that a block on the dashboard is exported. 164 */ 165 public function test_user_block() { 166 $this->resetAfterTest(); 167 168 $title = 'Example title'; 169 $content = 'Example content'; 170 $format = FORMAT_PLAIN; 171 172 // Test setup. 173 $user = $this->getDataGenerator()->create_user(); 174 $this->setUser($user); 175 $block = $this->create_user_block($title, $content, $format); 176 $context = \context_block::instance($block->instance->id); 177 178 // Get the contexts. 179 $contextlist = provider::get_contexts_for_userid($user->id); 180 181 // Only the user context should be returned. 182 $this->assertCount(1, $contextlist); 183 $this->assertEquals($context, $contextlist->current()); 184 185 // Export the data. 186 $this->export_context_data_for_user($user->id, $context, 'block_html'); 187 $writer = \core_privacy\local\request\writer::with_context($context); 188 $this->assertTrue($writer->has_any_data()); 189 190 // Check the data. 191 $data = $writer->get_data([]); 192 $this->assertInstanceOf('stdClass', $data); 193 $this->assertEquals($title, $data->title); 194 $this->assertEquals(format_text($content, $format, $this->get_format_options()), $data->content); 195 196 // Delete the context. 197 provider::delete_data_for_all_users_in_context($context); 198 199 // Re-fetch the contexts - it should no longer be returned. 200 $contextlist = provider::get_contexts_for_userid($user->id); 201 $this->assertCount(0, $contextlist); 202 } 203 204 /** 205 * Test that a block on the dashboard which is not configured is _not_ exported. 206 */ 207 public function test_user_block_unconfigured() { 208 global $DB; 209 210 $this->resetAfterTest(); 211 212 $title = 'Example title'; 213 $content = 'Example content'; 214 $format = FORMAT_PLAIN; 215 216 // Test setup. 217 $user = $this->getDataGenerator()->create_user(); 218 $this->setUser($user); 219 $block = $this->create_user_block($title, $content, $format); 220 $block->instance->configdata = ''; 221 $DB->update_record('block_instances', $block->instance); 222 $block = block_instance('html', $block->instance); 223 224 $context = \context_block::instance($block->instance->id); 225 226 // Get the contexts. 227 $contextlist = provider::get_contexts_for_userid($user->id); 228 229 // Only the user context should be returned. 230 $this->assertCount(1, $contextlist); 231 $this->assertEquals($context, $contextlist->current()); 232 233 // Export the data. 234 $this->export_context_data_for_user($user->id, $context, 'block_html'); 235 $writer = \core_privacy\local\request\writer::with_context($context); 236 $this->assertFalse($writer->has_any_data()); 237 } 238 239 /** 240 * Test that a block on the dashboard is exported. 241 */ 242 public function test_user_multiple_blocks_exported() { 243 $this->resetAfterTest(); 244 245 $title = 'Example title'; 246 $content = 'Example content'; 247 $format = FORMAT_PLAIN; 248 249 // Test setup. 250 $blocks = []; 251 $contexts = []; 252 $user = $this->getDataGenerator()->create_user(); 253 $this->setUser($user); 254 255 $block = $this->create_user_block($title, $content, $format); 256 $context = \context_block::instance($block->instance->id); 257 $contexts[$context->id] = $context; 258 259 $block = $this->create_user_block($title, $content, $format); 260 $context = \context_block::instance($block->instance->id); 261 $contexts[$context->id] = $context; 262 263 // Get the contexts. 264 $contextlist = provider::get_contexts_for_userid($user->id); 265 266 // There are now two blocks on the user context. 267 $this->assertCount(2, $contextlist); 268 foreach ($contextlist as $context) { 269 $this->assertTrue(isset($contexts[$context->id])); 270 } 271 272 // Turn them into an approved_contextlist. 273 $approvedlist = new approved_contextlist($user, 'block_html', $contextlist->get_contextids()); 274 275 // Delete using delete_data_for_user. 276 provider::delete_data_for_user($approvedlist); 277 278 // Re-fetch the contexts - it should no longer be returned. 279 $contextlist = provider::get_contexts_for_userid($user->id); 280 $this->assertCount(0, $contextlist); 281 } 282 283 /** 284 * Test that a block on the dashboard is not exported. 285 */ 286 public function test_course_blocks_not_exported() { 287 $this->resetAfterTest(); 288 289 $title = 'Example title'; 290 $content = 'Example content'; 291 $format = FORMAT_PLAIN; 292 293 // Test setup. 294 $user = $this->getDataGenerator()->create_user(); 295 $course = $this->getDataGenerator()->create_course(); 296 $this->setUser($user); 297 298 $block = $this->create_course_block($course, $title, $content, $format); 299 $context = \context_block::instance($block->instance->id); 300 301 // Get the contexts. 302 $contextlist = provider::get_contexts_for_userid($user->id); 303 304 // No blocks should be returned. 305 $this->assertCount(0, $contextlist); 306 } 307 308 /** 309 * Test that a block on the dashboard is exported. 310 */ 311 public function test_mixed_multiple_blocks_exported() { 312 $this->resetAfterTest(); 313 314 $title = 'Example title'; 315 $content = 'Example content'; 316 $format = FORMAT_PLAIN; 317 318 // Test setup. 319 $contexts = []; 320 321 $user = $this->getDataGenerator()->create_user(); 322 $course = $this->getDataGenerator()->create_course(); 323 $this->setUser($user); 324 325 $block = $this->create_course_block($course, $title, $content, $format); 326 $context = \context_block::instance($block->instance->id); 327 328 $block = $this->create_user_block($title, $content, $format); 329 $context = \context_block::instance($block->instance->id); 330 $contexts[$context->id] = $context; 331 332 $block = $this->create_user_block($title, $content, $format); 333 $context = \context_block::instance($block->instance->id); 334 $contexts[$context->id] = $context; 335 336 // Get the contexts. 337 $contextlist = provider::get_contexts_for_userid($user->id); 338 339 // There are now two blocks on the user context. 340 $this->assertCount(2, $contextlist); 341 foreach ($contextlist as $context) { 342 $this->assertTrue(isset($contexts[$context->id])); 343 } 344 } 345 346 /** 347 * Test that only users with a user context HTML block are fetched. 348 */ 349 public function test_get_users_in_context() { 350 $this->resetAfterTest(); 351 352 $component = 'block_html'; 353 $title = 'Block title'; 354 $content = 'Block content'; 355 $blockformat = FORMAT_PLAIN; 356 357 // Create a user with a user context HTML block. 358 $user1 = $this->getDataGenerator()->create_user(); 359 $this->setUser($user1); 360 361 $userblock = $this->create_user_block($title, $content, $blockformat); 362 $usercontext = \context_block::instance($userblock->instance->id); 363 364 // Create a user with a course context HTML block. 365 $user2 = $this->getDataGenerator()->create_user(); 366 $this->setUser($user2); 367 368 $course = $this->getDataGenerator()->create_course(); 369 $courseblock = $this->create_course_block($course, $title, $content, $blockformat); 370 $coursecontext = \context_block::instance($courseblock->instance->id); 371 372 // Ensure only the user with a user context HTML block is returned. 373 $userlist = new \core_privacy\local\request\userlist($usercontext, $component); 374 \block_html\privacy\provider::get_users_in_context($userlist); 375 376 $this->assertCount(1, $userlist); 377 378 $expected = [$user1->id]; 379 $actual = $userlist->get_userids(); 380 381 $this->assertEquals($expected, $actual); 382 383 // Ensure passing the course context returns no users. 384 $userlist = new \core_privacy\local\request\userlist($coursecontext, $component); 385 \mod_forum\privacy\provider::get_users_in_context($userlist); 386 $this->assertEmpty($userlist); 387 } 388 389 /** 390 * Test that data for users in approved userlist is deleted. 391 */ 392 public function test_delete_data_for_users() { 393 $this->resetAfterTest(); 394 395 $component = 'block_html'; 396 $title = 'Block title'; 397 $content = 'Block content'; 398 $blockformat = FORMAT_PLAIN; 399 400 // Create 2 user swith a user context HTML blocks. 401 $user1 = $this->getDataGenerator()->create_user(); 402 $this->setUser($user1); 403 404 $block1 = $this->create_user_block($title, $content, $blockformat); 405 $context1 = \context_block::instance($block1->instance->id); 406 407 $user2 = $this->getDataGenerator()->create_user(); 408 $this->setUser($user2); 409 $block2 = $this->create_user_block($title, $content, $blockformat); 410 $context2 = \context_block::instance($block2->instance->id); 411 412 // Create and populate the userlists. 413 $userlist1 = new \core_privacy\local\request\userlist($context1, $component); 414 \block_html\privacy\provider::get_users_in_context($userlist1); 415 $userlist2 = new \core_privacy\local\request\userlist($context2, $component); 416 \block_html\privacy\provider::get_users_in_context($userlist2); 417 418 // Ensure both members are included. 419 $this->assertCount(1, $userlist1); 420 $this->assertCount(1, $userlist2); 421 422 // Convert $userlist1 into an approved_contextlist. 423 $approvedlist = new approved_userlist($context1, 'block_html', $userlist1->get_userids()); 424 425 // Delete using delete_data_for_user. 426 provider::delete_data_for_users($approvedlist); 427 428 // Re-fetch users in the contexts - only the first one should now be empty. 429 $userlist1 = new \core_privacy\local\request\userlist($context1, $component); 430 \block_html\privacy\provider::get_users_in_context($userlist1); 431 $this->assertCount(0, $userlist1); 432 433 $userlist2 = new \core_privacy\local\request\userlist($context2, $component); 434 \block_html\privacy\provider::get_users_in_context($userlist2); 435 $this->assertCount(1, $userlist2); 436 } 437 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body