See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
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 * The post exporter tests. 19 * 20 * @package mod_forum 21 * @copyright 2019 Ryan Wyllie <ryan@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace mod_forum; 26 27 use mod_forum\local\entities\discussion as discussion_entity; 28 use mod_forum\local\entities\post as post_entity; 29 use mod_forum\local\exporters\post as post_exporter; 30 use mod_forum\local\managers\capability as capability_manager; 31 use mod_forum_tests_generator_trait; 32 33 defined('MOODLE_INTERNAL') || die(); 34 35 global $CFG; 36 require_once (__DIR__ . '/generator_trait.php'); 37 require_once($CFG->dirroot . '/rating/lib.php'); 38 39 /** 40 * The post exporter tests. 41 * 42 * @package mod_forum 43 * @copyright 2019 Ryan Wyllie <ryan@moodle.com> 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 class exporters_post_test extends \advanced_testcase { 47 // Make use of the test generator trait. 48 use mod_forum_tests_generator_trait; 49 50 /** 51 * Test the export function returns expected values. 52 * 53 * @dataProvider export_post_provider 54 * @param bool $istimed True if this is a timed post 55 * @param int $addtime Seconds to be added to the current time 56 */ 57 public function test_export_post($istimed = false, $addtime = 0) { 58 global $CFG, $PAGE; 59 $this->resetAfterTest(); 60 61 $CFG->enableportfolios = true; 62 $filestorage = get_file_storage(); 63 $renderer = $PAGE->get_renderer('core'); 64 $datagenerator = $this->getDataGenerator(); 65 $forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 66 $user = $datagenerator->create_user(); 67 $course = $datagenerator->create_course(); 68 $forum = $datagenerator->create_module('forum', ['course' => $course->id]); 69 $coursemodule = get_coursemodule_from_instance('forum', $forum->id); 70 $context = \context_module::instance($coursemodule->id); 71 $now = time(); 72 73 $forumgenparams = [ 74 'course' => $forum->course, 75 'userid' => $user->id, 76 'forum' => $forum->id, 77 ]; 78 if ($istimed) { 79 $forumgenparams['timestart'] = $now + $addtime; 80 } 81 $discussion = $forumgenerator->create_discussion((object) $forumgenparams); 82 83 $post = $forumgenerator->create_post((object) [ 84 'discussion' => $discussion->id, 85 'parent' => 0, 86 'userid' => $user->id, 87 'created' => $now, 88 'modified' => $now, 89 'subject' => 'This is the subject', 90 'message' => 'This is the message', 91 'messagetrust' => 1, 92 'attachment' => 0, 93 'totalscore' => 0, 94 'mailnow' => 1, 95 'deleted' => 0 96 ]); 97 98 \core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post->id, $context, ['foo', 'bar']); 99 $tags = \core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id); 100 $attachment = $filestorage->create_file_from_string( 101 [ 102 'contextid' => $context->id, 103 'component' => 'mod_forum', 104 'filearea' => 'attachment', 105 'itemid' => $post->id, 106 'filepath' => '/', 107 'filename' => 'example1.jpg', 108 ], 109 'image contents' 110 ); 111 112 $canview = true; 113 $canedit = true; 114 $candelete = true; 115 $cansplit = true; 116 $canreply = true; 117 $canexport = true; 118 $cancontrolreadstatus = true; 119 $canreplyprivately = true; 120 $canenrol = true; 121 $capabilitymanager = new test_capability_manager( 122 $canview, 123 $canedit, 124 $candelete, 125 $cansplit, 126 $canreply, 127 $canexport, 128 $cancontrolreadstatus, 129 $canreplyprivately, 130 $canenrol 131 ); 132 $managerfactory = \mod_forum\local\container::get_manager_factory(); 133 $entityfactory = \mod_forum\local\container::get_entity_factory(); 134 $forum = $entityfactory->get_forum_from_stdClass($forum, $context, $coursemodule, $course); 135 $discussion = $entityfactory->get_discussion_from_stdClass($discussion); 136 $post = $entityfactory->get_post_from_stdClass($post); 137 $author = $entityfactory->get_author_from_stdClass($user); 138 $authorcontext = \context_user::instance($author->get_id()); 139 140 $exporter = new post_exporter($post, [ 141 'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(), 142 'capabilitymanager' => $capabilitymanager, 143 'readreceiptcollection' => null, 144 'urlfactory' => \mod_forum\local\container::get_url_factory(), 145 'forum' => $forum, 146 'discussion' => $discussion, 147 'author' => $author, 148 'authorcontextid' => $authorcontext->id, 149 'user' => $user, 150 'context' => $context, 151 'authorgroups' => [], 152 'attachments' => [$attachment], 153 'tags' => $tags, 154 'rating' => null, 155 'includehtml' => true 156 ]); 157 158 $exportedpost = $exporter->export($renderer); 159 160 $this->assertEquals('This is the subject', $exportedpost->subject); 161 $this->assertEquals('This is the message', $exportedpost->message); 162 $this->assertEquals($user->id, $exportedpost->author->id); 163 $this->assertEquals($discussion->get_id(), $exportedpost->discussionid); 164 $this->assertEquals(false, $exportedpost->hasparent); 165 $this->assertEquals(null, $exportedpost->parentid); 166 if ($istimed && ($addtime > 0)) { 167 $this->assertEquals($now + $addtime, $exportedpost->timecreated); 168 } else { 169 $this->assertEquals($now, $exportedpost->timecreated); 170 } 171 $this->assertEquals(null, $exportedpost->unread); 172 $this->assertEquals(false, $exportedpost->isdeleted); 173 $this->assertEquals($canview, $exportedpost->capabilities['view']); 174 $this->assertEquals($canedit, $exportedpost->capabilities['edit']); 175 $this->assertEquals($candelete, $exportedpost->capabilities['delete']); 176 $this->assertEquals($cansplit, $exportedpost->capabilities['split']); 177 $this->assertEquals($canreply, $exportedpost->capabilities['reply']); 178 $this->assertEquals($canexport, $exportedpost->capabilities['export']); 179 $this->assertEquals($canenrol, $exportedpost->capabilities['selfenrol']); 180 $this->assertEquals($cancontrolreadstatus, $exportedpost->capabilities['controlreadstatus']); 181 $this->assertNotEmpty($exportedpost->urls['view']); 182 $this->assertNotEmpty($exportedpost->urls['viewisolated']); 183 $this->assertNotEmpty($exportedpost->urls['edit']); 184 $this->assertNotEmpty($exportedpost->urls['delete']); 185 $this->assertNotEmpty($exportedpost->urls['split']); 186 $this->assertNotEmpty($exportedpost->urls['reply']); 187 $this->assertNotEmpty($exportedpost->urls['markasread']); 188 $this->assertNotEmpty($exportedpost->urls['markasunread']); 189 $this->assertCount(1, $exportedpost->attachments); 190 $this->assertEquals('example1.jpg', $exportedpost->attachments[0]->filename); 191 $this->assertCount(2, $exportedpost->tags); 192 $this->assertEquals('foo', $exportedpost->tags[0]['displayname']); 193 $this->assertEquals('bar', $exportedpost->tags[1]['displayname']); 194 $this->assertEquals(null, $exportedpost->html['rating']); 195 $this->assertNotEquals(null, $exportedpost->html['taglist']); 196 $this->assertNotEmpty($exportedpost->html['authorsubheading']); 197 } 198 199 /** 200 * Data provider for test_export_post(). 201 * 202 * @return array 203 */ 204 public function export_post_provider(): array { 205 return [ 206 'Simple export' => [ 207 ], 208 'Test timed post future' => [ 209 true, 210 1000 211 ], 212 'Test timed post past' => [ 213 true, 214 -1000 215 ], 216 ]; 217 } 218 219 /** 220 * Test exporting of a deleted post. 221 */ 222 public function test_export_deleted_post() { 223 global $CFG, $PAGE; 224 $this->resetAfterTest(); 225 226 $CFG->enableportfolios = true; 227 $filestorage = get_file_storage(); 228 $renderer = $PAGE->get_renderer('core'); 229 $datagenerator = $this->getDataGenerator(); 230 $forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 231 $user = $datagenerator->create_user(); 232 $course = $datagenerator->create_course(); 233 $forum = $datagenerator->create_module('forum', ['course' => $course->id]); 234 $coursemodule = get_coursemodule_from_instance('forum', $forum->id); 235 $context = \context_module::instance($coursemodule->id); 236 $discussion = $forumgenerator->create_discussion((object) [ 237 'course' => $forum->course, 238 'userid' => $user->id, 239 'forum' => $forum->id 240 ]); 241 $now = time(); 242 $post = $forumgenerator->create_post((object) [ 243 'discussion' => $discussion->id, 244 'parent' => 0, 245 'userid' => $user->id, 246 'created' => $now, 247 'modified' => $now, 248 'subject' => 'This is the subject', 249 'message' => 'This is the message', 250 'messagetrust' => 1, 251 'attachment' => 0, 252 'totalscore' => 0, 253 'mailnow' => 1, 254 'deleted' => 1 255 ]); 256 257 \core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post->id, $context, ['foo', 'bar']); 258 $tags = \core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id); 259 $attachment = $filestorage->create_file_from_string( 260 [ 261 'contextid' => $context->id, 262 'component' => 'mod_forum', 263 'filearea' => 'attachment', 264 'itemid' => $post->id, 265 'filepath' => '/', 266 'filename' => 'example1.jpg', 267 ], 268 'image contents' 269 ); 270 271 $canview = true; 272 $canedit = true; 273 $candelete = true; 274 $cansplit = true; 275 $canreply = true; 276 $canexport = true; 277 $cancontrolreadstatus = true; 278 $capabilitymanager = new test_capability_manager( 279 $canview, 280 $canedit, 281 $candelete, 282 $cansplit, 283 $canreply, 284 $canexport, 285 $cancontrolreadstatus 286 ); 287 $managerfactory = \mod_forum\local\container::get_manager_factory(); 288 $entityfactory = \mod_forum\local\container::get_entity_factory(); 289 $forum = $entityfactory->get_forum_from_stdClass($forum, $context, $coursemodule, $course); 290 $discussion = $entityfactory->get_discussion_from_stdClass($discussion); 291 $post = $entityfactory->get_post_from_stdClass($post); 292 $author = $entityfactory->get_author_from_stdClass($user); 293 $authorcontext = \context_user::instance($author->get_id()); 294 295 $exporter = new post_exporter($post, [ 296 'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(), 297 'capabilitymanager' => $capabilitymanager, 298 'readreceiptcollection' => null, 299 'urlfactory' => \mod_forum\local\container::get_url_factory(), 300 'forum' => $forum, 301 'discussion' => $discussion, 302 'author' => $author, 303 'authorcontextid' => $authorcontext->id, 304 'user' => $user, 305 'context' => $context, 306 'authorgroups' => [], 307 'attachments' => [$attachment], 308 'tags' => $tags, 309 'rating' => null, 310 'includehtml' => true 311 ]); 312 313 $exportedpost = $exporter->export($renderer); 314 315 $this->assertNotEquals('This is the subject', $exportedpost->subject); 316 $this->assertNotEquals('This is the message', $exportedpost->message); 317 $this->assertEquals(null, $exportedpost->timecreated); 318 $this->assertEquals(null, $exportedpost->unread); 319 $this->assertEquals(true, $exportedpost->isdeleted); 320 $this->assertEquals([], $exportedpost->attachments); 321 $this->assertEquals([], $exportedpost->tags); 322 $this->assertEquals(null, $exportedpost->html['rating']); 323 $this->assertEquals(null, $exportedpost->html['taglist']); 324 $this->assertEquals(null, $exportedpost->html['authorsubheading']); 325 } 326 327 /** 328 * Test exporting of a post the user can't view. 329 */ 330 public function test_export_post_no_view_capability() { 331 global $CFG, $PAGE; 332 $this->resetAfterTest(); 333 334 $CFG->enableportfolios = true; 335 $filestorage = get_file_storage(); 336 $renderer = $PAGE->get_renderer('core'); 337 $datagenerator = $this->getDataGenerator(); 338 $forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 339 $user = $datagenerator->create_user(); 340 $course = $datagenerator->create_course(); 341 $forum = $datagenerator->create_module('forum', ['course' => $course->id]); 342 $coursemodule = get_coursemodule_from_instance('forum', $forum->id); 343 $context = \context_module::instance($coursemodule->id); 344 $discussion = $forumgenerator->create_discussion((object) [ 345 'course' => $forum->course, 346 'userid' => $user->id, 347 'forum' => $forum->id 348 ]); 349 $now = time(); 350 $post = $forumgenerator->create_post((object) [ 351 'discussion' => $discussion->id, 352 'parent' => 0, 353 'userid' => $user->id, 354 'created' => $now, 355 'modified' => $now, 356 'subject' => 'This is the subject', 357 'message' => 'This is the message', 358 'messagetrust' => 1, 359 'attachment' => 0, 360 'totalscore' => 0, 361 'mailnow' => 1, 362 'deleted' => 0 363 ]); 364 365 \core_tag_tag::set_item_tags('mod_forum', 'forum_posts', $post->id, $context, ['foo', 'bar']); 366 $tags = \core_tag_tag::get_item_tags('mod_forum', 'forum_posts', $post->id); 367 $attachment = $filestorage->create_file_from_string( 368 [ 369 'contextid' => $context->id, 370 'component' => 'mod_forum', 371 'filearea' => 'attachment', 372 'itemid' => $post->id, 373 'filepath' => '/', 374 'filename' => 'example1.jpg', 375 ], 376 'image contents' 377 ); 378 379 $canview = false; 380 $canedit = true; 381 $candelete = true; 382 $cansplit = true; 383 $canreply = true; 384 $canexport = true; 385 $cancontrolreadstatus = true; 386 $capabilitymanager = new test_capability_manager( 387 $canview, 388 $canedit, 389 $candelete, 390 $cansplit, 391 $canreply, 392 $canexport, 393 $cancontrolreadstatus 394 ); 395 $managerfactory = \mod_forum\local\container::get_manager_factory(); 396 $entityfactory = \mod_forum\local\container::get_entity_factory(); 397 $forum = $entityfactory->get_forum_from_stdClass($forum, $context, $coursemodule, $course); 398 $discussion = $entityfactory->get_discussion_from_stdClass($discussion); 399 $post = $entityfactory->get_post_from_stdClass($post); 400 $author = $entityfactory->get_author_from_stdClass($user); 401 $authorcontext = \context_user::instance($author->get_id()); 402 403 $exporter = new post_exporter($post, [ 404 'legacydatamapperfactory' => \mod_forum\local\container::get_legacy_data_mapper_factory(), 405 'capabilitymanager' => $capabilitymanager, 406 'readreceiptcollection' => null, 407 'urlfactory' => \mod_forum\local\container::get_url_factory(), 408 'forum' => $forum, 409 'discussion' => $discussion, 410 'author' => $author, 411 'authorcontextid' => $authorcontext->id, 412 'user' => $user, 413 'context' => $context, 414 'authorgroups' => [], 415 'attachments' => [$attachment], 416 'tags' => $tags, 417 'rating' => null, 418 'includehtml' => true 419 ]); 420 421 $exportedpost = $exporter->export($renderer); 422 423 $this->assertNotEquals('This is the subject', $exportedpost->subject); 424 $this->assertNotEquals('This is the message', $exportedpost->message); 425 $this->assertEquals(null, $exportedpost->timecreated); 426 $this->assertEquals(null, $exportedpost->unread); 427 $this->assertEquals(false, $exportedpost->isdeleted); 428 $this->assertEquals([], $exportedpost->attachments); 429 $this->assertEquals([], $exportedpost->tags); 430 $this->assertEquals(null, $exportedpost->html['rating']); 431 $this->assertEquals(null, $exportedpost->html['taglist']); 432 $this->assertEquals(null, $exportedpost->html['authorsubheading']); 433 } 434 } 435 436 /** 437 * Test implementation of the capability manager. 438 * 439 * @copyright 2019 Ryan Wyllie <ryan@moodle.com> 440 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 441 */ 442 class test_capability_manager extends capability_manager { 443 /** @var bool $view Value for can_view_post */ 444 private $view; 445 /** @var bool $edit Value for can_edit_post */ 446 private $edit; 447 /** @var bool $delete Value for can_delete_post */ 448 private $delete; 449 /** @var bool $split Value for can_split_post */ 450 private $split; 451 /** @var bool $reply Value for can_reply_to_post */ 452 private $reply; 453 /** @var bool $export Value for can_export_post */ 454 private $export; 455 /** @var bool $controlreadstatus Value for can_manually_control_post_read_status */ 456 private $controlreadstatus; 457 /** @var bool $controlreadstatus Value for can_reply_privately_to_post */ 458 private $canreplyprivatelytopost; 459 /** @var bool $canenrol Value for can_self_enrol */ 460 private $canenrol; 461 462 /** 463 * Constructor. 464 * 465 * @param bool $view Value for can_view_post 466 * @param bool $edit Value for can_edit_post 467 * @param bool $delete Value for can_delete_post 468 * @param bool $split Value for can_split_post 469 * @param bool $reply Value for can_reply_to_post 470 * @param bool $export Value for can_export_post 471 * @param bool $controlreadstatus Value for can_manually_control_post_read_status 472 */ 473 public function __construct( 474 bool $view = true, 475 bool $edit = true, 476 bool $delete = true, 477 bool $split = true, 478 bool $reply = true, 479 bool $export = true, 480 bool $controlreadstatus = true, 481 bool $canreplyprivatelytopost = true, 482 bool $canenrol = true 483 ) { 484 $this->view = $view; 485 $this->edit = $edit; 486 $this->delete = $delete; 487 $this->split = $split; 488 $this->reply = $reply; 489 $this->export = $export; 490 $this->controlreadstatus = $controlreadstatus; 491 $this->canreplyprivatelytopost = $canreplyprivatelytopost; 492 $this->canenrol = $canenrol; 493 } 494 495 /** 496 * Override can_view_post 497 * 498 * @param \stdClass $user The user 499 * @param discussion_entity $discussion The discussion 500 * @param post_entity $post The post 501 * @return bool 502 */ 503 public function can_view_post(\stdClass $user, discussion_entity $discussion, post_entity $post) : bool { 504 return $this->view; 505 } 506 507 /** 508 * Override can_edit_post 509 * 510 * @param \stdClass $user The user 511 * @param discussion_entity $discussion The discussion 512 * @param post_entity $post The post 513 * @return bool 514 */ 515 public function can_edit_post(\stdClass $user, discussion_entity $discussion, post_entity $post) : bool { 516 return $this->edit; 517 } 518 519 /** 520 * Override can_delete_post 521 * 522 * @param \stdClass $user The user 523 * @param discussion_entity $discussion The discussion 524 * @param post_entity $post The post 525 * @param bool $hasreplies 526 * @return bool 527 */ 528 public function can_delete_post(\stdClass $user, discussion_entity $discussion, post_entity $post, 529 bool $hasreplies = false) : bool { 530 return $this->delete; 531 } 532 533 /** 534 * Override can_split_post 535 * 536 * @param \stdClass $user The user 537 * @param discussion_entity $discussion The discussion 538 * @param post_entity $post The post 539 * @return bool 540 */ 541 public function can_split_post(\stdClass $user, discussion_entity $discussion, post_entity $post) : bool { 542 return $this->split; 543 } 544 545 /** 546 * Override can_reply_to_post 547 * 548 * @param \stdClass $user The user 549 * @param discussion_entity $discussion The discussion 550 * @param post_entity $post The post 551 * @return bool 552 */ 553 public function can_reply_to_post(\stdClass $user, discussion_entity $discussion, post_entity $post) : bool { 554 return $this->reply; 555 } 556 557 /** 558 * Override can_export_post 559 * 560 * @param \stdClass $user The user 561 * @param post_entity $post The post 562 * @return bool 563 */ 564 public function can_export_post(\stdClass $user, post_entity $post) : bool { 565 return $this->export; 566 } 567 568 /** 569 * Override can_manually_control_post_read_status 570 * 571 * @param \stdClass $user The user 572 * @return bool 573 */ 574 public function can_manually_control_post_read_status(\stdClass $user) : bool { 575 return $this->controlreadstatus; 576 } 577 578 /** 579 * Override can_reply_privately_to_post 580 * @param \stdClass $user 581 * @param post_entity $post 582 * @return bool 583 */ 584 public function can_reply_privately_to_post(\stdClass $user, post_entity $post) : bool { 585 return $this->canreplyprivatelytopost; 586 } 587 588 /** 589 * Override can_self_enrol 590 * @param \stdClass $user 591 * @return bool 592 */ 593 public function can_self_enrol(\stdClass $user) : bool { 594 return $this->canenrol; 595 } 596 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body