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