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