Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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 namespace mod_forum; 18 19 use mod_forum_tests_generator_trait; 20 21 defined('MOODLE_INTERNAL') || die(); 22 23 require_once (__DIR__ . '/generator_trait.php'); 24 25 /** 26 * The exported_posts builder tests. 27 * 28 * @package mod_forum 29 * @copyright 2019 Ryan Wyllie <ryan@moodle.com> 30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 */ 32 class builders_exported_posts_test extends \advanced_testcase { 33 // Make use of the test generator trait. 34 use mod_forum_tests_generator_trait; 35 36 /** @var \mod_forum\local\builders\exported_posts */ 37 private $builder; 38 39 /** 40 * Set up function for tests. 41 */ 42 public function setUp(): void { 43 // We must clear the subscription caches. This has to be done both before each test, and after in case of other 44 // tests using these functions. 45 \mod_forum\subscriptions::reset_forum_cache(); 46 47 $builderfactory = \mod_forum\local\container::get_builder_factory(); 48 $this->builder = $builderfactory->get_exported_posts_builder(); 49 } 50 51 /** 52 * Tear down function for tests. 53 */ 54 public function tearDown(): void { 55 // We must clear the subscription caches. This has to be done both before each test, and after in case of other 56 // tests using these functions. 57 \mod_forum\subscriptions::reset_forum_cache(); 58 } 59 60 /** 61 * Convert the stdClass values into their proper entity classes. 62 * 63 * @param stdClass[] $forums List of forums 64 * @param stdClass[] $discussions List of discussions 65 * @param stdClass[] $posts List of posts 66 * @return array 67 */ 68 private function convert_to_entities(array $forums, array $discussions, array $posts) { 69 global $DB; 70 $entityfactory = \mod_forum\local\container::get_entity_factory(); 71 72 return [ 73 // Forums. 74 array_map(function($forum) use ($entityfactory, $DB) { 75 $course = $DB->get_record('course', ['id' => $forum->course]); 76 $coursemodule = get_coursemodule_from_instance('forum', $forum->id); 77 $context = \context_module::instance($coursemodule->id); 78 return $entityfactory->get_forum_from_stdClass($forum, $context, $coursemodule, $course); 79 }, $forums), 80 // Discussions. 81 array_map(function($discussion) use ($entityfactory) { 82 return $entityfactory->get_discussion_from_stdClass($discussion); 83 }, $discussions), 84 // Posts. 85 array_map(function($post) use ($entityfactory) { 86 return $entityfactory->get_post_from_stdClass($post); 87 }, $posts) 88 ]; 89 } 90 91 /** 92 * Test the build function throws exception if not given all of the forums for 93 * the list of posts. 94 */ 95 public function test_build_throws_exception_on_missing_forums() { 96 $this->resetAfterTest(); 97 98 $datagenerator = $this->getDataGenerator(); 99 $user = $datagenerator->create_user(); 100 $course = $datagenerator->create_course(); 101 $forum1 = $datagenerator->create_module('forum', ['course' => $course->id]); 102 $forum2 = $datagenerator->create_module('forum', ['course' => $course->id]); 103 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user); 104 [$discussion2, $post2] = $this->helper_post_to_forum($forum2, $user); 105 106 [$forums, $discussions, $posts] = $this->convert_to_entities( 107 [$forum1, $forum2], 108 [$discussion1, $discussion2], 109 [$post1, $post2] 110 ); 111 112 $this->expectException('moodle_exception'); 113 $this->builder->build($user, [$forums[0]], $discussions, $posts); 114 } 115 116 /** 117 * Test the build function throws exception if not given all of the discussions for 118 * the list of posts. 119 */ 120 public function test_build_throws_exception_on_missing_discussions() { 121 $this->resetAfterTest(); 122 123 $datagenerator = $this->getDataGenerator(); 124 $user = $datagenerator->create_user(); 125 $course = $datagenerator->create_course(); 126 $forum1 = $datagenerator->create_module('forum', ['course' => $course->id]); 127 $forum2 = $datagenerator->create_module('forum', ['course' => $course->id]); 128 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user); 129 [$discussion2, $post2] = $this->helper_post_to_forum($forum2, $user); 130 131 [$forums, $discussions, $posts] = $this->convert_to_entities( 132 [$forum1, $forum2], 133 [$discussion1, $discussion2], 134 [$post1, $post2] 135 ); 136 137 $this->expectException('moodle_exception'); 138 $this->builder->build($user, $forums, [$discussions[0]], $posts); 139 } 140 141 /** 142 * Test the build function returns the exported posts in the order that the posts are 143 * given. 144 */ 145 public function test_build_returns_posts_in_order() { 146 $this->resetAfterTest(); 147 148 $datagenerator = $this->getDataGenerator(); 149 $user1 = $datagenerator->create_user(); 150 $user2 = $datagenerator->create_user(); 151 $course = $datagenerator->create_course(); 152 $forum1 = $datagenerator->create_module('forum', ['course' => $course->id]); 153 $forum2 = $datagenerator->create_module('forum', ['course' => $course->id]); 154 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1); 155 [$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2); 156 $post3 = $this->helper_reply_to_post($post1, $user1); 157 $post4 = $this->helper_reply_to_post($post1, $user2); 158 [$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1); 159 [$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2); 160 $post7 = $this->helper_reply_to_post($post2, $user1); 161 $post8 = $this->helper_reply_to_post($post2, $user2); 162 163 [$forums, $discussions, $posts] = $this->convert_to_entities( 164 [$forum1, $forum2], 165 [$discussion1, $discussion2, $discussion3, $discussion4], 166 [$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8] 167 ); 168 169 // Randomly order the posts. 170 shuffle($posts); 171 172 $exportedposts = $this->builder->build($user1, $forums, $discussions, $posts); 173 174 $expectedpostids = array_map(function($post) { 175 return $post->get_id(); 176 }, $posts); 177 $actualpostids = array_map(function($exportedpost) { 178 return (int) $exportedpost->id; 179 }, $exportedposts); 180 181 $this->assertEquals($expectedpostids, $actualpostids); 182 } 183 184 /** 185 * Test the build function loads authors. 186 */ 187 public function test_build_loads_authors() { 188 $this->resetAfterTest(); 189 190 $datagenerator = $this->getDataGenerator(); 191 $user1 = $datagenerator->create_user(); 192 $user2 = $datagenerator->create_user(); 193 $user3 = $datagenerator->create_user(); 194 $course = $datagenerator->create_course(); 195 $forum1 = $datagenerator->create_module('forum', ['course' => $course->id]); 196 $forum2 = $datagenerator->create_module('forum', ['course' => $course->id]); 197 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1); 198 [$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2); 199 $post3 = $this->helper_reply_to_post($post1, $user1); 200 $post4 = $this->helper_reply_to_post($post1, $user2); 201 [$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1); 202 [$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2); 203 // These 2 replies from user 3 won't be inlcuded in the export. 204 $post7 = $this->helper_reply_to_post($post2, $user3); 205 $post8 = $this->helper_reply_to_post($post2, $user3); 206 207 [$forums, $discussions, $posts] = $this->convert_to_entities( 208 [$forum1, $forum2], 209 [$discussion1, $discussion2, $discussion3, $discussion4], 210 [$post1, $post2, $post3, $post4, $post5, $post6] 211 ); 212 213 $datagenerator->enrol_user($user1->id, $course->id); 214 $exportedposts = $this->builder->build($user1, $forums, $discussions, $posts); 215 216 // We didn't include any posts from user 3 so we shouldn't see the authors 217 // that match that user. 218 $expectedids = [$user1->id, $user2->id]; 219 $actualids = array_unique(array_map(function($exportedpost) { 220 return (int) $exportedpost->author->id; 221 }, $exportedposts)); 222 223 sort($expectedids); 224 sort($actualids); 225 226 $this->assertEquals($expectedids, $actualids); 227 } 228 229 /** 230 * Test the build function loads attachments. 231 */ 232 public function test_build_loads_attachments() { 233 $this->resetAfterTest(); 234 235 $datagenerator = $this->getDataGenerator(); 236 $user1 = $datagenerator->create_user(); 237 $user2 = $datagenerator->create_user(); 238 $user3 = $datagenerator->create_user(); 239 $course = $datagenerator->create_course(); 240 $forum1 = $datagenerator->create_module('forum', ['course' => $course->id]); 241 $forum2 = $datagenerator->create_module('forum', ['course' => $course->id]); 242 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1); 243 [$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2); 244 $post3 = $this->helper_reply_to_post($post1, $user1); 245 $post4 = $this->helper_reply_to_post($post1, $user2); 246 [$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1); 247 [$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2); 248 $post7 = $this->helper_reply_to_post($post5, $user3); 249 $post8 = $this->helper_reply_to_post($post5, $user3); 250 $filestorage = get_file_storage(); 251 252 [$forums, $discussions, $posts] = $this->convert_to_entities( 253 [$forum1, $forum2], 254 [$discussion1, $discussion2, $discussion3, $discussion4], 255 [$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8] 256 ); 257 258 // Add an attachment to a post in forum 1. 259 $attachment1 = $filestorage->create_file_from_string( 260 [ 261 'contextid' => $forums[0]->get_context()->id, 262 'component' => 'mod_forum', 263 'filearea' => 'attachment', 264 'itemid' => $post1->id, 265 'filepath' => '/', 266 'filename' => 'example1.jpg', 267 ], 268 'image contents' 269 ); 270 271 // Add an attachment to a post in forum 2. 272 $attachment2 = $filestorage->create_file_from_string( 273 [ 274 'contextid' => $forums[1]->get_context()->id, 275 'component' => 'mod_forum', 276 'filearea' => 'attachment', 277 'itemid' => $post7->id, 278 'filepath' => '/', 279 'filename' => 'example2.jpg', 280 ], 281 'image contents' 282 ); 283 284 // Enrol the user so that they can see the posts. 285 $datagenerator->enrol_user($user1->id, $course->id); 286 287 $exportedposts = $this->builder->build($user1, $forums, $discussions, $posts); 288 289 $expected = ['example1.jpg', 'example2.jpg']; 290 $actual = array_reduce($exportedposts, function($carry, $exportedpost) { 291 if (!empty($exportedpost->attachments)) { 292 foreach ($exportedpost->attachments as $attachment) { 293 $carry[] = $attachment->filename; 294 } 295 } 296 return $carry; 297 }, []); 298 299 sort($expected); 300 sort($actual); 301 302 $this->assertEquals($expected, $actual); 303 } 304 305 /** 306 * Test the build function loads author groups. 307 */ 308 public function test_build_loads_author_groups() { 309 $this->resetAfterTest(); 310 311 $datagenerator = $this->getDataGenerator(); 312 $user1 = $datagenerator->create_user(); 313 $user2 = $datagenerator->create_user(); 314 $user3 = $datagenerator->create_user(); 315 $course1 = $datagenerator->create_course(); 316 $course2 = $datagenerator->create_course(); 317 $forum1 = $datagenerator->create_module('forum', ['course' => $course1->id]); 318 $forum2 = $datagenerator->create_module('forum', ['course' => $course1->id]); 319 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1); 320 [$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2); 321 $post3 = $this->helper_reply_to_post($post1, $user1); 322 $post4 = $this->helper_reply_to_post($post1, $user2); 323 [$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1); 324 [$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2); 325 $post7 = $this->helper_reply_to_post($post5, $user3); 326 $post8 = $this->helper_reply_to_post($post5, $user3); 327 328 [$forums, $discussions, $posts] = $this->convert_to_entities( 329 [$forum1, $forum2], 330 [$discussion1, $discussion2, $discussion3, $discussion4], 331 [$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8] 332 ); 333 334 // Enrol the user so that they can see the posts. 335 $datagenerator->enrol_user($user1->id, $course1->id); 336 $datagenerator->enrol_user($user1->id, $course2->id); 337 $datagenerator->enrol_user($user2->id, $course1->id); 338 $datagenerator->enrol_user($user2->id, $course2->id); 339 $datagenerator->enrol_user($user3->id, $course1->id); 340 $datagenerator->enrol_user($user3->id, $course2->id); 341 342 $group1 = $datagenerator->create_group(['courseid' => $course1->id]); 343 $group2 = $datagenerator->create_group(['courseid' => $course1->id]); 344 // This group shouldn't be included in the results since it's in a different course. 345 $group3 = $datagenerator->create_group(['courseid' => $course2->id]); 346 347 $datagenerator->create_group_member(['userid' => $user1->id, 'groupid' => $group1->id]); 348 $datagenerator->create_group_member(['userid' => $user2->id, 'groupid' => $group1->id]); 349 $datagenerator->create_group_member(['userid' => $user1->id, 'groupid' => $group2->id]); 350 $datagenerator->create_group_member(['userid' => $user1->id, 'groupid' => $group3->id]); 351 352 $exportedposts = $this->builder->build($user1, $forums, $discussions, $posts); 353 354 $expected = [ 355 $user1->id => [$group1->id, $group2->id], 356 $user2->id => [$group1->id], 357 $user3->id => [] 358 ]; 359 $actual = array_reduce($exportedposts, function($carry, $exportedpost) { 360 $author = $exportedpost->author; 361 $authorid = $author->id; 362 363 if (!isset($carry[$authorid])) { 364 $carry[$authorid] = array_map(function($group) { 365 return $group['id']; 366 }, $author->groups); 367 } 368 369 return $carry; 370 }, []); 371 372 $this->assertEquals($expected, $actual); 373 } 374 375 /** 376 * Test the build function loads tags. 377 */ 378 public function test_build_loads_tags() { 379 $this->resetAfterTest(); 380 381 $datagenerator = $this->getDataGenerator(); 382 $user1 = $datagenerator->create_user(); 383 $user2 = $datagenerator->create_user(); 384 $user3 = $datagenerator->create_user(); 385 $course1 = $datagenerator->create_course(); 386 $course2 = $datagenerator->create_course(); 387 $forum1 = $datagenerator->create_module('forum', ['course' => $course1->id]); 388 $forum2 = $datagenerator->create_module('forum', ['course' => $course1->id]); 389 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1); 390 [$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2); 391 $post3 = $this->helper_reply_to_post($post1, $user1); 392 $post4 = $this->helper_reply_to_post($post1, $user2); 393 [$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1); 394 [$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2); 395 $post7 = $this->helper_reply_to_post($post5, $user3); 396 $post8 = $this->helper_reply_to_post($post5, $user3); 397 398 [$forums, $discussions, $posts] = $this->convert_to_entities( 399 [$forum1, $forum2], 400 [$discussion1, $discussion2, $discussion3, $discussion4], 401 [$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8] 402 ); 403 404 // Enrol the user so that they can see the posts. 405 $datagenerator->enrol_user($user1->id, $course1->id); 406 $datagenerator->enrol_user($user1->id, $course2->id); 407 $datagenerator->enrol_user($user2->id, $course1->id); 408 $datagenerator->enrol_user($user2->id, $course2->id); 409 $datagenerator->enrol_user($user3->id, $course1->id); 410 $datagenerator->enrol_user($user3->id, $course2->id); 411 412 \core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post1->id, $forums[0]->get_context(), ['foo', 'bar']); 413 \core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post4->id, $forums[0]->get_context(), ['foo', 'baz']); 414 \core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post7->id, $forums[1]->get_context(), ['bip']); 415 416 $exportedposts = $this->builder->build($user1, $forums, $discussions, $posts); 417 418 $expected = [ 419 $post1->id => ['foo', 'bar'], 420 $post4->id => ['foo', 'baz'], 421 $post7->id => ['bip'] 422 ]; 423 $actual = array_reduce($exportedposts, function($carry, $exportedpost) { 424 if (!empty($exportedpost->tags)) { 425 $carry[$exportedpost->id] = array_map(function($tag) { 426 return $tag['displayname']; 427 }, $exportedpost->tags); 428 } 429 430 return $carry; 431 }, []); 432 433 $this->assertEquals($expected, $actual); 434 } 435 436 /** 437 * Test the build function loads read_receipts. 438 */ 439 public function test_build_loads_read_receipts() { 440 $this->resetAfterTest(); 441 442 $datagenerator = $this->getDataGenerator(); 443 $user1 = $datagenerator->create_user(['trackforums' => 1]); 444 $user2 = $datagenerator->create_user(['trackforums' => 0]); 445 $course1 = $datagenerator->create_course(); 446 $course2 = $datagenerator->create_course(); 447 $forum1 = $datagenerator->create_module('forum', ['course' => $course1->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL]); 448 $forum2 = $datagenerator->create_module('forum', ['course' => $course1->id, 'trackingtype' => FORUM_TRACKING_OFF]); 449 [$discussion1, $post1] = $this->helper_post_to_forum($forum1, $user1); 450 [$discussion2, $post2] = $this->helper_post_to_forum($forum1, $user2); 451 $post3 = $this->helper_reply_to_post($post1, $user1); 452 $post4 = $this->helper_reply_to_post($post1, $user2); 453 [$discussion3, $post5] = $this->helper_post_to_forum($forum2, $user1); 454 [$discussion4, $post6] = $this->helper_post_to_forum($forum2, $user2); 455 $post7 = $this->helper_reply_to_post($post5, $user1); 456 $post8 = $this->helper_reply_to_post($post5, $user1); 457 458 [$forums, $discussions, $posts] = $this->convert_to_entities( 459 [$forum1, $forum2], 460 [$discussion1, $discussion2, $discussion3, $discussion4], 461 [$post1, $post2, $post3, $post4, $post5, $post6, $post7, $post8] 462 ); 463 464 // Enrol the user so that they can see the posts. 465 $datagenerator->enrol_user($user1->id, $course1->id); 466 $datagenerator->enrol_user($user1->id, $course2->id); 467 $datagenerator->enrol_user($user2->id, $course1->id); 468 $datagenerator->enrol_user($user2->id, $course2->id); 469 470 forum_tp_add_read_record($user1->id, $post1->id); 471 forum_tp_add_read_record($user1->id, $post4->id); 472 forum_tp_add_read_record($user1->id, $post7->id); 473 forum_tp_add_read_record($user2->id, $post1->id); 474 forum_tp_add_read_record($user2->id, $post4->id); 475 forum_tp_add_read_record($user2->id, $post7->id); 476 477 // User 1 has tracking enabled. 478 $exportedposts = $this->builder->build($user1, $forums, $discussions, $posts); 479 480 $expected = [ 481 // Tracking set for forum 1 for user 1. 482 $post1->id => false, 483 $post2->id => true, 484 $post3->id => true, 485 $post4->id => false, 486 // Tracking is off for forum 2 so everything should be null. 487 $post5->id => null, 488 $post6->id => null, 489 $post7->id => null, 490 $post8->id => null 491 ]; 492 $actual = array_reduce($exportedposts, function($carry, $exportedpost) { 493 $carry[$exportedpost->id] = $exportedpost->unread; 494 return $carry; 495 }, []); 496 497 $this->assertEquals($expected, $actual); 498 499 // User 2 has tracking disabled. 500 $exportedposts = $this->builder->build($user2, $forums, $discussions, $posts); 501 502 // Tracking is off for user 2 so everything should be null. 503 $expected = [ 504 $post1->id => null, 505 $post2->id => null, 506 $post3->id => null, 507 $post4->id => null, 508 $post5->id => null, 509 $post6->id => null, 510 $post7->id => null, 511 $post8->id => null 512 ]; 513 $actual = array_reduce($exportedposts, function($carry, $exportedpost) { 514 $carry[$exportedpost->id] = $exportedpost->unread; 515 return $carry; 516 }, []); 517 518 $this->assertEquals($expected, $actual); 519 } 520 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body