Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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 module forums tests 19 * 20 * @package mod_forum 21 * @copyright 2013 Frédéric Massart 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 global $CFG; 28 require_once($CFG->dirroot . '/mod/forum/lib.php'); 29 require_once($CFG->dirroot . '/mod/forum/locallib.php'); 30 require_once($CFG->dirroot . '/rating/lib.php'); 31 32 class mod_forum_lib_testcase extends advanced_testcase { 33 34 public function setUp(): void { 35 // We must clear the subscription caches. This has to be done both before each test, and after in case of other 36 // tests using these functions. 37 \mod_forum\subscriptions::reset_forum_cache(); 38 } 39 40 public function tearDown(): void { 41 // We must clear the subscription caches. This has to be done both before each test, and after in case of other 42 // tests using these functions. 43 \mod_forum\subscriptions::reset_forum_cache(); 44 } 45 46 public function test_forum_trigger_content_uploaded_event() { 47 $this->resetAfterTest(); 48 49 $user = $this->getDataGenerator()->create_user(); 50 $course = $this->getDataGenerator()->create_course(); 51 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 52 $context = context_module::instance($forum->cmid); 53 54 $this->setUser($user->id); 55 $fakepost = (object) array('id' => 123, 'message' => 'Yay!', 'discussion' => 100); 56 $cm = get_coursemodule_from_instance('forum', $forum->id); 57 58 $fs = get_file_storage(); 59 $dummy = (object) array( 60 'contextid' => $context->id, 61 'component' => 'mod_forum', 62 'filearea' => 'attachment', 63 'itemid' => $fakepost->id, 64 'filepath' => '/', 65 'filename' => 'myassignmnent.pdf' 66 ); 67 $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename); 68 69 $data = new stdClass(); 70 $sink = $this->redirectEvents(); 71 forum_trigger_content_uploaded_event($fakepost, $cm, 'some triggered from value'); 72 $events = $sink->get_events(); 73 74 $this->assertCount(1, $events); 75 $event = reset($events); 76 $this->assertInstanceOf('\mod_forum\event\assessable_uploaded', $event); 77 $this->assertEquals($context->id, $event->contextid); 78 $this->assertEquals($fakepost->id, $event->objectid); 79 $this->assertEquals($fakepost->message, $event->other['content']); 80 $this->assertEquals($fakepost->discussion, $event->other['discussionid']); 81 $this->assertCount(1, $event->other['pathnamehashes']); 82 $this->assertEquals($fi->get_pathnamehash(), $event->other['pathnamehashes'][0]); 83 $expected = new stdClass(); 84 $expected->modulename = 'forum'; 85 $expected->name = 'some triggered from value'; 86 $expected->cmid = $forum->cmid; 87 $expected->itemid = $fakepost->id; 88 $expected->courseid = $course->id; 89 $expected->userid = $user->id; 90 $expected->content = $fakepost->message; 91 $expected->pathnamehashes = array($fi->get_pathnamehash()); 92 $this->assertEventLegacyData($expected, $event); 93 $this->assertEventContextNotUsed($event); 94 } 95 96 public function test_forum_get_courses_user_posted_in() { 97 $this->resetAfterTest(); 98 99 $user1 = $this->getDataGenerator()->create_user(); 100 $user2 = $this->getDataGenerator()->create_user(); 101 $user3 = $this->getDataGenerator()->create_user(); 102 103 $course1 = $this->getDataGenerator()->create_course(); 104 $course2 = $this->getDataGenerator()->create_course(); 105 $course3 = $this->getDataGenerator()->create_course(); 106 107 // Create 3 forums, one in each course. 108 $record = new stdClass(); 109 $record->course = $course1->id; 110 $forum1 = $this->getDataGenerator()->create_module('forum', $record); 111 112 $record = new stdClass(); 113 $record->course = $course2->id; 114 $forum2 = $this->getDataGenerator()->create_module('forum', $record); 115 116 $record = new stdClass(); 117 $record->course = $course3->id; 118 $forum3 = $this->getDataGenerator()->create_module('forum', $record); 119 120 // Add a second forum in course 1. 121 $record = new stdClass(); 122 $record->course = $course1->id; 123 $forum4 = $this->getDataGenerator()->create_module('forum', $record); 124 125 // Add discussions to course 1 started by user1. 126 $record = new stdClass(); 127 $record->course = $course1->id; 128 $record->userid = $user1->id; 129 $record->forum = $forum1->id; 130 $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 131 132 $record = new stdClass(); 133 $record->course = $course1->id; 134 $record->userid = $user1->id; 135 $record->forum = $forum4->id; 136 $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 137 138 // Add discussions to course2 started by user1. 139 $record = new stdClass(); 140 $record->course = $course2->id; 141 $record->userid = $user1->id; 142 $record->forum = $forum2->id; 143 $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 144 145 // Add discussions to course 3 started by user2. 146 $record = new stdClass(); 147 $record->course = $course3->id; 148 $record->userid = $user2->id; 149 $record->forum = $forum3->id; 150 $discussion3 = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 151 152 // Add post to course 3 by user1. 153 $record = new stdClass(); 154 $record->course = $course3->id; 155 $record->userid = $user1->id; 156 $record->forum = $forum3->id; 157 $record->discussion = $discussion3->id; 158 $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); 159 160 // User 3 hasn't posted anything, so shouldn't get any results. 161 $user3courses = forum_get_courses_user_posted_in($user3); 162 $this->assertEmpty($user3courses); 163 164 // User 2 has only posted in course3. 165 $user2courses = forum_get_courses_user_posted_in($user2); 166 $this->assertCount(1, $user2courses); 167 $user2course = array_shift($user2courses); 168 $this->assertEquals($course3->id, $user2course->id); 169 $this->assertEquals($course3->shortname, $user2course->shortname); 170 171 // User 1 has posted in all 3 courses. 172 $user1courses = forum_get_courses_user_posted_in($user1); 173 $this->assertCount(3, $user1courses); 174 foreach ($user1courses as $course) { 175 $this->assertContains($course->id, array($course1->id, $course2->id, $course3->id)); 176 $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname, 177 $course3->shortname)); 178 179 } 180 181 // User 1 has only started a discussion in course 1 and 2 though. 182 $user1courses = forum_get_courses_user_posted_in($user1, true); 183 $this->assertCount(2, $user1courses); 184 foreach ($user1courses as $course) { 185 $this->assertContains($course->id, array($course1->id, $course2->id)); 186 $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname)); 187 } 188 } 189 190 /** 191 * Test the logic in the forum_tp_can_track_forums() function. 192 */ 193 public function test_forum_tp_can_track_forums() { 194 global $CFG; 195 196 $this->resetAfterTest(); 197 198 $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1)); 199 $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0)); 200 $course = $this->getDataGenerator()->create_course(); 201 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off. 202 $forumoff = $this->getDataGenerator()->create_module('forum', $options); 203 204 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On. 205 $forumforce = $this->getDataGenerator()->create_module('forum', $options); 206 207 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional. 208 $forumoptional = $this->getDataGenerator()->create_module('forum', $options); 209 210 // Allow force. 211 $CFG->forum_allowforcedreadtracking = 1; 212 213 // User on, forum off, should be off. 214 $result = forum_tp_can_track_forums($forumoff, $useron); 215 $this->assertEquals(false, $result); 216 217 // User on, forum on, should be on. 218 $result = forum_tp_can_track_forums($forumforce, $useron); 219 $this->assertEquals(true, $result); 220 221 // User on, forum optional, should be on. 222 $result = forum_tp_can_track_forums($forumoptional, $useron); 223 $this->assertEquals(true, $result); 224 225 // User off, forum off, should be off. 226 $result = forum_tp_can_track_forums($forumoff, $useroff); 227 $this->assertEquals(false, $result); 228 229 // User off, forum force, should be on. 230 $result = forum_tp_can_track_forums($forumforce, $useroff); 231 $this->assertEquals(true, $result); 232 233 // User off, forum optional, should be off. 234 $result = forum_tp_can_track_forums($forumoptional, $useroff); 235 $this->assertEquals(false, $result); 236 237 // Don't allow force. 238 $CFG->forum_allowforcedreadtracking = 0; 239 240 // User on, forum off, should be off. 241 $result = forum_tp_can_track_forums($forumoff, $useron); 242 $this->assertEquals(false, $result); 243 244 // User on, forum on, should be on. 245 $result = forum_tp_can_track_forums($forumforce, $useron); 246 $this->assertEquals(true, $result); 247 248 // User on, forum optional, should be on. 249 $result = forum_tp_can_track_forums($forumoptional, $useron); 250 $this->assertEquals(true, $result); 251 252 // User off, forum off, should be off. 253 $result = forum_tp_can_track_forums($forumoff, $useroff); 254 $this->assertEquals(false, $result); 255 256 // User off, forum force, should be off. 257 $result = forum_tp_can_track_forums($forumforce, $useroff); 258 $this->assertEquals(false, $result); 259 260 // User off, forum optional, should be off. 261 $result = forum_tp_can_track_forums($forumoptional, $useroff); 262 $this->assertEquals(false, $result); 263 264 } 265 266 /** 267 * Test the logic in the test_forum_tp_is_tracked() function. 268 */ 269 public function test_forum_tp_is_tracked() { 270 global $CFG; 271 272 $this->resetAfterTest(); 273 274 $cache = cache::make('mod_forum', 'forum_is_tracked'); 275 $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1)); 276 $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0)); 277 $course = $this->getDataGenerator()->create_course(); 278 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off. 279 $forumoff = $this->getDataGenerator()->create_module('forum', $options); 280 281 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On. 282 $forumforce = $this->getDataGenerator()->create_module('forum', $options); 283 284 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional. 285 $forumoptional = $this->getDataGenerator()->create_module('forum', $options); 286 287 // Allow force. 288 $CFG->forum_allowforcedreadtracking = 1; 289 290 // User on, forum off, should be off. 291 $result = forum_tp_is_tracked($forumoff, $useron); 292 $this->assertEquals(false, $result); 293 294 // User on, forum force, should be on. 295 $result = forum_tp_is_tracked($forumforce, $useron); 296 $this->assertEquals(true, $result); 297 298 // User on, forum optional, should be on. 299 $result = forum_tp_is_tracked($forumoptional, $useron); 300 $this->assertEquals(true, $result); 301 302 // User off, forum off, should be off. 303 $result = forum_tp_is_tracked($forumoff, $useroff); 304 $this->assertEquals(false, $result); 305 306 // User off, forum force, should be on. 307 $result = forum_tp_is_tracked($forumforce, $useroff); 308 $this->assertEquals(true, $result); 309 310 // User off, forum optional, should be off. 311 $result = forum_tp_is_tracked($forumoptional, $useroff); 312 $this->assertEquals(false, $result); 313 314 $cache->purge(); 315 // Don't allow force. 316 $CFG->forum_allowforcedreadtracking = 0; 317 318 // User on, forum off, should be off. 319 $result = forum_tp_is_tracked($forumoff, $useron); 320 $this->assertEquals(false, $result); 321 322 // User on, forum force, should be on. 323 $result = forum_tp_is_tracked($forumforce, $useron); 324 $this->assertEquals(true, $result); 325 326 // User on, forum optional, should be on. 327 $result = forum_tp_is_tracked($forumoptional, $useron); 328 $this->assertEquals(true, $result); 329 330 // User off, forum off, should be off. 331 $result = forum_tp_is_tracked($forumoff, $useroff); 332 $this->assertEquals(false, $result); 333 334 // User off, forum force, should be off. 335 $result = forum_tp_is_tracked($forumforce, $useroff); 336 $this->assertEquals(false, $result); 337 338 // User off, forum optional, should be off. 339 $result = forum_tp_is_tracked($forumoptional, $useroff); 340 $this->assertEquals(false, $result); 341 342 // Stop tracking so we can test again. 343 forum_tp_stop_tracking($forumforce->id, $useron->id); 344 forum_tp_stop_tracking($forumoptional->id, $useron->id); 345 forum_tp_stop_tracking($forumforce->id, $useroff->id); 346 forum_tp_stop_tracking($forumoptional->id, $useroff->id); 347 348 $cache->purge(); 349 // Allow force. 350 $CFG->forum_allowforcedreadtracking = 1; 351 352 // User on, preference off, forum force, should be on. 353 $result = forum_tp_is_tracked($forumforce, $useron); 354 $this->assertEquals(true, $result); 355 356 // User on, preference off, forum optional, should be on. 357 $result = forum_tp_is_tracked($forumoptional, $useron); 358 $this->assertEquals(false, $result); 359 360 // User off, preference off, forum force, should be on. 361 $result = forum_tp_is_tracked($forumforce, $useroff); 362 $this->assertEquals(true, $result); 363 364 // User off, preference off, forum optional, should be off. 365 $result = forum_tp_is_tracked($forumoptional, $useroff); 366 $this->assertEquals(false, $result); 367 368 $cache->purge(); 369 // Don't allow force. 370 $CFG->forum_allowforcedreadtracking = 0; 371 372 // User on, preference off, forum force, should be on. 373 $result = forum_tp_is_tracked($forumforce, $useron); 374 $this->assertEquals(false, $result); 375 376 // User on, preference off, forum optional, should be on. 377 $result = forum_tp_is_tracked($forumoptional, $useron); 378 $this->assertEquals(false, $result); 379 380 // User off, preference off, forum force, should be off. 381 $result = forum_tp_is_tracked($forumforce, $useroff); 382 $this->assertEquals(false, $result); 383 384 // User off, preference off, forum optional, should be off. 385 $result = forum_tp_is_tracked($forumoptional, $useroff); 386 $this->assertEquals(false, $result); 387 } 388 389 /** 390 * Test the logic in the forum_tp_get_course_unread_posts() function. 391 */ 392 public function test_forum_tp_get_course_unread_posts() { 393 global $CFG; 394 395 $this->resetAfterTest(); 396 397 $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1)); 398 $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0)); 399 $course = $this->getDataGenerator()->create_course(); 400 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off. 401 $forumoff = $this->getDataGenerator()->create_module('forum', $options); 402 403 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On. 404 $forumforce = $this->getDataGenerator()->create_module('forum', $options); 405 406 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional. 407 $forumoptional = $this->getDataGenerator()->create_module('forum', $options); 408 409 // Add discussions to the tracking off forum. 410 $record = new stdClass(); 411 $record->course = $course->id; 412 $record->userid = $useron->id; 413 $record->forum = $forumoff->id; 414 $discussionoff = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 415 416 // Add discussions to the tracking forced forum. 417 $record = new stdClass(); 418 $record->course = $course->id; 419 $record->userid = $useron->id; 420 $record->forum = $forumforce->id; 421 $discussionforce = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 422 423 // Add post to the tracking forced discussion. 424 $record = new stdClass(); 425 $record->course = $course->id; 426 $record->userid = $useroff->id; 427 $record->forum = $forumforce->id; 428 $record->discussion = $discussionforce->id; 429 $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); 430 431 // Add discussions to the tracking optional forum. 432 $record = new stdClass(); 433 $record->course = $course->id; 434 $record->userid = $useron->id; 435 $record->forum = $forumoptional->id; 436 $discussionoptional = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 437 438 // Allow force. 439 $CFG->forum_allowforcedreadtracking = 1; 440 441 $result = forum_tp_get_course_unread_posts($useron->id, $course->id); 442 $this->assertEquals(2, count($result)); 443 $this->assertEquals(false, isset($result[$forumoff->id])); 444 $this->assertEquals(true, isset($result[$forumforce->id])); 445 $this->assertEquals(2, $result[$forumforce->id]->unread); 446 $this->assertEquals(true, isset($result[$forumoptional->id])); 447 $this->assertEquals(1, $result[$forumoptional->id]->unread); 448 449 $result = forum_tp_get_course_unread_posts($useroff->id, $course->id); 450 $this->assertEquals(1, count($result)); 451 $this->assertEquals(false, isset($result[$forumoff->id])); 452 $this->assertEquals(true, isset($result[$forumforce->id])); 453 $this->assertEquals(2, $result[$forumforce->id]->unread); 454 $this->assertEquals(false, isset($result[$forumoptional->id])); 455 456 // Don't allow force. 457 $CFG->forum_allowforcedreadtracking = 0; 458 459 $result = forum_tp_get_course_unread_posts($useron->id, $course->id); 460 $this->assertEquals(2, count($result)); 461 $this->assertEquals(false, isset($result[$forumoff->id])); 462 $this->assertEquals(true, isset($result[$forumforce->id])); 463 $this->assertEquals(2, $result[$forumforce->id]->unread); 464 $this->assertEquals(true, isset($result[$forumoptional->id])); 465 $this->assertEquals(1, $result[$forumoptional->id]->unread); 466 467 $result = forum_tp_get_course_unread_posts($useroff->id, $course->id); 468 $this->assertEquals(0, count($result)); 469 $this->assertEquals(false, isset($result[$forumoff->id])); 470 $this->assertEquals(false, isset($result[$forumforce->id])); 471 $this->assertEquals(false, isset($result[$forumoptional->id])); 472 473 // Stop tracking so we can test again. 474 forum_tp_stop_tracking($forumforce->id, $useron->id); 475 forum_tp_stop_tracking($forumoptional->id, $useron->id); 476 forum_tp_stop_tracking($forumforce->id, $useroff->id); 477 forum_tp_stop_tracking($forumoptional->id, $useroff->id); 478 479 // Allow force. 480 $CFG->forum_allowforcedreadtracking = 1; 481 482 $result = forum_tp_get_course_unread_posts($useron->id, $course->id); 483 $this->assertEquals(1, count($result)); 484 $this->assertEquals(false, isset($result[$forumoff->id])); 485 $this->assertEquals(true, isset($result[$forumforce->id])); 486 $this->assertEquals(2, $result[$forumforce->id]->unread); 487 $this->assertEquals(false, isset($result[$forumoptional->id])); 488 489 $result = forum_tp_get_course_unread_posts($useroff->id, $course->id); 490 $this->assertEquals(1, count($result)); 491 $this->assertEquals(false, isset($result[$forumoff->id])); 492 $this->assertEquals(true, isset($result[$forumforce->id])); 493 $this->assertEquals(2, $result[$forumforce->id]->unread); 494 $this->assertEquals(false, isset($result[$forumoptional->id])); 495 496 // Don't allow force. 497 $CFG->forum_allowforcedreadtracking = 0; 498 499 $result = forum_tp_get_course_unread_posts($useron->id, $course->id); 500 $this->assertEquals(0, count($result)); 501 $this->assertEquals(false, isset($result[$forumoff->id])); 502 $this->assertEquals(false, isset($result[$forumforce->id])); 503 $this->assertEquals(false, isset($result[$forumoptional->id])); 504 505 $result = forum_tp_get_course_unread_posts($useroff->id, $course->id); 506 $this->assertEquals(0, count($result)); 507 $this->assertEquals(false, isset($result[$forumoff->id])); 508 $this->assertEquals(false, isset($result[$forumforce->id])); 509 $this->assertEquals(false, isset($result[$forumoptional->id])); 510 } 511 512 /** 513 * Test the logic in the forum_tp_get_course_unread_posts() function when private replies are present. 514 * 515 * @covers ::forum_tp_get_course_unread_posts 516 */ 517 public function test_forum_tp_get_course_unread_posts_with_private_replies() { 518 global $DB; 519 520 $this->resetAfterTest(); 521 522 $generator = $this->getDataGenerator(); 523 524 // Create 3 students. 525 $s1 = $generator->create_user(['trackforums' => 1]); 526 $s2 = $generator->create_user(['trackforums' => 1]); 527 $s3 = $generator->create_user(['trackforums' => 1]); 528 // Editing teacher. 529 $t1 = $generator->create_user(['trackforums' => 1]); 530 // Non-editing teacher. 531 $t2 = $generator->create_user(['trackforums' => 1]); 532 533 // Create our course. 534 $course = $generator->create_course(); 535 536 // Enrol editing and non-editing teachers. 537 $generator->enrol_user($t1->id, $course->id, 'editingteacher'); 538 $generator->enrol_user($t2->id, $course->id, 'teacher'); 539 540 // Create forums. 541 $forum1 = $generator->create_module('forum', ['course' => $course->id]); 542 $forum2 = $generator->create_module('forum', ['course' => $course->id]); 543 $forumgenerator = $generator->get_plugin_generator('mod_forum'); 544 545 // Prevent the non-editing teacher from reading private replies in forum 2. 546 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'teacher']); 547 $forum2cm = get_coursemodule_from_instance('forum', $forum2->id); 548 $forum2context = context_module::instance($forum2cm->id); 549 role_change_permission($teacherroleid, $forum2context, 'mod/forum:readprivatereplies', CAP_PREVENT); 550 551 // Create discussion by s1. 552 $discussiondata = (object)[ 553 'course' => $course->id, 554 'forum' => $forum1->id, 555 'userid' => $s1->id, 556 ]; 557 $discussion1 = $forumgenerator->create_discussion($discussiondata); 558 559 // Create discussion by s2. 560 $discussiondata->userid = $s2->id; 561 $discussion2 = $forumgenerator->create_discussion($discussiondata); 562 563 // Create discussion by s3. 564 $discussiondata->userid = $s3->id; 565 $discussion3 = $forumgenerator->create_discussion($discussiondata); 566 567 // Post a normal reply to s1's discussion in forum 1 as the editing teacher. 568 $replydata = (object)[ 569 'course' => $course->id, 570 'forum' => $forum1->id, 571 'discussion' => $discussion1->id, 572 'userid' => $t1->id, 573 ]; 574 $forumgenerator->create_post($replydata); 575 576 // Post a normal reply to s2's discussion as the editing teacher. 577 $replydata->discussion = $discussion2->id; 578 $forumgenerator->create_post($replydata); 579 580 // Post a normal reply to s3's discussion as the editing teacher. 581 $replydata->discussion = $discussion3->id; 582 $forumgenerator->create_post($replydata); 583 584 // Post a private reply to s1's discussion in forum 1 as the editing teacher. 585 $replydata->discussion = $discussion1->id; 586 $replydata->userid = $t1->id; 587 $replydata->privatereplyto = $s1->id; 588 $forumgenerator->create_post($replydata); 589 // Post another private reply to s1 as the teacher. 590 $forumgenerator->create_post($replydata); 591 592 // Post a private reply to s2's discussion as the editing teacher. 593 $replydata->discussion = $discussion2->id; 594 $replydata->privatereplyto = $s2->id; 595 $forumgenerator->create_post($replydata); 596 597 // Create discussion by s1 in forum 2. 598 $discussiondata->forum = $forum2->id; 599 $discussiondata->userid = $s1->id; 600 $discussion21 = $forumgenerator->create_discussion($discussiondata); 601 602 // Post a private reply to s1's discussion in forum 2 as the editing teacher. 603 $replydata->discussion = $discussion21->id; 604 $replydata->privatereplyto = $s1->id; 605 $forumgenerator->create_post($replydata); 606 607 // Let's count! 608 // S1 should see 8 unread posts 3 discussions posts + 2 private replies + 3 normal replies. 609 $result = forum_tp_get_course_unread_posts($s1->id, $course->id); 610 $unreadcounts = $result[$forum1->id]; 611 $this->assertEquals(8, $unreadcounts->unread); 612 613 // S2 should see 7 unread posts 3 discussions posts + 1 private reply + 3 normal replies. 614 $result = forum_tp_get_course_unread_posts($s2->id, $course->id); 615 $unreadcounts = $result[$forum1->id]; 616 $this->assertEquals(7, $unreadcounts->unread); 617 618 // S3 should see 6 unread posts 3 discussions posts + 3 normal replies. No private replies. 619 $result = forum_tp_get_course_unread_posts($s3->id, $course->id); 620 $unreadcounts = $result[$forum1->id]; 621 $this->assertEquals(6, $unreadcounts->unread); 622 623 // The editing teacher should see 9 unread posts in forum 1: 3 discussions posts + 3 normal replies + 3 private replies. 624 $result = forum_tp_get_course_unread_posts($t1->id, $course->id); 625 $unreadcounts = $result[$forum1->id]; 626 $this->assertEquals(9, $unreadcounts->unread); 627 628 // Same with the non-editing teacher, since they can read private replies by default. 629 $result = forum_tp_get_course_unread_posts($t2->id, $course->id); 630 $unreadcounts = $result[$forum1->id]; 631 $this->assertEquals(9, $unreadcounts->unread); 632 633 // But for forum 2, the non-editing teacher should only see 1 unread which is s1's discussion post. 634 $unreadcounts = $result[$forum2->id]; 635 $this->assertEquals(1, $unreadcounts->unread); 636 } 637 638 /** 639 * Test the logic in the forum_tp_count_forum_unread_posts() function when private replies are present but without 640 * separate group mode. This should yield the same results returned by forum_tp_get_course_unread_posts(). 641 * 642 * @covers ::forum_tp_count_forum_unread_posts 643 */ 644 public function test_forum_tp_count_forum_unread_posts_with_private_replies() { 645 global $DB; 646 647 $this->resetAfterTest(); 648 649 $generator = $this->getDataGenerator(); 650 651 // Create 3 students. 652 $s1 = $generator->create_user(['username' => 's1', 'trackforums' => 1]); 653 $s2 = $generator->create_user(['username' => 's2', 'trackforums' => 1]); 654 $s3 = $generator->create_user(['username' => 's3', 'trackforums' => 1]); 655 // Editing teacher. 656 $t1 = $generator->create_user(['username' => 't1', 'trackforums' => 1]); 657 // Non-editing teacher. 658 $t2 = $generator->create_user(['username' => 't2', 'trackforums' => 1]); 659 660 // Create our course. 661 $course = $generator->create_course(); 662 663 // Enrol editing and non-editing teachers. 664 $generator->enrol_user($t1->id, $course->id, 'editingteacher'); 665 $generator->enrol_user($t2->id, $course->id, 'teacher'); 666 667 // Create forums. 668 $forum1 = $generator->create_module('forum', ['course' => $course->id]); 669 $forum2 = $generator->create_module('forum', ['course' => $course->id]); 670 $forumgenerator = $generator->get_plugin_generator('mod_forum'); 671 672 // Prevent the non-editing teacher from reading private replies in forum 2. 673 $teacherroleid = $DB->get_field('role', 'id', ['shortname' => 'teacher']); 674 $forum2cm = get_coursemodule_from_instance('forum', $forum2->id); 675 $forum2context = context_module::instance($forum2cm->id); 676 role_change_permission($teacherroleid, $forum2context, 'mod/forum:readprivatereplies', CAP_PREVENT); 677 678 // Create discussion by s1. 679 $discussiondata = (object)[ 680 'course' => $course->id, 681 'forum' => $forum1->id, 682 'userid' => $s1->id, 683 ]; 684 $discussion1 = $forumgenerator->create_discussion($discussiondata); 685 686 // Create discussion by s2. 687 $discussiondata->userid = $s2->id; 688 $discussion2 = $forumgenerator->create_discussion($discussiondata); 689 690 // Create discussion by s3. 691 $discussiondata->userid = $s3->id; 692 $discussion3 = $forumgenerator->create_discussion($discussiondata); 693 694 // Post a normal reply to s1's discussion in forum 1 as the editing teacher. 695 $replydata = (object)[ 696 'course' => $course->id, 697 'forum' => $forum1->id, 698 'discussion' => $discussion1->id, 699 'userid' => $t1->id, 700 ]; 701 $forumgenerator->create_post($replydata); 702 703 // Post a normal reply to s2's discussion as the editing teacher. 704 $replydata->discussion = $discussion2->id; 705 $forumgenerator->create_post($replydata); 706 707 // Post a normal reply to s3's discussion as the editing teacher. 708 $replydata->discussion = $discussion3->id; 709 $forumgenerator->create_post($replydata); 710 711 // Post a private reply to s1's discussion in forum 1 as the editing teacher. 712 $replydata->discussion = $discussion1->id; 713 $replydata->userid = $t1->id; 714 $replydata->privatereplyto = $s1->id; 715 $forumgenerator->create_post($replydata); 716 // Post another private reply to s1 as the teacher. 717 $forumgenerator->create_post($replydata); 718 719 // Post a private reply to s2's discussion as the editing teacher. 720 $replydata->discussion = $discussion2->id; 721 $replydata->privatereplyto = $s2->id; 722 $forumgenerator->create_post($replydata); 723 724 // Create discussion by s1 in forum 2. 725 $discussiondata->forum = $forum2->id; 726 $discussiondata->userid = $s1->id; 727 $discussion11 = $forumgenerator->create_discussion($discussiondata); 728 729 // Post a private reply to s1's discussion in forum 2 as the editing teacher. 730 $replydata->discussion = $discussion11->id; 731 $replydata->privatereplyto = $s1->id; 732 $forumgenerator->create_post($replydata); 733 734 // Let's count! 735 // S1 should see 8 unread posts 3 discussions posts + 2 private replies + 3 normal replies. 736 $this->setUser($s1); 737 $forum1cm = get_coursemodule_from_instance('forum', $forum1->id); 738 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 739 $this->assertEquals(8, $result); 740 741 // S2 should see 7 unread posts 3 discussions posts + 1 private reply + 3 normal replies. 742 $this->setUser($s2); 743 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 744 $this->assertEquals(7, $result); 745 746 // S3 should see 6 unread posts 3 discussions posts + 3 normal replies. No private replies. 747 $this->setUser($s3); 748 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 749 $this->assertEquals(6, $result); 750 751 // The editing teacher should see 9 unread posts in forum 1: 3 discussions posts + 3 normal replies + 3 private replies. 752 $this->setUser($t1); 753 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 754 $this->assertEquals(9, $result); 755 756 // Same with the non-editing teacher, since they can read private replies by default. 757 $this->setUser($t2); 758 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 759 $this->assertEquals(9, $result); 760 761 // But for forum 2, the non-editing teacher should only see 1 unread which is s1's discussion post. 762 $result = forum_tp_count_forum_unread_posts($forum2cm, $course); 763 $this->assertEquals(1, $result); 764 } 765 766 /** 767 * Test the logic in the forum_tp_count_forum_unread_posts() function when private replies are present and group modes are set. 768 * 769 * @covers ::forum_tp_count_forum_unread_posts 770 */ 771 public function test_forum_tp_count_forum_unread_posts_with_private_replies_and_separate_groups() { 772 $this->resetAfterTest(); 773 774 $generator = $this->getDataGenerator(); 775 776 // Create 3 students. 777 $s1 = $generator->create_user(['username' => 's1', 'trackforums' => 1]); 778 $s2 = $generator->create_user(['username' => 's2', 'trackforums' => 1]); 779 // Editing teacher. 780 $t1 = $generator->create_user(['username' => 't1', 'trackforums' => 1]); 781 782 // Create our course. 783 $course = $generator->create_course(); 784 785 // Enrol students, editing and non-editing teachers. 786 $generator->enrol_user($s1->id, $course->id, 'student'); 787 $generator->enrol_user($s2->id, $course->id, 'student'); 788 $generator->enrol_user($t1->id, $course->id, 'editingteacher'); 789 790 // Create groups. 791 $g1 = $generator->create_group(['courseid' => $course->id]); 792 $g2 = $generator->create_group(['courseid' => $course->id]); 793 $generator->create_group_member(['groupid' => $g1->id, 'userid' => $s1->id]); 794 $generator->create_group_member(['groupid' => $g2->id, 'userid' => $s2->id]); 795 796 // Create forums. 797 $forum1 = $generator->create_module('forum', ['course' => $course->id, 'groupmode' => SEPARATEGROUPS]); 798 $forum2 = $generator->create_module('forum', ['course' => $course->id, 'groupmode' => VISIBLEGROUPS]); 799 $forumgenerator = $generator->get_plugin_generator('mod_forum'); 800 801 // Create discussion by s1. 802 $discussiondata = (object)[ 803 'course' => $course->id, 804 'forum' => $forum1->id, 805 'userid' => $s1->id, 806 'groupid' => $g1->id, 807 ]; 808 $discussion1 = $forumgenerator->create_discussion($discussiondata); 809 810 // Create discussion by s2. 811 $discussiondata->userid = $s2->id; 812 $discussiondata->groupid = $g2->id; 813 $discussion2 = $forumgenerator->create_discussion($discussiondata); 814 815 // Post a normal reply to s1's discussion in forum 1 as the editing teacher. 816 $replydata = (object)[ 817 'course' => $course->id, 818 'forum' => $forum1->id, 819 'discussion' => $discussion1->id, 820 'userid' => $t1->id, 821 ]; 822 $forumgenerator->create_post($replydata); 823 824 // Post a normal reply to s2's discussion as the editing teacher. 825 $replydata->discussion = $discussion2->id; 826 $forumgenerator->create_post($replydata); 827 828 // Post a private reply to s1's discussion in forum 1 as the editing teacher. 829 $replydata->discussion = $discussion1->id; 830 $replydata->userid = $t1->id; 831 $replydata->privatereplyto = $s1->id; 832 $forumgenerator->create_post($replydata); 833 // Post another private reply to s1 as the teacher. 834 $forumgenerator->create_post($replydata); 835 836 // Post a private reply to s2's discussion as the editing teacher. 837 $replydata->discussion = $discussion2->id; 838 $replydata->privatereplyto = $s2->id; 839 $forumgenerator->create_post($replydata); 840 841 // Create discussion by s1 in forum 2. 842 $discussiondata->forum = $forum2->id; 843 $discussiondata->userid = $s1->id; 844 $discussiondata->groupid = $g1->id; 845 $discussion21 = $forumgenerator->create_discussion($discussiondata); 846 847 // Post a private reply to s1's discussion in forum 2 as the editing teacher. 848 $replydata->discussion = $discussion21->id; 849 $replydata->privatereplyto = $s1->id; 850 $forumgenerator->create_post($replydata); 851 852 // Let's count! 853 // S1 should see 4 unread posts in forum 1 (1 discussions post + 2 private replies + 1 normal reply). 854 $this->setUser($s1); 855 $forum1cm = get_coursemodule_from_instance('forum', $forum1->id); 856 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 857 $this->assertEquals(4, $result); 858 859 // S2 should see 3 unread posts in forum 1 (1 discussions post + 1 private reply + 1 normal reply). 860 $this->setUser($s2); 861 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 862 $this->assertEquals(3, $result); 863 864 // S2 should see 1 unread posts in forum 2 (visible groups, 1 discussion post from s1). 865 $forum2cm = get_coursemodule_from_instance('forum', $forum2->id); 866 $result = forum_tp_count_forum_unread_posts($forum2cm, $course, true); 867 $this->assertEquals(1, $result); 868 869 // The editing teacher should still see 7 unread posts (2 discussions posts + 2 normal replies + 3 private replies) 870 // in forum 1 since they have the capability to view all groups by default. 871 $this->setUser($t1); 872 $result = forum_tp_count_forum_unread_posts($forum1cm, $course, true); 873 $this->assertEquals(7, $result); 874 } 875 876 /** 877 * Test the logic in the test_forum_tp_get_untracked_forums() function. 878 */ 879 public function test_forum_tp_get_untracked_forums() { 880 global $CFG; 881 882 $this->resetAfterTest(); 883 884 $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1)); 885 $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0)); 886 $course = $this->getDataGenerator()->create_course(); 887 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off. 888 $forumoff = $this->getDataGenerator()->create_module('forum', $options); 889 890 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On. 891 $forumforce = $this->getDataGenerator()->create_module('forum', $options); 892 893 $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional. 894 $forumoptional = $this->getDataGenerator()->create_module('forum', $options); 895 896 // Allow force. 897 $CFG->forum_allowforcedreadtracking = 1; 898 899 // On user with force on. 900 $result = forum_tp_get_untracked_forums($useron->id, $course->id); 901 $this->assertEquals(1, count($result)); 902 $this->assertEquals(true, isset($result[$forumoff->id])); 903 904 // Off user with force on. 905 $result = forum_tp_get_untracked_forums($useroff->id, $course->id); 906 $this->assertEquals(2, count($result)); 907 $this->assertEquals(true, isset($result[$forumoff->id])); 908 $this->assertEquals(true, isset($result[$forumoptional->id])); 909 910 // Don't allow force. 911 $CFG->forum_allowforcedreadtracking = 0; 912 913 // On user with force off. 914 $result = forum_tp_get_untracked_forums($useron->id, $course->id); 915 $this->assertEquals(1, count($result)); 916 $this->assertEquals(true, isset($result[$forumoff->id])); 917 918 // Off user with force off. 919 $result = forum_tp_get_untracked_forums($useroff->id, $course->id); 920 $this->assertEquals(3, count($result)); 921 $this->assertEquals(true, isset($result[$forumoff->id])); 922 $this->assertEquals(true, isset($result[$forumoptional->id])); 923 $this->assertEquals(true, isset($result[$forumforce->id])); 924 925 // Stop tracking so we can test again. 926 forum_tp_stop_tracking($forumforce->id, $useron->id); 927 forum_tp_stop_tracking($forumoptional->id, $useron->id); 928 forum_tp_stop_tracking($forumforce->id, $useroff->id); 929 forum_tp_stop_tracking($forumoptional->id, $useroff->id); 930 931 // Allow force. 932 $CFG->forum_allowforcedreadtracking = 1; 933 934 // On user with force on. 935 $result = forum_tp_get_untracked_forums($useron->id, $course->id); 936 $this->assertEquals(2, count($result)); 937 $this->assertEquals(true, isset($result[$forumoff->id])); 938 $this->assertEquals(true, isset($result[$forumoptional->id])); 939 940 // Off user with force on. 941 $result = forum_tp_get_untracked_forums($useroff->id, $course->id); 942 $this->assertEquals(2, count($result)); 943 $this->assertEquals(true, isset($result[$forumoff->id])); 944 $this->assertEquals(true, isset($result[$forumoptional->id])); 945 946 // Don't allow force. 947 $CFG->forum_allowforcedreadtracking = 0; 948 949 // On user with force off. 950 $result = forum_tp_get_untracked_forums($useron->id, $course->id); 951 $this->assertEquals(3, count($result)); 952 $this->assertEquals(true, isset($result[$forumoff->id])); 953 $this->assertEquals(true, isset($result[$forumoptional->id])); 954 $this->assertEquals(true, isset($result[$forumforce->id])); 955 956 // Off user with force off. 957 $result = forum_tp_get_untracked_forums($useroff->id, $course->id); 958 $this->assertEquals(3, count($result)); 959 $this->assertEquals(true, isset($result[$forumoff->id])); 960 $this->assertEquals(true, isset($result[$forumoptional->id])); 961 $this->assertEquals(true, isset($result[$forumforce->id])); 962 } 963 964 /** 965 * Test subscription using automatic subscription on create. 966 */ 967 public function test_forum_auto_subscribe_on_create() { 968 global $CFG; 969 970 $this->resetAfterTest(); 971 972 $usercount = 5; 973 $course = $this->getDataGenerator()->create_course(); 974 $users = array(); 975 976 for ($i = 0; $i < $usercount; $i++) { 977 $user = $this->getDataGenerator()->create_user(); 978 $users[] = $user; 979 $this->getDataGenerator()->enrol_user($user->id, $course->id); 980 } 981 982 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); // Automatic Subscription. 983 $forum = $this->getDataGenerator()->create_module('forum', $options); 984 985 $result = \mod_forum\subscriptions::fetch_subscribed_users($forum); 986 $this->assertEquals($usercount, count($result)); 987 foreach ($users as $user) { 988 $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum)); 989 } 990 } 991 992 /** 993 * Test subscription using forced subscription on create. 994 */ 995 public function test_forum_forced_subscribe_on_create() { 996 global $CFG; 997 998 $this->resetAfterTest(); 999 1000 $usercount = 5; 1001 $course = $this->getDataGenerator()->create_course(); 1002 $users = array(); 1003 1004 for ($i = 0; $i < $usercount; $i++) { 1005 $user = $this->getDataGenerator()->create_user(); 1006 $users[] = $user; 1007 $this->getDataGenerator()->enrol_user($user->id, $course->id); 1008 } 1009 1010 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); // Forced subscription. 1011 $forum = $this->getDataGenerator()->create_module('forum', $options); 1012 1013 $result = \mod_forum\subscriptions::fetch_subscribed_users($forum); 1014 $this->assertEquals($usercount, count($result)); 1015 foreach ($users as $user) { 1016 $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum)); 1017 } 1018 } 1019 1020 /** 1021 * Test subscription using optional subscription on create. 1022 */ 1023 public function test_forum_optional_subscribe_on_create() { 1024 global $CFG; 1025 1026 $this->resetAfterTest(); 1027 1028 $usercount = 5; 1029 $course = $this->getDataGenerator()->create_course(); 1030 $users = array(); 1031 1032 for ($i = 0; $i < $usercount; $i++) { 1033 $user = $this->getDataGenerator()->create_user(); 1034 $users[] = $user; 1035 $this->getDataGenerator()->enrol_user($user->id, $course->id); 1036 } 1037 1038 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); // Subscription optional. 1039 $forum = $this->getDataGenerator()->create_module('forum', $options); 1040 1041 $result = \mod_forum\subscriptions::fetch_subscribed_users($forum); 1042 // No subscriptions by default. 1043 $this->assertEquals(0, count($result)); 1044 foreach ($users as $user) { 1045 $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum)); 1046 } 1047 } 1048 1049 /** 1050 * Test subscription using disallow subscription on create. 1051 */ 1052 public function test_forum_disallow_subscribe_on_create() { 1053 global $CFG; 1054 1055 $this->resetAfterTest(); 1056 1057 $usercount = 5; 1058 $course = $this->getDataGenerator()->create_course(); 1059 $users = array(); 1060 1061 for ($i = 0; $i < $usercount; $i++) { 1062 $user = $this->getDataGenerator()->create_user(); 1063 $users[] = $user; 1064 $this->getDataGenerator()->enrol_user($user->id, $course->id); 1065 } 1066 1067 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); // Subscription prevented. 1068 $forum = $this->getDataGenerator()->create_module('forum', $options); 1069 1070 $result = \mod_forum\subscriptions::fetch_subscribed_users($forum); 1071 // No subscriptions by default. 1072 $this->assertEquals(0, count($result)); 1073 foreach ($users as $user) { 1074 $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum)); 1075 } 1076 } 1077 1078 /** 1079 * Test that context fetching returns the appropriate context. 1080 */ 1081 public function test_forum_get_context() { 1082 global $DB, $PAGE; 1083 1084 $this->resetAfterTest(); 1085 1086 // Setup test data. 1087 $course = $this->getDataGenerator()->create_course(); 1088 $coursecontext = \context_course::instance($course->id); 1089 1090 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 1091 $forum = $this->getDataGenerator()->create_module('forum', $options); 1092 $forumcm = get_coursemodule_from_instance('forum', $forum->id); 1093 $forumcontext = \context_module::instance($forumcm->id); 1094 1095 // First check that specifying the context results in the correct context being returned. 1096 // Do this before we set up the page object and we should return from the coursemodule record. 1097 // There should be no DB queries here because the context type was correct. 1098 $startcount = $DB->perf_get_reads(); 1099 $result = forum_get_context($forum->id, $forumcontext); 1100 $aftercount = $DB->perf_get_reads(); 1101 $this->assertEquals($forumcontext, $result); 1102 $this->assertEquals(0, $aftercount - $startcount); 1103 1104 // And a context which is not the correct type. 1105 // This tests will result in a DB query to fetch the course_module. 1106 $startcount = $DB->perf_get_reads(); 1107 $result = forum_get_context($forum->id, $coursecontext); 1108 $aftercount = $DB->perf_get_reads(); 1109 $this->assertEquals($forumcontext, $result); 1110 $this->assertEquals(1, $aftercount - $startcount); 1111 1112 // Now do not specify a context at all. 1113 // This tests will result in a DB query to fetch the course_module. 1114 $startcount = $DB->perf_get_reads(); 1115 $result = forum_get_context($forum->id); 1116 $aftercount = $DB->perf_get_reads(); 1117 $this->assertEquals($forumcontext, $result); 1118 $this->assertEquals(1, $aftercount - $startcount); 1119 1120 // Set up the default page event to use the forum. 1121 $PAGE = new moodle_page(); 1122 $PAGE->set_context($forumcontext); 1123 $PAGE->set_cm($forumcm, $course, $forum); 1124 1125 // Now specify a context which is not a context_module. 1126 // There should be no DB queries here because we use the PAGE. 1127 $startcount = $DB->perf_get_reads(); 1128 $result = forum_get_context($forum->id, $coursecontext); 1129 $aftercount = $DB->perf_get_reads(); 1130 $this->assertEquals($forumcontext, $result); 1131 $this->assertEquals(0, $aftercount - $startcount); 1132 1133 // Now do not specify a context at all. 1134 // There should be no DB queries here because we use the PAGE. 1135 $startcount = $DB->perf_get_reads(); 1136 $result = forum_get_context($forum->id); 1137 $aftercount = $DB->perf_get_reads(); 1138 $this->assertEquals($forumcontext, $result); 1139 $this->assertEquals(0, $aftercount - $startcount); 1140 1141 // Now specify the page context of the course instead.. 1142 $PAGE = new moodle_page(); 1143 $PAGE->set_context($coursecontext); 1144 1145 // Now specify a context which is not a context_module. 1146 // This tests will result in a DB query to fetch the course_module. 1147 $startcount = $DB->perf_get_reads(); 1148 $result = forum_get_context($forum->id, $coursecontext); 1149 $aftercount = $DB->perf_get_reads(); 1150 $this->assertEquals($forumcontext, $result); 1151 $this->assertEquals(1, $aftercount - $startcount); 1152 1153 // Now do not specify a context at all. 1154 // This tests will result in a DB query to fetch the course_module. 1155 $startcount = $DB->perf_get_reads(); 1156 $result = forum_get_context($forum->id); 1157 $aftercount = $DB->perf_get_reads(); 1158 $this->assertEquals($forumcontext, $result); 1159 $this->assertEquals(1, $aftercount - $startcount); 1160 } 1161 1162 /** 1163 * Test getting the neighbour threads of a discussion. 1164 */ 1165 public function test_forum_get_neighbours() { 1166 global $CFG, $DB; 1167 $this->resetAfterTest(); 1168 1169 $timenow = time(); 1170 $timenext = $timenow; 1171 1172 // Setup test data. 1173 $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 1174 $course = $this->getDataGenerator()->create_course(); 1175 $user = $this->getDataGenerator()->create_user(); 1176 $user2 = $this->getDataGenerator()->create_user(); 1177 1178 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 1179 $cm = get_coursemodule_from_instance('forum', $forum->id); 1180 $context = context_module::instance($cm->id); 1181 1182 $record = new stdClass(); 1183 $record->course = $course->id; 1184 $record->userid = $user->id; 1185 $record->forum = $forum->id; 1186 $record->timemodified = time(); 1187 $disc1 = $forumgen->create_discussion($record); 1188 $record->timemodified++; 1189 $disc2 = $forumgen->create_discussion($record); 1190 $record->timemodified++; 1191 $disc3 = $forumgen->create_discussion($record); 1192 $record->timemodified++; 1193 $disc4 = $forumgen->create_discussion($record); 1194 $record->timemodified++; 1195 $disc5 = $forumgen->create_discussion($record); 1196 1197 // Getting the neighbours. 1198 $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum); 1199 $this->assertEmpty($neighbours['prev']); 1200 $this->assertEquals($disc2->id, $neighbours['next']->id); 1201 1202 $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum); 1203 $this->assertEquals($disc1->id, $neighbours['prev']->id); 1204 $this->assertEquals($disc3->id, $neighbours['next']->id); 1205 1206 $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum); 1207 $this->assertEquals($disc2->id, $neighbours['prev']->id); 1208 $this->assertEquals($disc4->id, $neighbours['next']->id); 1209 1210 $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum); 1211 $this->assertEquals($disc3->id, $neighbours['prev']->id); 1212 $this->assertEquals($disc5->id, $neighbours['next']->id); 1213 1214 $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum); 1215 $this->assertEquals($disc4->id, $neighbours['prev']->id); 1216 $this->assertEmpty($neighbours['next']); 1217 1218 // Post in some discussions. We manually update the discussion record because 1219 // the data generator plays with timemodified in a way that would break this test. 1220 $record->timemodified++; 1221 $disc1->timemodified = $record->timemodified; 1222 $DB->update_record('forum_discussions', $disc1); 1223 1224 $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum); 1225 $this->assertEquals($disc4->id, $neighbours['prev']->id); 1226 $this->assertEquals($disc1->id, $neighbours['next']->id); 1227 1228 $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum); 1229 $this->assertEmpty($neighbours['prev']); 1230 $this->assertEquals($disc3->id, $neighbours['next']->id); 1231 1232 $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum); 1233 $this->assertEquals($disc5->id, $neighbours['prev']->id); 1234 $this->assertEmpty($neighbours['next']); 1235 1236 // After some discussions were created. 1237 $record->timemodified++; 1238 $disc6 = $forumgen->create_discussion($record); 1239 $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum); 1240 $this->assertEquals($disc1->id, $neighbours['prev']->id); 1241 $this->assertEmpty($neighbours['next']); 1242 1243 $record->timemodified++; 1244 $disc7 = $forumgen->create_discussion($record); 1245 $neighbours = forum_get_discussion_neighbours($cm, $disc7, $forum); 1246 $this->assertEquals($disc6->id, $neighbours['prev']->id); 1247 $this->assertEmpty($neighbours['next']); 1248 1249 // Adding timed discussions. 1250 $CFG->forum_enabletimedposts = true; 1251 $now = $record->timemodified; 1252 $past = $now - 600; 1253 $future = $now + 600; 1254 1255 $record = new stdClass(); 1256 $record->course = $course->id; 1257 $record->userid = $user->id; 1258 $record->forum = $forum->id; 1259 $record->timestart = $past; 1260 $record->timeend = $future; 1261 $record->timemodified = $now; 1262 $record->timemodified++; 1263 $disc8 = $forumgen->create_discussion($record); 1264 $record->timemodified++; 1265 $record->timestart = $future; 1266 $record->timeend = 0; 1267 $disc9 = $forumgen->create_discussion($record); 1268 $record->timemodified++; 1269 $record->timestart = 0; 1270 $record->timeend = 0; 1271 $disc10 = $forumgen->create_discussion($record); 1272 $record->timemodified++; 1273 $record->timestart = 0; 1274 $record->timeend = $past; 1275 $disc11 = $forumgen->create_discussion($record); 1276 $record->timemodified++; 1277 $record->timestart = $past; 1278 $record->timeend = $future; 1279 $disc12 = $forumgen->create_discussion($record); 1280 $record->timemodified++; 1281 $record->timestart = $future + 1; // Should be last post for those that can see it. 1282 $record->timeend = 0; 1283 $disc13 = $forumgen->create_discussion($record); 1284 1285 // Admin user ignores the timed settings of discussions. 1286 // Post ordering taking into account timestart: 1287 // 8 = t 1288 // 10 = t+3 1289 // 11 = t+4 1290 // 12 = t+5 1291 // 9 = t+60 1292 // 13 = t+61. 1293 $this->setAdminUser(); 1294 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1295 $this->assertEquals($disc7->id, $neighbours['prev']->id); 1296 $this->assertEquals($disc10->id, $neighbours['next']->id); 1297 1298 $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum); 1299 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1300 $this->assertEquals($disc13->id, $neighbours['next']->id); 1301 1302 $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum); 1303 $this->assertEquals($disc8->id, $neighbours['prev']->id); 1304 $this->assertEquals($disc11->id, $neighbours['next']->id); 1305 1306 $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum); 1307 $this->assertEquals($disc10->id, $neighbours['prev']->id); 1308 $this->assertEquals($disc12->id, $neighbours['next']->id); 1309 1310 $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum); 1311 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1312 $this->assertEquals($disc9->id, $neighbours['next']->id); 1313 1314 $neighbours = forum_get_discussion_neighbours($cm, $disc13, $forum); 1315 $this->assertEquals($disc9->id, $neighbours['prev']->id); 1316 $this->assertEmpty($neighbours['next']); 1317 1318 // Normal user can see their own timed discussions. 1319 $this->setUser($user); 1320 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1321 $this->assertEquals($disc7->id, $neighbours['prev']->id); 1322 $this->assertEquals($disc10->id, $neighbours['next']->id); 1323 1324 $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum); 1325 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1326 $this->assertEquals($disc13->id, $neighbours['next']->id); 1327 1328 $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum); 1329 $this->assertEquals($disc8->id, $neighbours['prev']->id); 1330 $this->assertEquals($disc11->id, $neighbours['next']->id); 1331 1332 $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum); 1333 $this->assertEquals($disc10->id, $neighbours['prev']->id); 1334 $this->assertEquals($disc12->id, $neighbours['next']->id); 1335 1336 $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum); 1337 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1338 $this->assertEquals($disc9->id, $neighbours['next']->id); 1339 1340 $neighbours = forum_get_discussion_neighbours($cm, $disc13, $forum); 1341 $this->assertEquals($disc9->id, $neighbours['prev']->id); 1342 $this->assertEmpty($neighbours['next']); 1343 1344 // Normal user does not ignore timed settings. 1345 $this->setUser($user2); 1346 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1347 $this->assertEquals($disc7->id, $neighbours['prev']->id); 1348 $this->assertEquals($disc10->id, $neighbours['next']->id); 1349 1350 $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum); 1351 $this->assertEquals($disc8->id, $neighbours['prev']->id); 1352 $this->assertEquals($disc12->id, $neighbours['next']->id); 1353 1354 $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum); 1355 $this->assertEquals($disc10->id, $neighbours['prev']->id); 1356 $this->assertEmpty($neighbours['next']); 1357 1358 // Reset to normal mode. 1359 $CFG->forum_enabletimedposts = false; 1360 $this->setAdminUser(); 1361 1362 // Two discussions with identical timemodified will sort by id. 1363 $record->timemodified += 25; 1364 $DB->update_record('forum_discussions', (object) array('id' => $disc3->id, 'timemodified' => $record->timemodified)); 1365 $DB->update_record('forum_discussions', (object) array('id' => $disc2->id, 'timemodified' => $record->timemodified)); 1366 $DB->update_record('forum_discussions', (object) array('id' => $disc12->id, 'timemodified' => $record->timemodified - 5)); 1367 $disc2 = $DB->get_record('forum_discussions', array('id' => $disc2->id)); 1368 $disc3 = $DB->get_record('forum_discussions', array('id' => $disc3->id)); 1369 1370 $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum); 1371 $this->assertEquals($disc2->id, $neighbours['prev']->id); 1372 $this->assertEmpty($neighbours['next']); 1373 1374 $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum); 1375 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1376 $this->assertEquals($disc3->id, $neighbours['next']->id); 1377 1378 // Set timemodified to not be identical. 1379 $DB->update_record('forum_discussions', (object) array('id' => $disc2->id, 'timemodified' => $record->timemodified - 1)); 1380 1381 // Test pinned posts behave correctly. 1382 $disc8->pinned = FORUM_DISCUSSION_PINNED; 1383 $DB->update_record('forum_discussions', (object) array('id' => $disc8->id, 'pinned' => $disc8->pinned)); 1384 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1385 $this->assertEquals($disc3->id, $neighbours['prev']->id); 1386 $this->assertEmpty($neighbours['next']); 1387 1388 $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum); 1389 $this->assertEquals($disc2->id, $neighbours['prev']->id); 1390 $this->assertEquals($disc8->id, $neighbours['next']->id); 1391 1392 // Test 3 pinned posts. 1393 $disc6->pinned = FORUM_DISCUSSION_PINNED; 1394 $DB->update_record('forum_discussions', (object) array('id' => $disc6->id, 'pinned' => $disc6->pinned)); 1395 $disc4->pinned = FORUM_DISCUSSION_PINNED; 1396 $DB->update_record('forum_discussions', (object) array('id' => $disc4->id, 'pinned' => $disc4->pinned)); 1397 1398 $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum); 1399 $this->assertEquals($disc4->id, $neighbours['prev']->id); 1400 $this->assertEquals($disc8->id, $neighbours['next']->id); 1401 1402 $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum); 1403 $this->assertEquals($disc3->id, $neighbours['prev']->id); 1404 $this->assertEquals($disc6->id, $neighbours['next']->id); 1405 1406 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1407 $this->assertEquals($disc6->id, $neighbours['prev']->id); 1408 $this->assertEmpty($neighbours['next']); 1409 } 1410 1411 /** 1412 * Test getting the neighbour threads of a blog-like forum. 1413 */ 1414 public function test_forum_get_neighbours_blog() { 1415 global $CFG, $DB; 1416 $this->resetAfterTest(); 1417 1418 $timenow = time(); 1419 $timenext = $timenow; 1420 1421 // Setup test data. 1422 $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 1423 $course = $this->getDataGenerator()->create_course(); 1424 $user = $this->getDataGenerator()->create_user(); 1425 $user2 = $this->getDataGenerator()->create_user(); 1426 1427 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog')); 1428 $cm = get_coursemodule_from_instance('forum', $forum->id); 1429 $context = context_module::instance($cm->id); 1430 1431 $record = new stdClass(); 1432 $record->course = $course->id; 1433 $record->userid = $user->id; 1434 $record->forum = $forum->id; 1435 $record->timemodified = time(); 1436 $disc1 = $forumgen->create_discussion($record); 1437 $record->timemodified++; 1438 $disc2 = $forumgen->create_discussion($record); 1439 $record->timemodified++; 1440 $disc3 = $forumgen->create_discussion($record); 1441 $record->timemodified++; 1442 $disc4 = $forumgen->create_discussion($record); 1443 $record->timemodified++; 1444 $disc5 = $forumgen->create_discussion($record); 1445 1446 // Getting the neighbours. 1447 $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum); 1448 $this->assertEmpty($neighbours['prev']); 1449 $this->assertEquals($disc2->id, $neighbours['next']->id); 1450 1451 $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum); 1452 $this->assertEquals($disc1->id, $neighbours['prev']->id); 1453 $this->assertEquals($disc3->id, $neighbours['next']->id); 1454 1455 $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum); 1456 $this->assertEquals($disc2->id, $neighbours['prev']->id); 1457 $this->assertEquals($disc4->id, $neighbours['next']->id); 1458 1459 $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum); 1460 $this->assertEquals($disc3->id, $neighbours['prev']->id); 1461 $this->assertEquals($disc5->id, $neighbours['next']->id); 1462 1463 $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum); 1464 $this->assertEquals($disc4->id, $neighbours['prev']->id); 1465 $this->assertEmpty($neighbours['next']); 1466 1467 // Make sure that the thread's timemodified does not affect the order. 1468 $record->timemodified++; 1469 $disc1->timemodified = $record->timemodified; 1470 $DB->update_record('forum_discussions', $disc1); 1471 1472 $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum); 1473 $this->assertEmpty($neighbours['prev']); 1474 $this->assertEquals($disc2->id, $neighbours['next']->id); 1475 1476 $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum); 1477 $this->assertEquals($disc1->id, $neighbours['prev']->id); 1478 $this->assertEquals($disc3->id, $neighbours['next']->id); 1479 1480 // Add another blog post. 1481 $record->timemodified++; 1482 $disc6 = $forumgen->create_discussion($record); 1483 $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum); 1484 $this->assertEquals($disc5->id, $neighbours['prev']->id); 1485 $this->assertEmpty($neighbours['next']); 1486 1487 $record->timemodified++; 1488 $disc7 = $forumgen->create_discussion($record); 1489 $neighbours = forum_get_discussion_neighbours($cm, $disc7, $forum); 1490 $this->assertEquals($disc6->id, $neighbours['prev']->id); 1491 $this->assertEmpty($neighbours['next']); 1492 1493 // Adding timed discussions. 1494 $CFG->forum_enabletimedposts = true; 1495 $now = $record->timemodified; 1496 $past = $now - 600; 1497 $future = $now + 600; 1498 1499 $record = new stdClass(); 1500 $record->course = $course->id; 1501 $record->userid = $user->id; 1502 $record->forum = $forum->id; 1503 $record->timestart = $past; 1504 $record->timeend = $future; 1505 $record->timemodified = $now; 1506 $record->timemodified++; 1507 $disc8 = $forumgen->create_discussion($record); 1508 $record->timemodified++; 1509 $record->timestart = $future; 1510 $record->timeend = 0; 1511 $disc9 = $forumgen->create_discussion($record); 1512 $record->timemodified++; 1513 $record->timestart = 0; 1514 $record->timeend = 0; 1515 $disc10 = $forumgen->create_discussion($record); 1516 $record->timemodified++; 1517 $record->timestart = 0; 1518 $record->timeend = $past; 1519 $disc11 = $forumgen->create_discussion($record); 1520 $record->timemodified++; 1521 $record->timestart = $past; 1522 $record->timeend = $future; 1523 $disc12 = $forumgen->create_discussion($record); 1524 1525 // Admin user ignores the timed settings of discussions. 1526 $this->setAdminUser(); 1527 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1528 $this->assertEquals($disc7->id, $neighbours['prev']->id); 1529 $this->assertEquals($disc9->id, $neighbours['next']->id); 1530 1531 $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum); 1532 $this->assertEquals($disc8->id, $neighbours['prev']->id); 1533 $this->assertEquals($disc10->id, $neighbours['next']->id); 1534 1535 $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum); 1536 $this->assertEquals($disc9->id, $neighbours['prev']->id); 1537 $this->assertEquals($disc11->id, $neighbours['next']->id); 1538 1539 $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum); 1540 $this->assertEquals($disc10->id, $neighbours['prev']->id); 1541 $this->assertEquals($disc12->id, $neighbours['next']->id); 1542 1543 $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum); 1544 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1545 $this->assertEmpty($neighbours['next']); 1546 1547 // Normal user can see their own timed discussions. 1548 $this->setUser($user); 1549 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1550 $this->assertEquals($disc7->id, $neighbours['prev']->id); 1551 $this->assertEquals($disc9->id, $neighbours['next']->id); 1552 1553 $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum); 1554 $this->assertEquals($disc8->id, $neighbours['prev']->id); 1555 $this->assertEquals($disc10->id, $neighbours['next']->id); 1556 1557 $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum); 1558 $this->assertEquals($disc9->id, $neighbours['prev']->id); 1559 $this->assertEquals($disc11->id, $neighbours['next']->id); 1560 1561 $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum); 1562 $this->assertEquals($disc10->id, $neighbours['prev']->id); 1563 $this->assertEquals($disc12->id, $neighbours['next']->id); 1564 1565 $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum); 1566 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1567 $this->assertEmpty($neighbours['next']); 1568 1569 // Normal user does not ignore timed settings. 1570 $this->setUser($user2); 1571 $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum); 1572 $this->assertEquals($disc7->id, $neighbours['prev']->id); 1573 $this->assertEquals($disc10->id, $neighbours['next']->id); 1574 1575 $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum); 1576 $this->assertEquals($disc8->id, $neighbours['prev']->id); 1577 $this->assertEquals($disc12->id, $neighbours['next']->id); 1578 1579 $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum); 1580 $this->assertEquals($disc10->id, $neighbours['prev']->id); 1581 $this->assertEmpty($neighbours['next']); 1582 1583 // Reset to normal mode. 1584 $CFG->forum_enabletimedposts = false; 1585 $this->setAdminUser(); 1586 1587 $record->timemodified++; 1588 // Two blog posts with identical creation time will sort by id. 1589 $DB->update_record('forum_posts', (object) array('id' => $disc2->firstpost, 'created' => $record->timemodified)); 1590 $DB->update_record('forum_posts', (object) array('id' => $disc3->firstpost, 'created' => $record->timemodified)); 1591 1592 $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum); 1593 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1594 $this->assertEquals($disc3->id, $neighbours['next']->id); 1595 1596 $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum); 1597 $this->assertEquals($disc2->id, $neighbours['prev']->id); 1598 $this->assertEmpty($neighbours['next']); 1599 } 1600 1601 /** 1602 * Test getting the neighbour threads of a discussion. 1603 */ 1604 public function test_forum_get_neighbours_with_groups() { 1605 $this->resetAfterTest(); 1606 1607 $timenow = time(); 1608 $timenext = $timenow; 1609 1610 // Setup test data. 1611 $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 1612 $course = $this->getDataGenerator()->create_course(); 1613 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 1614 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 1615 $user1 = $this->getDataGenerator()->create_user(); 1616 $user2 = $this->getDataGenerator()->create_user(); 1617 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 1618 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 1619 $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id)); 1620 1621 $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS)); 1622 $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS)); 1623 $cm1 = get_coursemodule_from_instance('forum', $forum1->id); 1624 $cm2 = get_coursemodule_from_instance('forum', $forum2->id); 1625 $context1 = context_module::instance($cm1->id); 1626 $context2 = context_module::instance($cm2->id); 1627 1628 // Creating discussions in both forums. 1629 $record = new stdClass(); 1630 $record->course = $course->id; 1631 $record->userid = $user1->id; 1632 $record->forum = $forum1->id; 1633 $record->groupid = $group1->id; 1634 $record->timemodified = time(); 1635 $disc11 = $forumgen->create_discussion($record); 1636 $record->forum = $forum2->id; 1637 $record->timemodified++; 1638 $disc21 = $forumgen->create_discussion($record); 1639 1640 $record->timemodified++; 1641 $record->userid = $user2->id; 1642 $record->forum = $forum1->id; 1643 $record->groupid = $group2->id; 1644 $disc12 = $forumgen->create_discussion($record); 1645 $record->forum = $forum2->id; 1646 $disc22 = $forumgen->create_discussion($record); 1647 1648 $record->timemodified++; 1649 $record->userid = $user1->id; 1650 $record->forum = $forum1->id; 1651 $record->groupid = null; 1652 $disc13 = $forumgen->create_discussion($record); 1653 $record->forum = $forum2->id; 1654 $disc23 = $forumgen->create_discussion($record); 1655 1656 $record->timemodified++; 1657 $record->userid = $user2->id; 1658 $record->forum = $forum1->id; 1659 $record->groupid = $group2->id; 1660 $disc14 = $forumgen->create_discussion($record); 1661 $record->forum = $forum2->id; 1662 $disc24 = $forumgen->create_discussion($record); 1663 1664 $record->timemodified++; 1665 $record->userid = $user1->id; 1666 $record->forum = $forum1->id; 1667 $record->groupid = $group1->id; 1668 $disc15 = $forumgen->create_discussion($record); 1669 $record->forum = $forum2->id; 1670 $disc25 = $forumgen->create_discussion($record); 1671 1672 // Admin user can see all groups. 1673 $this->setAdminUser(); 1674 $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1); 1675 $this->assertEmpty($neighbours['prev']); 1676 $this->assertEquals($disc12->id, $neighbours['next']->id); 1677 $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2); 1678 $this->assertEmpty($neighbours['prev']); 1679 $this->assertEquals($disc22->id, $neighbours['next']->id); 1680 1681 $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1); 1682 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1683 $this->assertEquals($disc13->id, $neighbours['next']->id); 1684 $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2); 1685 $this->assertEquals($disc21->id, $neighbours['prev']->id); 1686 $this->assertEquals($disc23->id, $neighbours['next']->id); 1687 1688 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1689 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1690 $this->assertEquals($disc14->id, $neighbours['next']->id); 1691 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1692 $this->assertEquals($disc22->id, $neighbours['prev']->id); 1693 $this->assertEquals($disc24->id, $neighbours['next']->id); 1694 1695 $neighbours = forum_get_discussion_neighbours($cm1, $disc14, $forum1); 1696 $this->assertEquals($disc13->id, $neighbours['prev']->id); 1697 $this->assertEquals($disc15->id, $neighbours['next']->id); 1698 $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2); 1699 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1700 $this->assertEquals($disc25->id, $neighbours['next']->id); 1701 1702 $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1); 1703 $this->assertEquals($disc14->id, $neighbours['prev']->id); 1704 $this->assertEmpty($neighbours['next']); 1705 $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2); 1706 $this->assertEquals($disc24->id, $neighbours['prev']->id); 1707 $this->assertEmpty($neighbours['next']); 1708 1709 // Admin user is only viewing group 1. 1710 $_POST['group'] = $group1->id; 1711 $this->assertEquals($group1->id, groups_get_activity_group($cm1, true)); 1712 $this->assertEquals($group1->id, groups_get_activity_group($cm2, true)); 1713 1714 $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1); 1715 $this->assertEmpty($neighbours['prev']); 1716 $this->assertEquals($disc13->id, $neighbours['next']->id); 1717 $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2); 1718 $this->assertEmpty($neighbours['prev']); 1719 $this->assertEquals($disc23->id, $neighbours['next']->id); 1720 1721 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1722 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1723 $this->assertEquals($disc15->id, $neighbours['next']->id); 1724 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1725 $this->assertEquals($disc21->id, $neighbours['prev']->id); 1726 $this->assertEquals($disc25->id, $neighbours['next']->id); 1727 1728 $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1); 1729 $this->assertEquals($disc13->id, $neighbours['prev']->id); 1730 $this->assertEmpty($neighbours['next']); 1731 $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2); 1732 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1733 $this->assertEmpty($neighbours['next']); 1734 1735 // Normal user viewing non-grouped posts (this is only possible in visible groups). 1736 $this->setUser($user1); 1737 $_POST['group'] = 0; 1738 $this->assertEquals(0, groups_get_activity_group($cm1, true)); 1739 1740 // They can see anything in visible groups. 1741 $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1); 1742 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1743 $this->assertEquals($disc13->id, $neighbours['next']->id); 1744 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1745 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1746 $this->assertEquals($disc14->id, $neighbours['next']->id); 1747 1748 // Normal user, orphan of groups, can only see non-grouped posts in separate groups. 1749 $this->setUser($user2); 1750 $_POST['group'] = 0; 1751 $this->assertEquals(0, groups_get_activity_group($cm2, true)); 1752 1753 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1754 $this->assertEmpty($neighbours['prev']); 1755 $this->assertEmpty($neighbours['next']); 1756 1757 $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2); 1758 $this->assertEmpty($neighbours['prev']); 1759 $this->assertEquals($disc23->id, $neighbours['next']->id); 1760 1761 $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2); 1762 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1763 $this->assertEmpty($neighbours['next']); 1764 1765 // Switching to viewing group 1. 1766 $this->setUser($user1); 1767 $_POST['group'] = $group1->id; 1768 $this->assertEquals($group1->id, groups_get_activity_group($cm1, true)); 1769 $this->assertEquals($group1->id, groups_get_activity_group($cm2, true)); 1770 1771 // They can see non-grouped or same group. 1772 $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1); 1773 $this->assertEmpty($neighbours['prev']); 1774 $this->assertEquals($disc13->id, $neighbours['next']->id); 1775 $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2); 1776 $this->assertEmpty($neighbours['prev']); 1777 $this->assertEquals($disc23->id, $neighbours['next']->id); 1778 1779 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1780 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1781 $this->assertEquals($disc15->id, $neighbours['next']->id); 1782 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1783 $this->assertEquals($disc21->id, $neighbours['prev']->id); 1784 $this->assertEquals($disc25->id, $neighbours['next']->id); 1785 1786 $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1); 1787 $this->assertEquals($disc13->id, $neighbours['prev']->id); 1788 $this->assertEmpty($neighbours['next']); 1789 $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2); 1790 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1791 $this->assertEmpty($neighbours['next']); 1792 1793 // Querying the neighbours of a discussion passing the wrong CM. 1794 $this->expectException('coding_exception'); 1795 forum_get_discussion_neighbours($cm2, $disc11, $forum2); 1796 } 1797 1798 /** 1799 * Test getting the neighbour threads of a blog-like forum with groups involved. 1800 */ 1801 public function test_forum_get_neighbours_with_groups_blog() { 1802 $this->resetAfterTest(); 1803 1804 $timenow = time(); 1805 $timenext = $timenow; 1806 1807 // Setup test data. 1808 $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 1809 $course = $this->getDataGenerator()->create_course(); 1810 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 1811 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 1812 $user1 = $this->getDataGenerator()->create_user(); 1813 $user2 = $this->getDataGenerator()->create_user(); 1814 $this->getDataGenerator()->enrol_user($user1->id, $course->id); 1815 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 1816 $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id)); 1817 1818 $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog', 1819 'groupmode' => VISIBLEGROUPS)); 1820 $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog', 1821 'groupmode' => SEPARATEGROUPS)); 1822 $cm1 = get_coursemodule_from_instance('forum', $forum1->id); 1823 $cm2 = get_coursemodule_from_instance('forum', $forum2->id); 1824 $context1 = context_module::instance($cm1->id); 1825 $context2 = context_module::instance($cm2->id); 1826 1827 // Creating blog posts in both forums. 1828 $record = new stdClass(); 1829 $record->course = $course->id; 1830 $record->userid = $user1->id; 1831 $record->forum = $forum1->id; 1832 $record->groupid = $group1->id; 1833 $record->timemodified = time(); 1834 $disc11 = $forumgen->create_discussion($record); 1835 $record->timenow = $timenext++; 1836 $record->forum = $forum2->id; 1837 $record->timemodified++; 1838 $disc21 = $forumgen->create_discussion($record); 1839 1840 $record->timemodified++; 1841 $record->userid = $user2->id; 1842 $record->forum = $forum1->id; 1843 $record->groupid = $group2->id; 1844 $disc12 = $forumgen->create_discussion($record); 1845 $record->forum = $forum2->id; 1846 $disc22 = $forumgen->create_discussion($record); 1847 1848 $record->timemodified++; 1849 $record->userid = $user1->id; 1850 $record->forum = $forum1->id; 1851 $record->groupid = null; 1852 $disc13 = $forumgen->create_discussion($record); 1853 $record->forum = $forum2->id; 1854 $disc23 = $forumgen->create_discussion($record); 1855 1856 $record->timemodified++; 1857 $record->userid = $user2->id; 1858 $record->forum = $forum1->id; 1859 $record->groupid = $group2->id; 1860 $disc14 = $forumgen->create_discussion($record); 1861 $record->forum = $forum2->id; 1862 $disc24 = $forumgen->create_discussion($record); 1863 1864 $record->timemodified++; 1865 $record->userid = $user1->id; 1866 $record->forum = $forum1->id; 1867 $record->groupid = $group1->id; 1868 $disc15 = $forumgen->create_discussion($record); 1869 $record->forum = $forum2->id; 1870 $disc25 = $forumgen->create_discussion($record); 1871 1872 // Admin user can see all groups. 1873 $this->setAdminUser(); 1874 $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1); 1875 $this->assertEmpty($neighbours['prev']); 1876 $this->assertEquals($disc12->id, $neighbours['next']->id); 1877 $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2); 1878 $this->assertEmpty($neighbours['prev']); 1879 $this->assertEquals($disc22->id, $neighbours['next']->id); 1880 1881 $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1); 1882 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1883 $this->assertEquals($disc13->id, $neighbours['next']->id); 1884 $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2); 1885 $this->assertEquals($disc21->id, $neighbours['prev']->id); 1886 $this->assertEquals($disc23->id, $neighbours['next']->id); 1887 1888 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1889 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1890 $this->assertEquals($disc14->id, $neighbours['next']->id); 1891 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1892 $this->assertEquals($disc22->id, $neighbours['prev']->id); 1893 $this->assertEquals($disc24->id, $neighbours['next']->id); 1894 1895 $neighbours = forum_get_discussion_neighbours($cm1, $disc14, $forum1); 1896 $this->assertEquals($disc13->id, $neighbours['prev']->id); 1897 $this->assertEquals($disc15->id, $neighbours['next']->id); 1898 $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2); 1899 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1900 $this->assertEquals($disc25->id, $neighbours['next']->id); 1901 1902 $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1); 1903 $this->assertEquals($disc14->id, $neighbours['prev']->id); 1904 $this->assertEmpty($neighbours['next']); 1905 $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2); 1906 $this->assertEquals($disc24->id, $neighbours['prev']->id); 1907 $this->assertEmpty($neighbours['next']); 1908 1909 // Admin user is only viewing group 1. 1910 $_POST['group'] = $group1->id; 1911 $this->assertEquals($group1->id, groups_get_activity_group($cm1, true)); 1912 $this->assertEquals($group1->id, groups_get_activity_group($cm2, true)); 1913 1914 $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1); 1915 $this->assertEmpty($neighbours['prev']); 1916 $this->assertEquals($disc13->id, $neighbours['next']->id); 1917 $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2); 1918 $this->assertEmpty($neighbours['prev']); 1919 $this->assertEquals($disc23->id, $neighbours['next']->id); 1920 1921 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1922 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1923 $this->assertEquals($disc15->id, $neighbours['next']->id); 1924 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1925 $this->assertEquals($disc21->id, $neighbours['prev']->id); 1926 $this->assertEquals($disc25->id, $neighbours['next']->id); 1927 1928 $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1); 1929 $this->assertEquals($disc13->id, $neighbours['prev']->id); 1930 $this->assertEmpty($neighbours['next']); 1931 $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2); 1932 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1933 $this->assertEmpty($neighbours['next']); 1934 1935 // Normal user viewing non-grouped posts (this is only possible in visible groups). 1936 $this->setUser($user1); 1937 $_POST['group'] = 0; 1938 $this->assertEquals(0, groups_get_activity_group($cm1, true)); 1939 1940 // They can see anything in visible groups. 1941 $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1); 1942 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1943 $this->assertEquals($disc13->id, $neighbours['next']->id); 1944 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1945 $this->assertEquals($disc12->id, $neighbours['prev']->id); 1946 $this->assertEquals($disc14->id, $neighbours['next']->id); 1947 1948 // Normal user, orphan of groups, can only see non-grouped posts in separate groups. 1949 $this->setUser($user2); 1950 $_POST['group'] = 0; 1951 $this->assertEquals(0, groups_get_activity_group($cm2, true)); 1952 1953 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1954 $this->assertEmpty($neighbours['prev']); 1955 $this->assertEmpty($neighbours['next']); 1956 1957 $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2); 1958 $this->assertEmpty($neighbours['prev']); 1959 $this->assertEquals($disc23->id, $neighbours['next']->id); 1960 1961 $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2); 1962 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1963 $this->assertEmpty($neighbours['next']); 1964 1965 // Switching to viewing group 1. 1966 $this->setUser($user1); 1967 $_POST['group'] = $group1->id; 1968 $this->assertEquals($group1->id, groups_get_activity_group($cm1, true)); 1969 $this->assertEquals($group1->id, groups_get_activity_group($cm2, true)); 1970 1971 // They can see non-grouped or same group. 1972 $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1); 1973 $this->assertEmpty($neighbours['prev']); 1974 $this->assertEquals($disc13->id, $neighbours['next']->id); 1975 $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2); 1976 $this->assertEmpty($neighbours['prev']); 1977 $this->assertEquals($disc23->id, $neighbours['next']->id); 1978 1979 $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1); 1980 $this->assertEquals($disc11->id, $neighbours['prev']->id); 1981 $this->assertEquals($disc15->id, $neighbours['next']->id); 1982 $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2); 1983 $this->assertEquals($disc21->id, $neighbours['prev']->id); 1984 $this->assertEquals($disc25->id, $neighbours['next']->id); 1985 1986 $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1); 1987 $this->assertEquals($disc13->id, $neighbours['prev']->id); 1988 $this->assertEmpty($neighbours['next']); 1989 $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2); 1990 $this->assertEquals($disc23->id, $neighbours['prev']->id); 1991 $this->assertEmpty($neighbours['next']); 1992 1993 // Querying the neighbours of a discussion passing the wrong CM. 1994 $this->expectException('coding_exception'); 1995 forum_get_discussion_neighbours($cm2, $disc11, $forum2); 1996 } 1997 1998 public function test_count_discussion_replies_basic() { 1999 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2000 2001 // Count the discussion replies in the forum. 2002 $result = forum_count_discussion_replies($forum->id); 2003 $this->assertCount(10, $result); 2004 } 2005 2006 public function test_count_discussion_replies_limited() { 2007 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2008 // Adding limits shouldn't make a difference. 2009 $result = forum_count_discussion_replies($forum->id, "", 20); 2010 $this->assertCount(10, $result); 2011 } 2012 2013 public function test_count_discussion_replies_paginated() { 2014 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2015 // Adding paging shouldn't make any difference. 2016 $result = forum_count_discussion_replies($forum->id, "", -1, 0, 100); 2017 $this->assertCount(10, $result); 2018 } 2019 2020 public function test_count_discussion_replies_paginated_sorted() { 2021 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2022 // Specifying the forumsort should also give a good result. This follows a different path. 2023 $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 100); 2024 $this->assertCount(10, $result); 2025 foreach ($result as $row) { 2026 // Grab the first discussionid. 2027 $discussionid = array_shift($discussionids); 2028 $this->assertEquals($discussionid, $row->discussion); 2029 } 2030 } 2031 2032 public function test_count_discussion_replies_limited_sorted() { 2033 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2034 // Adding limits, and a forumsort shouldn't make a difference. 2035 $result = forum_count_discussion_replies($forum->id, "d.id asc", 20); 2036 $this->assertCount(10, $result); 2037 foreach ($result as $row) { 2038 // Grab the first discussionid. 2039 $discussionid = array_shift($discussionids); 2040 $this->assertEquals($discussionid, $row->discussion); 2041 } 2042 } 2043 2044 public function test_count_discussion_replies_paginated_sorted_small() { 2045 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2046 // Grabbing a smaller subset and they should be ordered as expected. 2047 $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 5); 2048 $this->assertCount(5, $result); 2049 foreach ($result as $row) { 2050 // Grab the first discussionid. 2051 $discussionid = array_shift($discussionids); 2052 $this->assertEquals($discussionid, $row->discussion); 2053 } 2054 } 2055 2056 public function test_count_discussion_replies_paginated_sorted_small_reverse() { 2057 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2058 // Grabbing a smaller subset and they should be ordered as expected. 2059 $result = forum_count_discussion_replies($forum->id, "d.id desc", -1, 0, 5); 2060 $this->assertCount(5, $result); 2061 foreach ($result as $row) { 2062 // Grab the last discussionid. 2063 $discussionid = array_pop($discussionids); 2064 $this->assertEquals($discussionid, $row->discussion); 2065 } 2066 } 2067 2068 public function test_count_discussion_replies_limited_sorted_small_reverse() { 2069 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2070 // Adding limits, and a forumsort shouldn't make a difference. 2071 $result = forum_count_discussion_replies($forum->id, "d.id desc", 5); 2072 $this->assertCount(5, $result); 2073 foreach ($result as $row) { 2074 // Grab the last discussionid. 2075 $discussionid = array_pop($discussionids); 2076 $this->assertEquals($discussionid, $row->discussion); 2077 } 2078 } 2079 2080 /** 2081 * Test the reply count when used with private replies. 2082 */ 2083 public function test_forum_count_discussion_replies_private() { 2084 global $DB; 2085 $this->resetAfterTest(); 2086 2087 $course = $this->getDataGenerator()->create_course(); 2088 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 2089 $context = context_module::instance($forum->cmid); 2090 $cm = get_coursemodule_from_instance('forum', $forum->id); 2091 2092 $student = $this->getDataGenerator()->create_user(); 2093 $this->getDataGenerator()->enrol_user($student->id, $course->id); 2094 2095 $teacher = $this->getDataGenerator()->create_user(); 2096 $this->getDataGenerator()->enrol_user($teacher->id, $course->id); 2097 2098 $privilegeduser = $this->getDataGenerator()->create_user(); 2099 $this->getDataGenerator()->enrol_user($privilegeduser->id, $course->id, 'editingteacher'); 2100 2101 $otheruser = $this->getDataGenerator()->create_user(); 2102 $this->getDataGenerator()->enrol_user($otheruser->id, $course->id); 2103 2104 $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 2105 2106 // Create a discussion with some replies. 2107 $record = new stdClass(); 2108 $record->course = $forum->course; 2109 $record->forum = $forum->id; 2110 $record->userid = $student->id; 2111 $discussion = $generator->create_discussion($record); 2112 $replycount = 5; 2113 $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id)); 2114 2115 // Create a couple of standard replies. 2116 $post = new stdClass(); 2117 $post->userid = $student->id; 2118 $post->discussion = $discussion->id; 2119 $post->parent = $replyto->id; 2120 2121 for ($i = 0; $i < $replycount; $i++) { 2122 $post = $generator->create_post($post); 2123 } 2124 2125 // Create a private reply post from the teacher back to the student. 2126 $reply = new stdClass(); 2127 $reply->userid = $teacher->id; 2128 $reply->discussion = $discussion->id; 2129 $reply->parent = $replyto->id; 2130 $reply->privatereplyto = $replyto->userid; 2131 $generator->create_post($reply); 2132 2133 // The user is the author of the private reply. 2134 $this->setUser($teacher->id); 2135 $counts = forum_count_discussion_replies($forum->id); 2136 $this->assertEquals($replycount + 1, $counts[$discussion->id]->replies); 2137 2138 // The user is the intended recipient. 2139 $this->setUser($student->id); 2140 $counts = forum_count_discussion_replies($forum->id); 2141 $this->assertEquals($replycount + 1, $counts[$discussion->id]->replies); 2142 2143 // The user is not the author or recipient, but does have the readprivatereplies capability. 2144 $this->setUser($privilegeduser->id); 2145 $counts = forum_count_discussion_replies($forum->id, "", -1, -1, 0, true); 2146 $this->assertEquals($replycount + 1, $counts[$discussion->id]->replies); 2147 2148 // The user is not allowed to view this post. 2149 $this->setUser($otheruser->id); 2150 $counts = forum_count_discussion_replies($forum->id); 2151 $this->assertEquals($replycount, $counts[$discussion->id]->replies); 2152 } 2153 2154 public function test_discussion_pinned_sort() { 2155 list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5); 2156 $cm = get_coursemodule_from_instance('forum', $forum->id); 2157 $discussions = forum_get_discussions($cm); 2158 // First discussion should be pinned. 2159 $first = reset($discussions); 2160 $this->assertEquals(1, $first->pinned, "First discussion should be pinned discussion"); 2161 } 2162 public function test_forum_view() { 2163 global $CFG; 2164 2165 $CFG->enablecompletion = 1; 2166 $this->resetAfterTest(); 2167 2168 // Setup test data. 2169 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 2170 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), 2171 array('completion' => 2, 'completionview' => 1)); 2172 $context = context_module::instance($forum->cmid); 2173 $cm = get_coursemodule_from_instance('forum', $forum->id); 2174 2175 // Trigger and capture the event. 2176 $sink = $this->redirectEvents(); 2177 2178 $this->setAdminUser(); 2179 forum_view($forum, $course, $cm, $context); 2180 2181 $events = $sink->get_events(); 2182 // 2 additional events thanks to completion. 2183 $this->assertCount(3, $events); 2184 $event = array_pop($events); 2185 2186 // Checking that the event contains the expected values. 2187 $this->assertInstanceOf('\mod_forum\event\course_module_viewed', $event); 2188 $this->assertEquals($context, $event->get_context()); 2189 $url = new \moodle_url('/mod/forum/view.php', array('f' => $forum->id)); 2190 $this->assertEquals($url, $event->get_url()); 2191 $this->assertEventContextNotUsed($event); 2192 $this->assertNotEmpty($event->get_name()); 2193 2194 // Check completion status. 2195 $completion = new completion_info($course); 2196 $completiondata = $completion->get_data($cm); 2197 $this->assertEquals(1, $completiondata->completionstate); 2198 2199 } 2200 2201 /** 2202 * Test forum_discussion_view. 2203 */ 2204 public function test_forum_discussion_view() { 2205 global $CFG, $USER; 2206 2207 $this->resetAfterTest(); 2208 2209 // Setup test data. 2210 $course = $this->getDataGenerator()->create_course(); 2211 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 2212 $discussion = $this->create_single_discussion_with_replies($forum, $USER, 2); 2213 2214 $context = context_module::instance($forum->cmid); 2215 $cm = get_coursemodule_from_instance('forum', $forum->id); 2216 2217 // Trigger and capture the event. 2218 $sink = $this->redirectEvents(); 2219 2220 $this->setAdminUser(); 2221 forum_discussion_view($context, $forum, $discussion); 2222 2223 $events = $sink->get_events(); 2224 $this->assertCount(1, $events); 2225 $event = array_pop($events); 2226 2227 // Checking that the event contains the expected values. 2228 $this->assertInstanceOf('\mod_forum\event\discussion_viewed', $event); 2229 $this->assertEquals($context, $event->get_context()); 2230 $expected = array($course->id, 'forum', 'view discussion', "discuss.php?d={$discussion->id}", 2231 $discussion->id, $forum->cmid); 2232 $this->assertEventLegacyLogData($expected, $event); 2233 $this->assertEventContextNotUsed($event); 2234 2235 $this->assertNotEmpty($event->get_name()); 2236 2237 } 2238 2239 /** 2240 * Create a new course, forum, and user with a number of discussions and replies. 2241 * 2242 * @param int $discussioncount The number of discussions to create 2243 * @param int $replycount The number of replies to create in each discussion 2244 * @return array Containing the created forum object, and the ids of the created discussions. 2245 */ 2246 protected function create_multiple_discussions_with_replies($discussioncount, $replycount) { 2247 $this->resetAfterTest(); 2248 2249 // Setup the content. 2250 $user = $this->getDataGenerator()->create_user(); 2251 $course = $this->getDataGenerator()->create_course(); 2252 $record = new stdClass(); 2253 $record->course = $course->id; 2254 $forum = $this->getDataGenerator()->create_module('forum', $record); 2255 2256 // Create 10 discussions with replies. 2257 $discussionids = array(); 2258 for ($i = 0; $i < $discussioncount; $i++) { 2259 // Pin 3rd discussion. 2260 if ($i == 3) { 2261 $discussion = $this->create_single_discussion_pinned_with_replies($forum, $user, $replycount); 2262 } else { 2263 $discussion = $this->create_single_discussion_with_replies($forum, $user, $replycount); 2264 } 2265 2266 $discussionids[] = $discussion->id; 2267 } 2268 return array($forum, $discussionids); 2269 } 2270 2271 /** 2272 * Create a discussion with a number of replies. 2273 * 2274 * @param object $forum The forum which has been created 2275 * @param object $user The user making the discussion and replies 2276 * @param int $replycount The number of replies 2277 * @return object $discussion 2278 */ 2279 protected function create_single_discussion_with_replies($forum, $user, $replycount) { 2280 global $DB; 2281 2282 $generator = self::getDataGenerator()->get_plugin_generator('mod_forum'); 2283 2284 $record = new stdClass(); 2285 $record->course = $forum->course; 2286 $record->forum = $forum->id; 2287 $record->userid = $user->id; 2288 $discussion = $generator->create_discussion($record); 2289 2290 // Retrieve the first post. 2291 $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id)); 2292 2293 // Create the replies. 2294 $post = new stdClass(); 2295 $post->userid = $user->id; 2296 $post->discussion = $discussion->id; 2297 $post->parent = $replyto->id; 2298 2299 for ($i = 0; $i < $replycount; $i++) { 2300 $generator->create_post($post); 2301 } 2302 2303 return $discussion; 2304 } 2305 /** 2306 * Create a discussion with a number of replies. 2307 * 2308 * @param object $forum The forum which has been created 2309 * @param object $user The user making the discussion and replies 2310 * @param int $replycount The number of replies 2311 * @return object $discussion 2312 */ 2313 protected function create_single_discussion_pinned_with_replies($forum, $user, $replycount) { 2314 global $DB; 2315 2316 $generator = self::getDataGenerator()->get_plugin_generator('mod_forum'); 2317 2318 $record = new stdClass(); 2319 $record->course = $forum->course; 2320 $record->forum = $forum->id; 2321 $record->userid = $user->id; 2322 $record->pinned = FORUM_DISCUSSION_PINNED; 2323 $discussion = $generator->create_discussion($record); 2324 2325 // Retrieve the first post. 2326 $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id)); 2327 2328 // Create the replies. 2329 $post = new stdClass(); 2330 $post->userid = $user->id; 2331 $post->discussion = $discussion->id; 2332 $post->parent = $replyto->id; 2333 2334 for ($i = 0; $i < $replycount; $i++) { 2335 $generator->create_post($post); 2336 } 2337 2338 return $discussion; 2339 } 2340 2341 /** 2342 * Tests for mod_forum_rating_can_see_item_ratings(). 2343 * 2344 * @throws coding_exception 2345 * @throws rating_exception 2346 */ 2347 public function test_mod_forum_rating_can_see_item_ratings() { 2348 global $DB; 2349 2350 $this->resetAfterTest(); 2351 2352 // Setup test data. 2353 $course = new stdClass(); 2354 $course->groupmode = SEPARATEGROUPS; 2355 $course->groupmodeforce = true; 2356 $course = $this->getDataGenerator()->create_course($course); 2357 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 2358 $generator = self::getDataGenerator()->get_plugin_generator('mod_forum'); 2359 $cm = get_coursemodule_from_instance('forum', $forum->id); 2360 $context = context_module::instance($cm->id); 2361 2362 // Create users. 2363 $user1 = $this->getDataGenerator()->create_user(); 2364 $user2 = $this->getDataGenerator()->create_user(); 2365 $user3 = $this->getDataGenerator()->create_user(); 2366 $user4 = $this->getDataGenerator()->create_user(); 2367 2368 // Groups and stuff. 2369 $role = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); 2370 $this->getDataGenerator()->enrol_user($user1->id, $course->id, $role->id); 2371 $this->getDataGenerator()->enrol_user($user2->id, $course->id, $role->id); 2372 $this->getDataGenerator()->enrol_user($user3->id, $course->id, $role->id); 2373 $this->getDataGenerator()->enrol_user($user4->id, $course->id, $role->id); 2374 2375 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2376 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2377 groups_add_member($group1, $user1); 2378 groups_add_member($group1, $user2); 2379 groups_add_member($group2, $user3); 2380 groups_add_member($group2, $user4); 2381 2382 $record = new stdClass(); 2383 $record->course = $forum->course; 2384 $record->forum = $forum->id; 2385 $record->userid = $user1->id; 2386 $record->groupid = $group1->id; 2387 $discussion = $generator->create_discussion($record); 2388 2389 // Retrieve the first post. 2390 $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id)); 2391 2392 $ratingoptions = new stdClass; 2393 $ratingoptions->context = $context; 2394 $ratingoptions->ratingarea = 'post'; 2395 $ratingoptions->component = 'mod_forum'; 2396 $ratingoptions->itemid = $post->id; 2397 $ratingoptions->scaleid = 2; 2398 $ratingoptions->userid = $user2->id; 2399 $rating = new rating($ratingoptions); 2400 $rating->update_rating(2); 2401 2402 // Now try to access it as various users. 2403 unassign_capability('moodle/site:accessallgroups', $role->id); 2404 $params = array('contextid' => 2, 2405 'component' => 'mod_forum', 2406 'ratingarea' => 'post', 2407 'itemid' => $post->id, 2408 'scaleid' => 2); 2409 $this->setUser($user1); 2410 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2411 $this->setUser($user2); 2412 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2413 $this->setUser($user3); 2414 $this->assertFalse(mod_forum_rating_can_see_item_ratings($params)); 2415 $this->setUser($user4); 2416 $this->assertFalse(mod_forum_rating_can_see_item_ratings($params)); 2417 2418 // Now try with accessallgroups cap and make sure everything is visible. 2419 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $role->id, $context->id); 2420 $this->setUser($user1); 2421 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2422 $this->setUser($user2); 2423 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2424 $this->setUser($user3); 2425 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2426 $this->setUser($user4); 2427 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2428 2429 // Change group mode and verify visibility. 2430 $course->groupmode = VISIBLEGROUPS; 2431 $DB->update_record('course', $course); 2432 unassign_capability('moodle/site:accessallgroups', $role->id); 2433 $this->setUser($user1); 2434 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2435 $this->setUser($user2); 2436 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2437 $this->setUser($user3); 2438 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2439 $this->setUser($user4); 2440 $this->assertTrue(mod_forum_rating_can_see_item_ratings($params)); 2441 2442 } 2443 2444 /** 2445 * Test forum_get_discussions 2446 */ 2447 public function test_forum_get_discussions_with_groups() { 2448 global $DB; 2449 2450 $this->resetAfterTest(true); 2451 2452 // Create course to add the module. 2453 $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0)); 2454 $user1 = self::getDataGenerator()->create_user(); 2455 $user2 = self::getDataGenerator()->create_user(); 2456 $user3 = self::getDataGenerator()->create_user(); 2457 2458 $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST); 2459 self::getDataGenerator()->enrol_user($user1->id, $course->id, $role->id); 2460 self::getDataGenerator()->enrol_user($user2->id, $course->id, $role->id); 2461 self::getDataGenerator()->enrol_user($user3->id, $course->id, $role->id); 2462 2463 // Forum forcing separate gropus. 2464 $record = new stdClass(); 2465 $record->course = $course->id; 2466 $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS)); 2467 $cm = get_coursemodule_from_instance('forum', $forum->id); 2468 2469 // Create groups. 2470 $group1 = self::getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'group1')); 2471 $group2 = self::getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'group2')); 2472 $group3 = self::getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'group3')); 2473 2474 // Add the user1 to g1 and g2 groups. 2475 groups_add_member($group1->id, $user1->id); 2476 groups_add_member($group2->id, $user1->id); 2477 2478 // Add the user 2 and 3 to only one group. 2479 groups_add_member($group1->id, $user2->id); 2480 groups_add_member($group3->id, $user3->id); 2481 2482 // Add a few discussions. 2483 $record = array(); 2484 $record['course'] = $course->id; 2485 $record['forum'] = $forum->id; 2486 $record['userid'] = $user1->id; 2487 $record['groupid'] = $group1->id; 2488 $discussiong1u1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2489 2490 $record['groupid'] = $group2->id; 2491 $discussiong2u1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2492 2493 $record['userid'] = $user2->id; 2494 $record['groupid'] = $group1->id; 2495 $discussiong1u2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2496 2497 $record['userid'] = $user3->id; 2498 $record['groupid'] = $group3->id; 2499 $discussiong3u3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2500 2501 self::setUser($user1); 2502 2503 // Test retrieve discussions not passing the groupid parameter. We will receive only first group discussions. 2504 $discussions = forum_get_discussions($cm); 2505 self::assertCount(2, $discussions); 2506 foreach ($discussions as $discussion) { 2507 self::assertEquals($group1->id, $discussion->groupid); 2508 } 2509 2510 // Get all my discussions. 2511 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, 0); 2512 self::assertCount(3, $discussions); 2513 2514 // Get all my g1 discussions. 2515 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group1->id); 2516 self::assertCount(2, $discussions); 2517 foreach ($discussions as $discussion) { 2518 self::assertEquals($group1->id, $discussion->groupid); 2519 } 2520 2521 // Get all my g2 discussions. 2522 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group2->id); 2523 self::assertCount(1, $discussions); 2524 $discussion = array_shift($discussions); 2525 self::assertEquals($group2->id, $discussion->groupid); 2526 self::assertEquals($user1->id, $discussion->userid); 2527 self::assertEquals($discussiong2u1->id, $discussion->discussion); 2528 2529 // Get all my g3 discussions (I'm not enrolled in that group). 2530 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id); 2531 self::assertCount(0, $discussions); 2532 2533 // This group does not exist. 2534 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id + 1000); 2535 self::assertCount(0, $discussions); 2536 2537 self::setUser($user2); 2538 2539 // Test retrieve discussions not passing the groupid parameter. We will receive only first group discussions. 2540 $discussions = forum_get_discussions($cm); 2541 self::assertCount(2, $discussions); 2542 foreach ($discussions as $discussion) { 2543 self::assertEquals($group1->id, $discussion->groupid); 2544 } 2545 2546 // Get all my viewable discussions. 2547 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, 0); 2548 self::assertCount(2, $discussions); 2549 foreach ($discussions as $discussion) { 2550 self::assertEquals($group1->id, $discussion->groupid); 2551 } 2552 2553 // Get all my g2 discussions (I'm not enrolled in that group). 2554 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group2->id); 2555 self::assertCount(0, $discussions); 2556 2557 // Get all my g3 discussions (I'm not enrolled in that group). 2558 $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id); 2559 self::assertCount(0, $discussions); 2560 2561 } 2562 2563 /** 2564 * Test forum_user_can_post_discussion 2565 */ 2566 public function test_forum_user_can_post_discussion() { 2567 global $DB; 2568 2569 $this->resetAfterTest(true); 2570 2571 // Create course to add the module. 2572 $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1)); 2573 $user = self::getDataGenerator()->create_user(); 2574 $this->getDataGenerator()->enrol_user($user->id, $course->id); 2575 2576 // Forum forcing separate gropus. 2577 $record = new stdClass(); 2578 $record->course = $course->id; 2579 $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS)); 2580 $cm = get_coursemodule_from_instance('forum', $forum->id); 2581 $context = context_module::instance($cm->id); 2582 2583 self::setUser($user); 2584 2585 // The user is not enroled in any group, try to post in a forum with separate groups. 2586 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2587 $this->assertFalse($can); 2588 2589 // Create a group. 2590 $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2591 2592 // Try to post in a group the user is not enrolled. 2593 $can = forum_user_can_post_discussion($forum, $group->id, -1, $cm, $context); 2594 $this->assertFalse($can); 2595 2596 // Add the user to a group. 2597 groups_add_member($group->id, $user->id); 2598 2599 // Try to post in a group the user is not enrolled. 2600 $can = forum_user_can_post_discussion($forum, $group->id + 1, -1, $cm, $context); 2601 $this->assertFalse($can); 2602 2603 // Now try to post in the user group. (null means it will guess the group). 2604 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2605 $this->assertTrue($can); 2606 2607 $can = forum_user_can_post_discussion($forum, $group->id, -1, $cm, $context); 2608 $this->assertTrue($can); 2609 2610 // Test all groups. 2611 $can = forum_user_can_post_discussion($forum, -1, -1, $cm, $context); 2612 $this->assertFalse($can); 2613 2614 $this->setAdminUser(); 2615 $can = forum_user_can_post_discussion($forum, -1, -1, $cm, $context); 2616 $this->assertTrue($can); 2617 2618 // Change forum type. 2619 $forum->type = 'news'; 2620 $DB->update_record('forum', $forum); 2621 2622 // Admin can post news. 2623 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2624 $this->assertTrue($can); 2625 2626 // Normal users don't. 2627 self::setUser($user); 2628 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2629 $this->assertFalse($can); 2630 2631 // Change forum type. 2632 $forum->type = 'eachuser'; 2633 $DB->update_record('forum', $forum); 2634 2635 // I didn't post yet, so I should be able to post. 2636 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2637 $this->assertTrue($can); 2638 2639 // Post now. 2640 $record = new stdClass(); 2641 $record->course = $course->id; 2642 $record->userid = $user->id; 2643 $record->forum = $forum->id; 2644 $record->groupid = $group->id; 2645 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2646 2647 // I already posted, I shouldn't be able to post. 2648 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2649 $this->assertFalse($can); 2650 2651 // Last check with no groups, normal forum and course. 2652 $course->groupmode = NOGROUPS; 2653 $course->groupmodeforce = 0; 2654 $DB->update_record('course', $course); 2655 2656 $forum->type = 'general'; 2657 $forum->groupmode = NOGROUPS; 2658 $DB->update_record('forum', $forum); 2659 2660 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2661 $this->assertTrue($can); 2662 } 2663 2664 /** 2665 * Test forum_user_can_post_discussion_after_cutoff 2666 */ 2667 public function test_forum_user_can_post_discussion_after_cutoff() { 2668 $this->resetAfterTest(true); 2669 2670 // Create course to add the module. 2671 $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1)); 2672 $student = self::getDataGenerator()->create_user(); 2673 $teacher = self::getDataGenerator()->create_user(); 2674 $this->getDataGenerator()->enrol_user($student->id, $course->id); 2675 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher'); 2676 2677 // Forum forcing separate gropus. 2678 $record = new stdClass(); 2679 $record->course = $course->id; 2680 $record->cutoffdate = time() - 1; 2681 $forum = self::getDataGenerator()->create_module('forum', $record); 2682 $cm = get_coursemodule_from_instance('forum', $forum->id); 2683 $context = context_module::instance($cm->id); 2684 2685 self::setUser($student); 2686 2687 // Students usually don't have the mod/forum:canoverridecutoff capability. 2688 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2689 $this->assertFalse($can); 2690 2691 self::setUser($teacher); 2692 2693 // Teachers usually have the mod/forum:canoverridecutoff capability. 2694 $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context); 2695 $this->assertTrue($can); 2696 } 2697 2698 /** 2699 * Test forum_user_has_posted_discussion with no groups. 2700 */ 2701 public function test_forum_user_has_posted_discussion_no_groups() { 2702 global $CFG; 2703 2704 $this->resetAfterTest(true); 2705 2706 $course = self::getDataGenerator()->create_course(); 2707 $author = self::getDataGenerator()->create_user(); 2708 $other = self::getDataGenerator()->create_user(); 2709 $this->getDataGenerator()->enrol_user($author->id, $course->id); 2710 $forum = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ]); 2711 2712 self::setUser($author); 2713 2714 // Neither user has posted. 2715 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id)); 2716 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $other->id)); 2717 2718 // Post in the forum. 2719 $record = new stdClass(); 2720 $record->course = $course->id; 2721 $record->userid = $author->id; 2722 $record->forum = $forum->id; 2723 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2724 2725 // The author has now posted, but the other user has not. 2726 $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id)); 2727 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $other->id)); 2728 } 2729 2730 /** 2731 * Test forum_user_has_posted_discussion with multiple forums 2732 */ 2733 public function test_forum_user_has_posted_discussion_multiple_forums() { 2734 global $CFG; 2735 2736 $this->resetAfterTest(true); 2737 2738 $course = self::getDataGenerator()->create_course(); 2739 $author = self::getDataGenerator()->create_user(); 2740 $this->getDataGenerator()->enrol_user($author->id, $course->id); 2741 $forum1 = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ]); 2742 $forum2 = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ]); 2743 2744 self::setUser($author); 2745 2746 // No post in either forum. 2747 $this->assertFalse(forum_user_has_posted_discussion($forum1->id, $author->id)); 2748 $this->assertFalse(forum_user_has_posted_discussion($forum2->id, $author->id)); 2749 2750 // Post in the forum. 2751 $record = new stdClass(); 2752 $record->course = $course->id; 2753 $record->userid = $author->id; 2754 $record->forum = $forum1->id; 2755 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2756 2757 // The author has now posted in forum1, but not forum2. 2758 $this->assertTrue(forum_user_has_posted_discussion($forum1->id, $author->id)); 2759 $this->assertFalse(forum_user_has_posted_discussion($forum2->id, $author->id)); 2760 } 2761 2762 /** 2763 * Test forum_user_has_posted_discussion with multiple groups. 2764 */ 2765 public function test_forum_user_has_posted_discussion_multiple_groups() { 2766 global $CFG; 2767 2768 $this->resetAfterTest(true); 2769 2770 $course = self::getDataGenerator()->create_course(); 2771 $author = self::getDataGenerator()->create_user(); 2772 $this->getDataGenerator()->enrol_user($author->id, $course->id); 2773 2774 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2775 $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); 2776 groups_add_member($group1->id, $author->id); 2777 groups_add_member($group2->id, $author->id); 2778 2779 $forum = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ], [ 2780 'groupmode' => SEPARATEGROUPS, 2781 ]); 2782 2783 self::setUser($author); 2784 2785 // The user has not posted in either group. 2786 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id)); 2787 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id, $group1->id)); 2788 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id, $group2->id)); 2789 2790 // Post in one group. 2791 $record = new stdClass(); 2792 $record->course = $course->id; 2793 $record->userid = $author->id; 2794 $record->forum = $forum->id; 2795 $record->groupid = $group1->id; 2796 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2797 2798 // The author has now posted in one group, but the other user has not. 2799 $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id)); 2800 $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id, $group1->id)); 2801 $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id, $group2->id)); 2802 2803 // Post in the other group. 2804 $record = new stdClass(); 2805 $record->course = $course->id; 2806 $record->userid = $author->id; 2807 $record->forum = $forum->id; 2808 $record->groupid = $group2->id; 2809 $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); 2810 2811 // The author has now posted in one group, but the other user has not. 2812 $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id)); 2813 $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id, $group1->id)); 2814 $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id, $group2->id)); 2815 } 2816 2817 /** 2818 * Tests the mod_forum_myprofile_navigation() function. 2819 */ 2820 public function test_mod_forum_myprofile_navigation() { 2821 $this->resetAfterTest(true); 2822 2823 // Set up the test. 2824 $tree = new \core_user\output\myprofile\tree(); 2825 $user = $this->getDataGenerator()->create_user(); 2826 $course = $this->getDataGenerator()->create_course(); 2827 $iscurrentuser = true; 2828 2829 // Set as the current user. 2830 $this->setUser($user); 2831 2832 // Check the node tree is correct. 2833 mod_forum_myprofile_navigation($tree, $user, $iscurrentuser, $course); 2834 $reflector = new ReflectionObject($tree); 2835 $nodes = $reflector->getProperty('nodes'); 2836 $nodes->setAccessible(true); 2837 $this->assertArrayHasKey('forumposts', $nodes->getValue($tree)); 2838 $this->assertArrayHasKey('forumdiscussions', $nodes->getValue($tree)); 2839 } 2840 2841 /** 2842 * Tests the mod_forum_myprofile_navigation() function as a guest. 2843 */ 2844 public function test_mod_forum_myprofile_navigation_as_guest() { 2845 global $USER; 2846 2847 $this->resetAfterTest(true); 2848 2849 // Set up the test. 2850 $tree = new \core_user\output\myprofile\tree(); 2851 $course = $this->getDataGenerator()->create_course(); 2852 $iscurrentuser = true; 2853 2854 // Set user as guest. 2855 $this->setGuestUser(); 2856 2857 // Check the node tree is correct. 2858 mod_forum_myprofile_navigation($tree, $USER, $iscurrentuser, $course); 2859 $reflector = new ReflectionObject($tree); 2860 $nodes = $reflector->getProperty('nodes'); 2861 $nodes->setAccessible(true); 2862 $this->assertArrayNotHasKey('forumposts', $nodes->getValue($tree)); 2863 $this->assertArrayNotHasKey('forumdiscussions', $nodes->getValue($tree)); 2864 } 2865 2866 /** 2867 * Tests the mod_forum_myprofile_navigation() function as a user viewing another user's profile. 2868 */ 2869 public function test_mod_forum_myprofile_navigation_different_user() { 2870 $this->resetAfterTest(true); 2871 2872 // Set up the test. 2873 $tree = new \core_user\output\myprofile\tree(); 2874 $user = $this->getDataGenerator()->create_user(); 2875 $user2 = $this->getDataGenerator()->create_user(); 2876 $course = $this->getDataGenerator()->create_course(); 2877 $iscurrentuser = true; 2878 2879 // Set to different user's profile. 2880 $this->setUser($user2); 2881 2882 // Check the node tree is correct. 2883 mod_forum_myprofile_navigation($tree, $user, $iscurrentuser, $course); 2884 $reflector = new ReflectionObject($tree); 2885 $nodes = $reflector->getProperty('nodes'); 2886 $nodes->setAccessible(true); 2887 $this->assertArrayHasKey('forumposts', $nodes->getValue($tree)); 2888 $this->assertArrayHasKey('forumdiscussions', $nodes->getValue($tree)); 2889 } 2890 2891 /** 2892 * Test test_pinned_discussion_with_group. 2893 */ 2894 public function test_pinned_discussion_with_group() { 2895 global $SESSION; 2896 2897 $this->resetAfterTest(); 2898 $course1 = $this->getDataGenerator()->create_course(); 2899 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id)); 2900 2901 // Create an author user. 2902 $author = $this->getDataGenerator()->create_user(); 2903 $this->getDataGenerator()->enrol_user($author->id, $course1->id); 2904 2905 // Create two viewer users - one in a group, one not. 2906 $viewer1 = $this->getDataGenerator()->create_user((object) array('trackforums' => 1)); 2907 $this->getDataGenerator()->enrol_user($viewer1->id, $course1->id); 2908 2909 $viewer2 = $this->getDataGenerator()->create_user((object) array('trackforums' => 1)); 2910 $this->getDataGenerator()->enrol_user($viewer2->id, $course1->id); 2911 $this->getDataGenerator()->create_group_member(array('userid' => $viewer2->id, 'groupid' => $group1->id)); 2912 2913 $forum1 = $this->getDataGenerator()->create_module('forum', (object) array( 2914 'course' => $course1->id, 2915 'groupmode' => SEPARATEGROUPS, 2916 )); 2917 2918 $coursemodule = get_coursemodule_from_instance('forum', $forum1->id); 2919 2920 $alldiscussions = array(); 2921 $group1discussions = array(); 2922 2923 // Create 4 discussions in all participants group and group1, where the first 2924 // discussion is pinned in each group. 2925 $allrecord = new stdClass(); 2926 $allrecord->course = $course1->id; 2927 $allrecord->userid = $author->id; 2928 $allrecord->forum = $forum1->id; 2929 $allrecord->pinned = FORUM_DISCUSSION_PINNED; 2930 2931 $group1record = new stdClass(); 2932 $group1record->course = $course1->id; 2933 $group1record->userid = $author->id; 2934 $group1record->forum = $forum1->id; 2935 $group1record->groupid = $group1->id; 2936 $group1record->pinned = FORUM_DISCUSSION_PINNED; 2937 2938 $alldiscussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($allrecord); 2939 $group1discussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($group1record); 2940 2941 // Create unpinned discussions. 2942 $allrecord->pinned = FORUM_DISCUSSION_UNPINNED; 2943 $group1record->pinned = FORUM_DISCUSSION_UNPINNED; 2944 for ($i = 0; $i < 3; $i++) { 2945 $alldiscussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($allrecord); 2946 $group1discussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($group1record); 2947 } 2948 2949 // As viewer1 (no group). This user shouldn't see any of group1's discussions 2950 // so their expected discussion order is (where rightmost is highest priority): 2951 // Ad1, ad2, ad3, ad0. 2952 $this->setUser($viewer1->id); 2953 2954 // CHECK 1. 2955 // Take the neighbours of ad3, which should be prev: ad2 and next: ad0. 2956 $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[3], $forum1); 2957 // Ad2 check. 2958 $this->assertEquals($alldiscussions[2]->id, $neighbours['prev']->id); 2959 // Ad0 check. 2960 $this->assertEquals($alldiscussions[0]->id, $neighbours['next']->id); 2961 2962 // CHECK 2. 2963 // Take the neighbours of ad0, which should be prev: ad3 and next: null. 2964 $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[0], $forum1); 2965 // Ad3 check. 2966 $this->assertEquals($alldiscussions[3]->id, $neighbours['prev']->id); 2967 // Null check. 2968 $this->assertEmpty($neighbours['next']); 2969 2970 // CHECK 3. 2971 // Take the neighbours of ad1, which should be prev: null and next: ad2. 2972 $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[1], $forum1); 2973 // Null check. 2974 $this->assertEmpty($neighbours['prev']); 2975 // Ad2 check. 2976 $this->assertEquals($alldiscussions[2]->id, $neighbours['next']->id); 2977 2978 // Temporary hack to workaround for MDL-52656. 2979 $SESSION->currentgroup = null; 2980 2981 // As viewer2 (group1). This user should see all of group1's posts and the all participants group. 2982 // The expected discussion order is (rightmost is highest priority): 2983 // Ad1, gd1, ad2, gd2, ad3, gd3, ad0, gd0. 2984 $this->setUser($viewer2->id); 2985 2986 // CHECK 1. 2987 // Take the neighbours of ad1, which should be prev: null and next: gd1. 2988 $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[1], $forum1); 2989 // Null check. 2990 $this->assertEmpty($neighbours['prev']); 2991 // Gd1 check. 2992 $this->assertEquals($group1discussions[1]->id, $neighbours['next']->id); 2993 2994 // CHECK 2. 2995 // Take the neighbours of ad3, which should be prev: gd2 and next: gd3. 2996 $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[3], $forum1); 2997 // Gd2 check. 2998 $this->assertEquals($group1discussions[2]->id, $neighbours['prev']->id); 2999 // Gd3 check. 3000 $this->assertEquals($group1discussions[3]->id, $neighbours['next']->id); 3001 3002 // CHECK 3. 3003 // Take the neighbours of gd3, which should be prev: ad3 and next: ad0. 3004 $neighbours = forum_get_discussion_neighbours($coursemodule, $group1discussions[3], $forum1); 3005 // Ad3 check. 3006 $this->assertEquals($alldiscussions[3]->id, $neighbours['prev']->id); 3007 // Ad0 check. 3008 $this->assertEquals($alldiscussions[0]->id, $neighbours['next']->id); 3009 3010 // CHECK 4. 3011 // Take the neighbours of gd0, which should be prev: ad0 and next: null. 3012 $neighbours = forum_get_discussion_neighbours($coursemodule, $group1discussions[0], $forum1); 3013 // Ad0 check. 3014 $this->assertEquals($alldiscussions[0]->id, $neighbours['prev']->id); 3015 // Null check. 3016 $this->assertEmpty($neighbours['next']); 3017 } 3018 3019 /** 3020 * Test test_pinned_with_timed_discussions. 3021 */ 3022 public function test_pinned_with_timed_discussions() { 3023 global $CFG; 3024 3025 $CFG->forum_enabletimedposts = true; 3026 3027 $this->resetAfterTest(); 3028 $course = $this->getDataGenerator()->create_course(); 3029 3030 // Create an user. 3031 $user = $this->getDataGenerator()->create_user(); 3032 $this->getDataGenerator()->enrol_user($user->id, $course->id); 3033 3034 // Create a forum. 3035 $record = new stdClass(); 3036 $record->course = $course->id; 3037 $forum = $this->getDataGenerator()->create_module('forum', (object) array( 3038 'course' => $course->id, 3039 'groupmode' => SEPARATEGROUPS, 3040 )); 3041 3042 $coursemodule = get_coursemodule_from_instance('forum', $forum->id); 3043 $now = time(); 3044 $discussions = array(); 3045 $discussiongenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 3046 3047 $record = new stdClass(); 3048 $record->course = $course->id; 3049 $record->userid = $user->id; 3050 $record->forum = $forum->id; 3051 $record->pinned = FORUM_DISCUSSION_PINNED; 3052 $record->timemodified = $now; 3053 3054 $discussions[] = $discussiongenerator->create_discussion($record); 3055 3056 $record->pinned = FORUM_DISCUSSION_UNPINNED; 3057 $record->timestart = $now + 10; 3058 3059 $discussions[] = $discussiongenerator->create_discussion($record); 3060 3061 $record->timestart = $now; 3062 3063 $discussions[] = $discussiongenerator->create_discussion($record); 3064 3065 // Expected order of discussions: 3066 // D2, d1, d0. 3067 $this->setUser($user->id); 3068 3069 // CHECK 1. 3070 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[2], $forum); 3071 // Null check. 3072 $this->assertEmpty($neighbours['prev']); 3073 // D1 check. 3074 $this->assertEquals($discussions[1]->id, $neighbours['next']->id); 3075 3076 // CHECK 2. 3077 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[1], $forum); 3078 // D2 check. 3079 $this->assertEquals($discussions[2]->id, $neighbours['prev']->id); 3080 // D0 check. 3081 $this->assertEquals($discussions[0]->id, $neighbours['next']->id); 3082 3083 // CHECK 3. 3084 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[0], $forum); 3085 // D2 check. 3086 $this->assertEquals($discussions[1]->id, $neighbours['prev']->id); 3087 // Null check. 3088 $this->assertEmpty($neighbours['next']); 3089 } 3090 3091 /** 3092 * Test test_pinned_timed_discussions_with_timed_discussions. 3093 */ 3094 public function test_pinned_timed_discussions_with_timed_discussions() { 3095 global $CFG; 3096 3097 $CFG->forum_enabletimedposts = true; 3098 3099 $this->resetAfterTest(); 3100 $course = $this->getDataGenerator()->create_course(); 3101 3102 // Create an user. 3103 $user = $this->getDataGenerator()->create_user(); 3104 $this->getDataGenerator()->enrol_user($user->id, $course->id); 3105 3106 // Create a forum. 3107 $record = new stdClass(); 3108 $record->course = $course->id; 3109 $forum = $this->getDataGenerator()->create_module('forum', (object) array( 3110 'course' => $course->id, 3111 'groupmode' => SEPARATEGROUPS, 3112 )); 3113 3114 $coursemodule = get_coursemodule_from_instance('forum', $forum->id); 3115 $now = time(); 3116 $discussions = array(); 3117 $discussiongenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 3118 3119 $record = new stdClass(); 3120 $record->course = $course->id; 3121 $record->userid = $user->id; 3122 $record->forum = $forum->id; 3123 $record->pinned = FORUM_DISCUSSION_PINNED; 3124 $record->timemodified = $now; 3125 $record->timestart = $now + 10; 3126 3127 $discussions[] = $discussiongenerator->create_discussion($record); 3128 3129 $record->pinned = FORUM_DISCUSSION_UNPINNED; 3130 3131 $discussions[] = $discussiongenerator->create_discussion($record); 3132 3133 $record->timestart = $now; 3134 3135 $discussions[] = $discussiongenerator->create_discussion($record); 3136 3137 $record->pinned = FORUM_DISCUSSION_PINNED; 3138 3139 $discussions[] = $discussiongenerator->create_discussion($record); 3140 3141 // Expected order of discussions: 3142 // D2, d1, d3, d0. 3143 $this->setUser($user->id); 3144 3145 // CHECK 1. 3146 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[2], $forum); 3147 // Null check. 3148 $this->assertEmpty($neighbours['prev']); 3149 // D1 check. 3150 $this->assertEquals($discussions[1]->id, $neighbours['next']->id); 3151 3152 // CHECK 2. 3153 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[1], $forum); 3154 // D2 check. 3155 $this->assertEquals($discussions[2]->id, $neighbours['prev']->id); 3156 // D3 check. 3157 $this->assertEquals($discussions[3]->id, $neighbours['next']->id); 3158 3159 // CHECK 3. 3160 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[3], $forum); 3161 // D1 check. 3162 $this->assertEquals($discussions[1]->id, $neighbours['prev']->id); 3163 // D0 check. 3164 $this->assertEquals($discussions[0]->id, $neighbours['next']->id); 3165 3166 // CHECK 4. 3167 $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[0], $forum); 3168 // D3 check. 3169 $this->assertEquals($discussions[3]->id, $neighbours['prev']->id); 3170 // Null check. 3171 $this->assertEmpty($neighbours['next']); 3172 } 3173 3174 /** 3175 * Test for forum_is_author_hidden. 3176 */ 3177 public function test_forum_is_author_hidden() { 3178 // First post, different forum type. 3179 $post = (object) ['parent' => 0]; 3180 $forum = (object) ['type' => 'standard']; 3181 $this->assertFalse(forum_is_author_hidden($post, $forum)); 3182 3183 // Child post, different forum type. 3184 $post->parent = 1; 3185 $this->assertFalse(forum_is_author_hidden($post, $forum)); 3186 3187 // First post, single simple discussion forum type. 3188 $post->parent = 0; 3189 $forum->type = 'single'; 3190 $this->assertTrue(forum_is_author_hidden($post, $forum)); 3191 3192 // Child post, single simple discussion forum type. 3193 $post->parent = 1; 3194 $this->assertFalse(forum_is_author_hidden($post, $forum)); 3195 3196 // Incorrect parameters: $post. 3197 $this->expectException('coding_exception'); 3198 $this->expectExceptionMessage('$post->parent must be set.'); 3199 unset($post->parent); 3200 forum_is_author_hidden($post, $forum); 3201 3202 // Incorrect parameters: $forum. 3203 $this->expectException('coding_exception'); 3204 $this->expectExceptionMessage('$forum->type must be set.'); 3205 unset($forum->type); 3206 forum_is_author_hidden($post, $forum); 3207 } 3208 3209 /** 3210 * Test the forum_discussion_is_locked function. 3211 * 3212 * @dataProvider forum_discussion_is_locked_provider 3213 * @param stdClass $forum 3214 * @param stdClass $discussion 3215 * @param bool $expect 3216 */ 3217 public function test_forum_discussion_is_locked($forum, $discussion, $expect) { 3218 $this->resetAfterTest(); 3219 3220 $datagenerator = $this->getDataGenerator(); 3221 $plugingenerator = $datagenerator->get_plugin_generator('mod_forum'); 3222 3223 $course = $datagenerator->create_course(); 3224 $user = $datagenerator->create_user(); 3225 $forum = $datagenerator->create_module('forum', (object) array_merge([ 3226 'course' => $course->id 3227 ], $forum)); 3228 $discussion = $plugingenerator->create_discussion((object) array_merge([ 3229 'course' => $course->id, 3230 'userid' => $user->id, 3231 'forum' => $forum->id, 3232 ], $discussion)); 3233 3234 $this->assertEquals($expect, forum_discussion_is_locked($forum, $discussion)); 3235 } 3236 3237 /** 3238 * Dataprovider for forum_discussion_is_locked tests. 3239 * 3240 * @return array 3241 */ 3242 public function forum_discussion_is_locked_provider() { 3243 return [ 3244 'Unlocked: lockdiscussionafter is false' => [ 3245 ['lockdiscussionafter' => false], 3246 [], 3247 false 3248 ], 3249 'Unlocked: lockdiscussionafter is set; forum is of type single; post is recent' => [ 3250 ['lockdiscussionafter' => DAYSECS, 'type' => 'single'], 3251 ['timemodified' => time()], 3252 false 3253 ], 3254 'Unlocked: lockdiscussionafter is set; forum is of type single; post is old' => [ 3255 ['lockdiscussionafter' => MINSECS, 'type' => 'single'], 3256 ['timemodified' => time() - DAYSECS], 3257 false 3258 ], 3259 'Unlocked: lockdiscussionafter is set; forum is of type eachuser; post is recent' => [ 3260 ['lockdiscussionafter' => DAYSECS, 'type' => 'eachuser'], 3261 ['timemodified' => time()], 3262 false 3263 ], 3264 'Locked: lockdiscussionafter is set; forum is of type eachuser; post is old' => [ 3265 ['lockdiscussionafter' => MINSECS, 'type' => 'eachuser'], 3266 ['timemodified' => time() - DAYSECS], 3267 true 3268 ], 3269 ]; 3270 } 3271 3272 /** 3273 * Test the forum_is_cutoff_date_reached function. 3274 * 3275 * @dataProvider forum_is_cutoff_date_reached_provider 3276 * @param array $forum 3277 * @param bool $expect 3278 */ 3279 public function test_forum_is_cutoff_date_reached($forum, $expect) { 3280 $this->resetAfterTest(); 3281 3282 $datagenerator = $this->getDataGenerator(); 3283 $course = $datagenerator->create_course(); 3284 $forum = $datagenerator->create_module('forum', (object) array_merge([ 3285 'course' => $course->id 3286 ], $forum)); 3287 3288 $this->assertEquals($expect, forum_is_cutoff_date_reached($forum)); 3289 } 3290 3291 /** 3292 * Dataprovider for forum_is_cutoff_date_reached tests. 3293 * 3294 * @return array 3295 */ 3296 public function forum_is_cutoff_date_reached_provider() { 3297 $now = time(); 3298 return [ 3299 'cutoffdate is unset' => [ 3300 [], 3301 false 3302 ], 3303 'cutoffdate is 0' => [ 3304 ['cutoffdate' => 0], 3305 false 3306 ], 3307 'cutoffdate is set and is in future' => [ 3308 ['cutoffdate' => $now + 86400], 3309 false 3310 ], 3311 'cutoffdate is set and is in past' => [ 3312 ['cutoffdate' => $now - 86400], 3313 true 3314 ], 3315 ]; 3316 } 3317 3318 /** 3319 * Test the forum_is_due_date_reached function. 3320 * 3321 * @dataProvider forum_is_due_date_reached_provider 3322 * @param stdClass $forum 3323 * @param bool $expect 3324 */ 3325 public function test_forum_is_due_date_reached($forum, $expect) { 3326 $this->resetAfterTest(); 3327 3328 $this->setAdminUser(); 3329 3330 $datagenerator = $this->getDataGenerator(); 3331 $course = $datagenerator->create_course(); 3332 $forum = $datagenerator->create_module('forum', (object) array_merge([ 3333 'course' => $course->id 3334 ], $forum)); 3335 3336 $this->assertEquals($expect, forum_is_due_date_reached($forum)); 3337 } 3338 3339 /** 3340 * Dataprovider for forum_is_due_date_reached tests. 3341 * 3342 * @return array 3343 */ 3344 public function forum_is_due_date_reached_provider() { 3345 $now = time(); 3346 return [ 3347 'duedate is unset' => [ 3348 [], 3349 false 3350 ], 3351 'duedate is 0' => [ 3352 ['duedate' => 0], 3353 false 3354 ], 3355 'duedate is set and is in future' => [ 3356 ['duedate' => $now + 86400], 3357 false 3358 ], 3359 'duedate is set and is in past' => [ 3360 ['duedate' => $now - 86400], 3361 true 3362 ], 3363 ]; 3364 } 3365 3366 /** 3367 * Test that {@link forum_update_post()} keeps correct forum_discussions usermodified. 3368 */ 3369 public function test_forum_update_post_keeps_discussions_usermodified() { 3370 global $DB; 3371 3372 $this->resetAfterTest(); 3373 3374 // Let there be light. 3375 $teacher = self::getDataGenerator()->create_user(); 3376 $student = self::getDataGenerator()->create_user(); 3377 $course = self::getDataGenerator()->create_course(); 3378 3379 $forum = self::getDataGenerator()->create_module('forum', (object)[ 3380 'course' => $course->id, 3381 ]); 3382 3383 $generator = self::getDataGenerator()->get_plugin_generator('mod_forum'); 3384 3385 // Let the teacher start a discussion. 3386 $discussion = $generator->create_discussion((object)[ 3387 'course' => $course->id, 3388 'userid' => $teacher->id, 3389 'forum' => $forum->id, 3390 ]); 3391 3392 // On this freshly created discussion, the teacher is the author of the last post. 3393 $this->assertEquals($teacher->id, $DB->get_field('forum_discussions', 'usermodified', ['id' => $discussion->id])); 3394 3395 // Fetch modified timestamp of the discussion. 3396 $discussionmodified = $DB->get_field('forum_discussions', 'timemodified', ['id' => $discussion->id]); 3397 $pasttime = $discussionmodified - 3600; 3398 3399 // Adjust the discussion modified timestamp back an hour, so it's in the past. 3400 $adjustment = (object)[ 3401 'id' => $discussion->id, 3402 'timemodified' => $pasttime, 3403 ]; 3404 $DB->update_record('forum_discussions', $adjustment); 3405 3406 // Let the student reply to the teacher's post. 3407 $reply = $generator->create_post((object)[ 3408 'course' => $course->id, 3409 'userid' => $student->id, 3410 'forum' => $forum->id, 3411 'discussion' => $discussion->id, 3412 'parent' => $discussion->firstpost, 3413 ]); 3414 3415 // The student should now be the last post's author. 3416 $this->assertEquals($student->id, $DB->get_field('forum_discussions', 'usermodified', ['id' => $discussion->id])); 3417 3418 // Fetch modified timestamp of the discussion and student's post. 3419 $discussionmodified = $DB->get_field('forum_discussions', 'timemodified', ['id' => $discussion->id]); 3420 $postmodified = $DB->get_field('forum_posts', 'modified', ['id' => $reply->id]); 3421 3422 // Discussion modified time should be updated to be equal to the newly created post's time. 3423 $this->assertEquals($discussionmodified, $postmodified); 3424 3425 // Adjust the discussion and post timestamps, so they are in the past. 3426 $adjustment = (object)[ 3427 'id' => $discussion->id, 3428 'timemodified' => $pasttime, 3429 ]; 3430 $DB->update_record('forum_discussions', $adjustment); 3431 3432 $adjustment = (object)[ 3433 'id' => $reply->id, 3434 'modified' => $pasttime, 3435 ]; 3436 $DB->update_record('forum_posts', $adjustment); 3437 3438 // The discussion and student's post time should now be an hour in the past. 3439 $this->assertEquals($pasttime, $DB->get_field('forum_discussions', 'timemodified', ['id' => $discussion->id])); 3440 $this->assertEquals($pasttime, $DB->get_field('forum_posts', 'modified', ['id' => $reply->id])); 3441 3442 // Let the teacher edit the student's reply. 3443 $this->setUser($teacher->id); 3444 $newpost = (object)[ 3445 'id' => $reply->id, 3446 'itemid' => 0, 3447 'subject' => 'Amended subject', 3448 ]; 3449 forum_update_post($newpost, null); 3450 3451 // The student should still be the last post's author. 3452 $this->assertEquals($student->id, $DB->get_field('forum_discussions', 'usermodified', ['id' => $discussion->id])); 3453 3454 // The discussion modified time should not have changed. 3455 $this->assertEquals($pasttime, $DB->get_field('forum_discussions', 'timemodified', ['id' => $discussion->id])); 3456 3457 // The post time should be updated. 3458 $this->assertGreaterThan($pasttime, $DB->get_field('forum_posts', 'modified', ['id' => $reply->id])); 3459 } 3460 3461 public function test_forum_core_calendar_provide_event_action() { 3462 $this->resetAfterTest(); 3463 $this->setAdminUser(); 3464 3465 // Create the activity. 3466 $course = $this->getDataGenerator()->create_course(); 3467 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 3468 'completionreplies' => 5, 'completiondiscussions' => 2)); 3469 3470 // Create a calendar event. 3471 $event = $this->create_action_event($course->id, $forum->id, 3472 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 3473 3474 // Create an action factory. 3475 $factory = new \core_calendar\action_factory(); 3476 3477 // Decorate action event. 3478 $actionevent = mod_forum_core_calendar_provide_event_action($event, $factory); 3479 3480 // Confirm the event was decorated. 3481 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 3482 $this->assertEquals(get_string('view'), $actionevent->get_name()); 3483 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 3484 $this->assertEquals(7, $actionevent->get_item_count()); 3485 $this->assertTrue($actionevent->is_actionable()); 3486 } 3487 3488 public function test_forum_core_calendar_provide_event_action_in_hidden_section() { 3489 global $CFG; 3490 3491 $this->resetAfterTest(); 3492 $this->setAdminUser(); 3493 3494 // Create a course. 3495 $course = $this->getDataGenerator()->create_course(); 3496 3497 // Create a student. 3498 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 3499 3500 // Create the activity. 3501 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 3502 'completionreplies' => 5, 'completiondiscussions' => 2)); 3503 3504 // Create a calendar event. 3505 $event = $this->create_action_event($course->id, $forum->id, 3506 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 3507 3508 // Set sections 0 as hidden. 3509 set_section_visible($course->id, 0, 0); 3510 3511 // Now, log out. 3512 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 3513 $this->setUser(); 3514 3515 // Create an action factory. 3516 $factory = new \core_calendar\action_factory(); 3517 3518 // Decorate action event for the student. 3519 $actionevent = mod_forum_core_calendar_provide_event_action($event, $factory, $student->id); 3520 3521 // Confirm the event is not shown at all. 3522 $this->assertNull($actionevent); 3523 } 3524 3525 public function test_forum_core_calendar_provide_event_action_for_user() { 3526 global $CFG; 3527 3528 $this->resetAfterTest(); 3529 $this->setAdminUser(); 3530 3531 // Create a course. 3532 $course = $this->getDataGenerator()->create_course(); 3533 3534 // Create a student. 3535 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 3536 3537 // Create the activity. 3538 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 3539 'completionreplies' => 5, 'completiondiscussions' => 2)); 3540 3541 // Create a calendar event. 3542 $event = $this->create_action_event($course->id, $forum->id, 3543 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 3544 3545 // Now log out. 3546 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 3547 $this->setUser(); 3548 3549 // Create an action factory. 3550 $factory = new \core_calendar\action_factory(); 3551 3552 // Decorate action event for the student. 3553 $actionevent = mod_forum_core_calendar_provide_event_action($event, $factory, $student->id); 3554 3555 // Confirm the event was decorated. 3556 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 3557 $this->assertEquals(get_string('view'), $actionevent->get_name()); 3558 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 3559 $this->assertEquals(7, $actionevent->get_item_count()); 3560 $this->assertTrue($actionevent->is_actionable()); 3561 } 3562 3563 public function test_forum_core_calendar_provide_event_action_as_non_user() { 3564 global $CFG; 3565 3566 $this->resetAfterTest(); 3567 $this->setAdminUser(); 3568 3569 // Create the activity. 3570 $course = $this->getDataGenerator()->create_course(); 3571 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 3572 3573 // Create a calendar event. 3574 $event = $this->create_action_event($course->id, $forum->id, 3575 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 3576 3577 // Log out the user and set force login to true. 3578 \core\session\manager::init_empty_session(); 3579 $CFG->forcelogin = true; 3580 3581 // Create an action factory. 3582 $factory = new \core_calendar\action_factory(); 3583 3584 // Decorate action event. 3585 $actionevent = mod_forum_core_calendar_provide_event_action($event, $factory); 3586 3587 // Ensure result was null. 3588 $this->assertNull($actionevent); 3589 } 3590 3591 public function test_forum_core_calendar_provide_event_action_already_completed() { 3592 global $CFG; 3593 3594 $this->resetAfterTest(); 3595 $this->setAdminUser(); 3596 3597 $CFG->enablecompletion = 1; 3598 3599 // Create the activity. 3600 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 3601 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), 3602 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); 3603 3604 // Get some additional data. 3605 $cm = get_coursemodule_from_instance('forum', $forum->id); 3606 3607 // Create a calendar event. 3608 $event = $this->create_action_event($course->id, $forum->id, 3609 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 3610 3611 // Mark the activity as completed. 3612 $completion = new completion_info($course); 3613 $completion->set_module_viewed($cm); 3614 3615 // Create an action factory. 3616 $factory = new \core_calendar\action_factory(); 3617 3618 // Decorate action event. 3619 $actionevent = mod_forum_core_calendar_provide_event_action($event, $factory); 3620 3621 // Ensure result was null. 3622 $this->assertNull($actionevent); 3623 } 3624 3625 public function test_forum_core_calendar_provide_event_action_already_completed_for_user() { 3626 global $CFG; 3627 3628 $this->resetAfterTest(); 3629 $this->setAdminUser(); 3630 3631 $CFG->enablecompletion = 1; 3632 3633 // Create a course. 3634 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 3635 3636 // Create a student. 3637 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 3638 3639 // Create the activity. 3640 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id), 3641 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); 3642 3643 // Get some additional data. 3644 $cm = get_coursemodule_from_instance('forum', $forum->id); 3645 3646 // Create a calendar event. 3647 $event = $this->create_action_event($course->id, $forum->id, 3648 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 3649 3650 // Mark the activity as completed for the student. 3651 $completion = new completion_info($course); 3652 $completion->set_module_viewed($cm, $student->id); 3653 3654 // Create an action factory. 3655 $factory = new \core_calendar\action_factory(); 3656 3657 // Decorate action event. 3658 $actionevent = mod_forum_core_calendar_provide_event_action($event, $factory, $student->id); 3659 3660 // Ensure result was null. 3661 $this->assertNull($actionevent); 3662 } 3663 3664 public function test_mod_forum_get_tagged_posts() { 3665 global $DB; 3666 3667 $this->resetAfterTest(); 3668 $this->setAdminUser(); 3669 3670 // Setup test data. 3671 $forumgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); 3672 $course3 = $this->getDataGenerator()->create_course(); 3673 $course2 = $this->getDataGenerator()->create_course(); 3674 $course1 = $this->getDataGenerator()->create_course(); 3675 $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course1->id)); 3676 $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course2->id)); 3677 $forum3 = $this->getDataGenerator()->create_module('forum', array('course' => $course3->id)); 3678 $post11 = $forumgenerator->create_content($forum1, array('tags' => array('Cats', 'Dogs'))); 3679 $post12 = $forumgenerator->create_content($forum1, array('tags' => array('Cats', 'mice'))); 3680 $post13 = $forumgenerator->create_content($forum1, array('tags' => array('Cats'))); 3681 $post14 = $forumgenerator->create_content($forum1); 3682 $post15 = $forumgenerator->create_content($forum1, array('tags' => array('Cats'))); 3683 $post16 = $forumgenerator->create_content($forum1, array('tags' => array('Cats'), 'hidden' => true)); 3684 $post21 = $forumgenerator->create_content($forum2, array('tags' => array('Cats'))); 3685 $post22 = $forumgenerator->create_content($forum2, array('tags' => array('Cats', 'Dogs'))); 3686 $post23 = $forumgenerator->create_content($forum2, array('tags' => array('mice', 'Cats'))); 3687 $post31 = $forumgenerator->create_content($forum3, array('tags' => array('mice', 'Cats'))); 3688 3689 $tag = core_tag_tag::get_by_name(0, 'Cats'); 3690 3691 // Admin can see everything. 3692 $res = mod_forum_get_tagged_posts($tag, /*$exclusivemode = */false, 3693 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$post = */0); 3694 $this->assertRegExp('/'.$post11->subject.'</', $res->content); 3695 $this->assertRegExp('/'.$post12->subject.'</', $res->content); 3696 $this->assertRegExp('/'.$post13->subject.'</', $res->content); 3697 $this->assertNotRegExp('/'.$post14->subject.'</', $res->content); 3698 $this->assertRegExp('/'.$post15->subject.'</', $res->content); 3699 $this->assertRegExp('/'.$post16->subject.'</', $res->content); 3700 $this->assertNotRegExp('/'.$post21->subject.'</', $res->content); 3701 $this->assertNotRegExp('/'.$post22->subject.'</', $res->content); 3702 $this->assertNotRegExp('/'.$post23->subject.'</', $res->content); 3703 $this->assertNotRegExp('/'.$post31->subject.'</', $res->content); 3704 $this->assertEmpty($res->prevpageurl); 3705 $this->assertNotEmpty($res->nextpageurl); 3706 $res = mod_forum_get_tagged_posts($tag, /*$exclusivemode = */false, 3707 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$post = */1); 3708 $this->assertNotRegExp('/'.$post11->subject.'</', $res->content); 3709 $this->assertNotRegExp('/'.$post12->subject.'</', $res->content); 3710 $this->assertNotRegExp('/'.$post13->subject.'</', $res->content); 3711 $this->assertNotRegExp('/'.$post14->subject.'</', $res->content); 3712 $this->assertNotRegExp('/'.$post15->subject.'</', $res->content); 3713 $this->assertNotRegExp('/'.$post16->subject.'</', $res->content); 3714 $this->assertRegExp('/'.$post21->subject.'</', $res->content); 3715 $this->assertRegExp('/'.$post22->subject.'</', $res->content); 3716 $this->assertRegExp('/'.$post23->subject.'</', $res->content); 3717 $this->assertRegExp('/'.$post31->subject.'</', $res->content); 3718 $this->assertNotEmpty($res->prevpageurl); 3719 $this->assertEmpty($res->nextpageurl); 3720 3721 // Create and enrol a user. 3722 $student = self::getDataGenerator()->create_user(); 3723 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 3724 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 3725 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 3726 $this->setUser($student); 3727 core_tag_index_builder::reset_caches(); 3728 3729 // User can not see posts in course 3 because he is not enrolled. 3730 $res = mod_forum_get_tagged_posts($tag, /*$exclusivemode = */false, 3731 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$post = */1); 3732 $this->assertRegExp('/'.$post22->subject.'/', $res->content); 3733 $this->assertRegExp('/'.$post23->subject.'/', $res->content); 3734 $this->assertNotRegExp('/'.$post31->subject.'/', $res->content); 3735 3736 // User can search forum posts inside a course. 3737 $coursecontext = context_course::instance($course1->id); 3738 $res = mod_forum_get_tagged_posts($tag, /*$exclusivemode = */false, 3739 /*$fromctx = */0, /*$ctx = */$coursecontext->id, /*$rec = */1, /*$post = */0); 3740 $this->assertRegExp('/'.$post11->subject.'/', $res->content); 3741 $this->assertRegExp('/'.$post12->subject.'/', $res->content); 3742 $this->assertRegExp('/'.$post13->subject.'/', $res->content); 3743 $this->assertNotRegExp('/'.$post14->subject.'/', $res->content); 3744 $this->assertRegExp('/'.$post15->subject.'/', $res->content); 3745 $this->assertRegExp('/'.$post16->subject.'/', $res->content); 3746 $this->assertNotRegExp('/'.$post21->subject.'/', $res->content); 3747 $this->assertNotRegExp('/'.$post22->subject.'/', $res->content); 3748 $this->assertNotRegExp('/'.$post23->subject.'/', $res->content); 3749 $this->assertEmpty($res->nextpageurl); 3750 } 3751 3752 /** 3753 * Creates an action event. 3754 * 3755 * @param int $courseid The course id. 3756 * @param int $instanceid The instance id. 3757 * @param string $eventtype The event type. 3758 * @return bool|calendar_event 3759 */ 3760 private function create_action_event($courseid, $instanceid, $eventtype) { 3761 $event = new stdClass(); 3762 $event->name = 'Calendar event'; 3763 $event->modulename = 'forum'; 3764 $event->courseid = $courseid; 3765 $event->instance = $instanceid; 3766 $event->type = CALENDAR_EVENT_TYPE_ACTION; 3767 $event->eventtype = $eventtype; 3768 $event->timestart = time(); 3769 3770 return calendar_event::create($event); 3771 } 3772 3773 /** 3774 * Test the callback responsible for returning the completion rule descriptions. 3775 * This function should work given either an instance of the module (cm_info), such as when checking the active rules, 3776 * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type. 3777 */ 3778 public function test_mod_forum_completion_get_active_rule_descriptions() { 3779 $this->resetAfterTest(); 3780 $this->setAdminUser(); 3781 3782 // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't. 3783 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]); 3784 $forum1 = $this->getDataGenerator()->create_module('forum', [ 3785 'course' => $course->id, 3786 'completion' => 2, 3787 'completiondiscussions' => 3, 3788 'completionreplies' => 3, 3789 'completionposts' => 3 3790 ]); 3791 $forum2 = $this->getDataGenerator()->create_module('forum', [ 3792 'course' => $course->id, 3793 'completion' => 2, 3794 'completiondiscussions' => 0, 3795 'completionreplies' => 0, 3796 'completionposts' => 0 3797 ]); 3798 $cm1 = cm_info::create(get_coursemodule_from_instance('forum', $forum1->id)); 3799 $cm2 = cm_info::create(get_coursemodule_from_instance('forum', $forum2->id)); 3800 3801 // Data for the stdClass input type. 3802 // This type of input would occur when checking the default completion rules for an activity type, where we don't have 3803 // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info. 3804 $moddefaults = new stdClass(); 3805 $moddefaults->customdata = ['customcompletionrules' => [ 3806 'completiondiscussions' => 3, 3807 'completionreplies' => 3, 3808 'completionposts' => 3 3809 ]]; 3810 $moddefaults->completion = 2; 3811 3812 $activeruledescriptions = [ 3813 get_string('completiondiscussionsdesc', 'forum', 3), 3814 get_string('completionrepliesdesc', 'forum', 3), 3815 get_string('completionpostsdesc', 'forum', 3) 3816 ]; 3817 $this->assertEquals(mod_forum_get_completion_active_rule_descriptions($cm1), $activeruledescriptions); 3818 $this->assertEquals(mod_forum_get_completion_active_rule_descriptions($cm2), []); 3819 $this->assertEquals(mod_forum_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions); 3820 $this->assertEquals(mod_forum_get_completion_active_rule_descriptions(new stdClass()), []); 3821 } 3822 3823 /** 3824 * Test the forum_post_is_visible_privately function used in private replies. 3825 */ 3826 public function test_forum_post_is_visible_privately() { 3827 $this->resetAfterTest(); 3828 3829 $course = $this->getDataGenerator()->create_course(); 3830 $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id)); 3831 $context = context_module::instance($forum->cmid); 3832 $cm = get_coursemodule_from_instance('forum', $forum->id); 3833 3834 $author = $this->getDataGenerator()->create_user(); 3835 $this->getDataGenerator()->enrol_user($author->id, $course->id); 3836 3837 $recipient = $this->getDataGenerator()->create_user(); 3838 $this->getDataGenerator()->enrol_user($recipient->id, $course->id); 3839 3840 $privilegeduser = $this->getDataGenerator()->create_user(); 3841 $this->getDataGenerator()->enrol_user($privilegeduser->id, $course->id, 'editingteacher'); 3842 3843 $otheruser = $this->getDataGenerator()->create_user(); 3844 $this->getDataGenerator()->enrol_user($otheruser->id, $course->id); 3845 3846 // Fake a post - this does not need to be persisted to the DB. 3847 $post = new \stdClass(); 3848 $post->userid = $author->id; 3849 $post->privatereplyto = $recipient->id; 3850 3851 // The user is the author. 3852 $this->setUser($author->id); 3853 $this->assertTrue(forum_post_is_visible_privately($post, $cm)); 3854 3855 // The user is the intended recipient. 3856 $this->setUser($recipient->id); 3857 $this->assertTrue(forum_post_is_visible_privately($post, $cm)); 3858 3859 // The user is not the author or recipient, but does have the readprivatereplies capability. 3860 $this->setUser($privilegeduser->id); 3861 $this->assertTrue(forum_post_is_visible_privately($post, $cm)); 3862 3863 // The user is not allowed to view this post. 3864 $this->setUser($otheruser->id); 3865 $this->assertFalse(forum_post_is_visible_privately($post, $cm)); 3866 } 3867 3868 /** 3869 * An unkown event type should not have any limits 3870 */ 3871 public function test_mod_forum_core_calendar_get_valid_event_timestart_range_unknown_event() { 3872 global $CFG; 3873 require_once($CFG->dirroot . "/calendar/lib.php"); 3874 3875 $this->resetAfterTest(true); 3876 $this->setAdminUser(); 3877 $generator = $this->getDataGenerator(); 3878 $course = $generator->create_course(); 3879 $duedate = time() + DAYSECS; 3880 $forum = new \stdClass(); 3881 $forum->duedate = $duedate; 3882 3883 // Create a valid event. 3884 $event = new \calendar_event([ 3885 'name' => 'Test event', 3886 'description' => '', 3887 'format' => 1, 3888 'courseid' => $course->id, 3889 'groupid' => 0, 3890 'userid' => 2, 3891 'modulename' => 'forum', 3892 'instance' => 1, 3893 'eventtype' => FORUM_EVENT_TYPE_DUE . "SOMETHING ELSE", 3894 'timestart' => 1, 3895 'timeduration' => 86400, 3896 'visible' => 1 3897 ]); 3898 3899 list ($min, $max) = mod_forum_core_calendar_get_valid_event_timestart_range($event, $forum); 3900 $this->assertNull($min); 3901 $this->assertNull($max); 3902 } 3903 3904 /** 3905 * Forums configured without a cutoff date should not have any limits applied. 3906 */ 3907 public function test_mod_forum_core_calendar_get_valid_event_timestart_range_due_no_limit() { 3908 global $CFG; 3909 require_once($CFG->dirroot . '/calendar/lib.php'); 3910 3911 $this->resetAfterTest(true); 3912 $this->setAdminUser(); 3913 $generator = $this->getDataGenerator(); 3914 $course = $generator->create_course(); 3915 $duedate = time() + DAYSECS; 3916 $forum = new \stdClass(); 3917 $forum->duedate = $duedate; 3918 3919 // Create a valid event. 3920 $event = new \calendar_event([ 3921 'name' => 'Test event', 3922 'description' => '', 3923 'format' => 1, 3924 'courseid' => $course->id, 3925 'groupid' => 0, 3926 'userid' => 2, 3927 'modulename' => 'forum', 3928 'instance' => 1, 3929 'eventtype' => FORUM_EVENT_TYPE_DUE, 3930 'timestart' => 1, 3931 'timeduration' => 86400, 3932 'visible' => 1 3933 ]); 3934 3935 list($min, $max) = mod_forum_core_calendar_get_valid_event_timestart_range($event, $forum); 3936 $this->assertNull($min); 3937 $this->assertNull($max); 3938 } 3939 3940 /** 3941 * Forums should be top bound by the cutoff date. 3942 */ 3943 public function test_mod_forum_core_calendar_get_valid_event_timestart_range_due_with_limits() { 3944 global $CFG; 3945 require_once($CFG->dirroot . '/calendar/lib.php'); 3946 3947 $this->resetAfterTest(true); 3948 $this->setAdminUser(); 3949 $generator = $this->getDataGenerator(); 3950 $course = $generator->create_course(); 3951 $duedate = time() + DAYSECS; 3952 $cutoffdate = $duedate + DAYSECS; 3953 $forum = new \stdClass(); 3954 $forum->duedate = $duedate; 3955 $forum->cutoffdate = $cutoffdate; 3956 3957 // Create a valid event. 3958 $event = new \calendar_event([ 3959 'name' => 'Test event', 3960 'description' => '', 3961 'format' => 1, 3962 'courseid' => $course->id, 3963 'groupid' => 0, 3964 'userid' => 2, 3965 'modulename' => 'forum', 3966 'instance' => 1, 3967 'eventtype' => FORUM_EVENT_TYPE_DUE, 3968 'timestart' => 1, 3969 'timeduration' => 86400, 3970 'visible' => 1 3971 ]); 3972 3973 list($min, $max) = mod_forum_core_calendar_get_valid_event_timestart_range($event, $forum); 3974 $this->assertNull($min); 3975 $this->assertEquals($cutoffdate, $max[0]); 3976 $this->assertNotEmpty($max[1]); 3977 } 3978 3979 /** 3980 * An unknown event type should not change the forum instance. 3981 */ 3982 public function test_mod_forum_core_calendar_event_timestart_updated_unknown_event() { 3983 global $CFG, $DB; 3984 require_once($CFG->dirroot . "/calendar/lib.php"); 3985 3986 $this->resetAfterTest(true); 3987 $this->setAdminUser(); 3988 $generator = $this->getDataGenerator(); 3989 $course = $generator->create_course(); 3990 $forumgenerator = $generator->get_plugin_generator('mod_forum'); 3991 $duedate = time() + DAYSECS; 3992 $cutoffdate = $duedate + DAYSECS; 3993 $forum = $forumgenerator->create_instance(['course' => $course->id]); 3994 $forum->duedate = $duedate; 3995 $forum->cutoffdate = $cutoffdate; 3996 $DB->update_record('forum', $forum); 3997 3998 // Create a valid event. 3999 $event = new \calendar_event([ 4000 'name' => 'Test event', 4001 'description' => '', 4002 'format' => 1, 4003 'courseid' => $course->id, 4004 'groupid' => 0, 4005 'userid' => 2, 4006 'modulename' => 'forum', 4007 'instance' => $forum->id, 4008 'eventtype' => FORUM_EVENT_TYPE_DUE . "SOMETHING ELSE", 4009 'timestart' => 1, 4010 'timeduration' => 86400, 4011 'visible' => 1 4012 ]); 4013 4014 mod_forum_core_calendar_event_timestart_updated($event, $forum); 4015 4016 $forum = $DB->get_record('forum', ['id' => $forum->id]); 4017 $this->assertEquals($duedate, $forum->duedate); 4018 $this->assertEquals($cutoffdate, $forum->cutoffdate); 4019 } 4020 4021 /** 4022 * Due date events should update the forum due date. 4023 */ 4024 public function test_mod_forum_core_calendar_event_timestart_updated_due_event() { 4025 global $CFG, $DB; 4026 require_once($CFG->dirroot . "/calendar/lib.php"); 4027 4028 $this->resetAfterTest(true); 4029 $this->setAdminUser(); 4030 $generator = $this->getDataGenerator(); 4031 $course = $generator->create_course(); 4032 $forumgenerator = $generator->get_plugin_generator('mod_forum'); 4033 $duedate = time() + DAYSECS; 4034 $cutoffdate = $duedate + DAYSECS; 4035 $newduedate = $duedate + 1; 4036 $forum = $forumgenerator->create_instance(['course' => $course->id]); 4037 $forum->duedate = $duedate; 4038 $forum->cutoffdate = $cutoffdate; 4039 $DB->update_record('forum', $forum); 4040 4041 // Create a valid event. 4042 $event = new \calendar_event([ 4043 'name' => 'Test event', 4044 'description' => '', 4045 'format' => 1, 4046 'courseid' => $course->id, 4047 'groupid' => 0, 4048 'userid' => 2, 4049 'modulename' => 'forum', 4050 'instance' => $forum->id, 4051 'eventtype' => FORUM_EVENT_TYPE_DUE, 4052 'timestart' => $newduedate, 4053 'timeduration' => 86400, 4054 'visible' => 1 4055 ]); 4056 4057 mod_forum_core_calendar_event_timestart_updated($event, $forum); 4058 4059 $forum = $DB->get_record('forum', ['id' => $forum->id]); 4060 $this->assertEquals($newduedate, $forum->duedate); 4061 $this->assertEquals($cutoffdate, $forum->cutoffdate); 4062 } 4063 4064 /** 4065 * Test forum_get_layout_modes function. 4066 */ 4067 public function test_forum_get_layout_modes() { 4068 $expectednormal = [ 4069 FORUM_MODE_FLATOLDEST => get_string('modeflatoldestfirst', 'forum'), 4070 FORUM_MODE_FLATNEWEST => get_string('modeflatnewestfirst', 'forum'), 4071 FORUM_MODE_THREADED => get_string('modethreaded', 'forum'), 4072 FORUM_MODE_NESTED => get_string('modenested', 'forum') 4073 ]; 4074 $expectedexperimental = [ 4075 FORUM_MODE_FLATOLDEST => get_string('modeflatoldestfirst', 'forum'), 4076 FORUM_MODE_FLATNEWEST => get_string('modeflatnewestfirst', 'forum'), 4077 FORUM_MODE_THREADED => get_string('modethreaded', 'forum'), 4078 FORUM_MODE_NESTED_V2 => get_string('modenestedv2', 'forum') 4079 ]; 4080 4081 $this->assertEquals($expectednormal, forum_get_layout_modes()); 4082 $this->assertEquals($expectednormal, forum_get_layout_modes(false)); 4083 $this->assertEquals($expectedexperimental, forum_get_layout_modes(true)); 4084 } 4085 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body