Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * The forum module mail generation tests. 19 * 20 * @package mod_forum 21 * @category external 22 * @copyright 2013 Andrew Nicols 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 global $CFG; 29 require_once($CFG->dirroot . '/mod/forum/lib.php'); 30 require_once (__DIR__ . '/cron_trait.php'); 31 require_once (__DIR__ . '/generator_trait.php'); 32 33 class mod_forum_mail_testcase extends advanced_testcase { 34 // Make use of the cron tester trait. 35 use mod_forum_tests_cron_trait; 36 37 // Make use of the test generator trait. 38 use mod_forum_tests_generator_trait; 39 40 /** 41 * @var \phpunit_message_sink 42 */ 43 protected $messagesink; 44 45 /** 46 * @var \phpunit_mailer_sink 47 */ 48 protected $mailsink; 49 50 public function setUp(): void { 51 global $CFG; 52 53 // We must clear the subscription caches. This has to be done both before each test, and after in case of other 54 // tests using these functions. 55 \mod_forum\subscriptions::reset_forum_cache(); 56 \mod_forum\subscriptions::reset_discussion_cache(); 57 58 // Messaging is not compatible with transactions... 59 $this->preventResetByRollback(); 60 61 // Catch all messages. 62 $this->messagesink = $this->redirectMessages(); 63 $this->mailsink = $this->redirectEmails(); 64 65 // Forcibly reduce the maxeditingtime to a second in the past to 66 // ensure that messages are sent out. 67 $CFG->maxeditingtime = -1; 68 } 69 70 public function tearDown(): void { 71 // We must clear the subscription caches. This has to be done both before each test, and after in case of other 72 // tests using these functions. 73 \mod_forum\subscriptions::reset_forum_cache(); 74 75 $this->messagesink->clear(); 76 $this->messagesink->close(); 77 unset($this->messagesink); 78 79 $this->mailsink->clear(); 80 $this->mailsink->close(); 81 unset($this->mailsink); 82 } 83 84 /** 85 * Perform message inbound setup for the mod_forum reply handler. 86 */ 87 protected function helper_spoof_message_inbound_setup() { 88 global $CFG, $DB; 89 // Setup the default Inbound Message mailbox settings. 90 $CFG->messageinbound_domain = 'example.com'; 91 $CFG->messageinbound_enabled = true; 92 93 // Must be no longer than 15 characters. 94 $CFG->messageinbound_mailbox = 'moodlemoodle123'; 95 96 $record = $DB->get_record('messageinbound_handlers', array('classname' => '\mod_forum\message\inbound\reply_handler')); 97 $record->enabled = true; 98 $record->id = $DB->update_record('messageinbound_handlers', $record); 99 } 100 101 public function test_cron_message_includes_courseid() { 102 $this->resetAfterTest(true); 103 104 // Create a course, with a forum. 105 $course = $this->getDataGenerator()->create_course(); 106 107 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 108 $forum = $this->getDataGenerator()->create_module('forum', $options); 109 110 // Create two users enrolled in the course as students. 111 list($author, $recipient) = $this->helper_create_users($course, 2); 112 113 // Post a discussion to the forum. 114 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 115 116 $expect = [ 117 'author' => (object) [ 118 'userid' => $author->id, 119 'messages' => 1, 120 ], 121 'recipient' => (object) [ 122 'userid' => $recipient->id, 123 'messages' => 1, 124 ], 125 ]; 126 $this->queue_tasks_and_assert($expect); 127 128 $this->messagesink->close(); 129 $this->eventsink = $this->redirectEvents(); 130 $this->send_notifications_and_assert($author, [$post]); 131 $events = $this->eventsink->get_events(); 132 $event = reset($events); 133 134 $this->assertEquals($course->id, $event->other['courseid']); 135 136 $this->send_notifications_and_assert($recipient, [$post]); 137 } 138 139 public function test_forced_subscription() { 140 global $DB; 141 $this->resetAfterTest(true); 142 143 // Create a course, with a forum. 144 $course = $this->getDataGenerator()->create_course(); 145 146 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 147 $forum = $this->getDataGenerator()->create_module('forum', $options); 148 149 // Create users enrolled in the course as students. 150 list($author, $recipient, $unconfirmed, $deleted) = $this->helper_create_users($course, 4); 151 152 // Make the third user unconfirmed (thence inactive) to make sure it does not break the notifications. 153 $DB->set_field('user', 'confirmed', 0, ['id' => $unconfirmed->id]); 154 155 // Mark the fourth user as deleted to make sure it does not break the notifications. 156 $DB->set_field('user', 'deleted', 1, ['id' => $deleted->id]); 157 158 // Post a discussion to the forum. 159 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 160 161 $expect = [ 162 (object) [ 163 'userid' => $author->id, 164 'messages' => 1, 165 ], 166 (object) [ 167 'userid' => $recipient->id, 168 'messages' => 1, 169 ], 170 (object) [ 171 'userid' => $unconfirmed->id, 172 'messages' => 0, 173 ], 174 (object) [ 175 'userid' => $deleted->id, 176 'messages' => 0, 177 ], 178 ]; 179 $this->queue_tasks_and_assert($expect); 180 181 $this->send_notifications_and_assert($author, [$post]); 182 $this->send_notifications_and_assert($recipient, [$post]); 183 $this->send_notifications_and_assert($unconfirmed, []); 184 $this->send_notifications_and_assert($deleted, []); 185 } 186 187 /** 188 * Ensure that for a forum with subscription disabled that standard users will not receive posts. 189 */ 190 public function test_subscription_disabled_standard_users() { 191 global $DB; 192 193 $this->resetAfterTest(true); 194 195 // Create a course, with a forum. 196 $course = $this->getDataGenerator()->create_course(); 197 198 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); 199 $forum = $this->getDataGenerator()->create_module('forum', $options); 200 201 // Create two users enrolled in the course as students. 202 list($author, $recipient) = $this->helper_create_users($course, 2); 203 204 // Post a discussion to the forum. 205 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 206 207 // Run cron and check that the expected number of users received the notification. 208 $expect = [ 209 (object) [ 210 'userid' => $author->id, 211 'messages' => 0, 212 ], 213 (object) [ 214 'userid' => $recipient->id, 215 'messages' => 0, 216 ], 217 ]; 218 $this->queue_tasks_and_assert($expect); 219 220 $this->send_notifications_and_assert($author, []); 221 $this->send_notifications_and_assert($recipient, []); 222 } 223 224 /** 225 * Ensure that for a forum with subscription disabled that a user subscribed to the forum will receive the post. 226 */ 227 public function test_subscription_disabled_user_subscribed_forum() { 228 global $DB; 229 230 $this->resetAfterTest(true); 231 232 // Create a course, with a forum. 233 $course = $this->getDataGenerator()->create_course(); 234 235 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); 236 $forum = $this->getDataGenerator()->create_module('forum', $options); 237 238 // Create two users enrolled in the course as students. 239 list($author, $recipient) = $this->helper_create_users($course, 2); 240 241 // A user with the manageactivities capability within the course can subscribe. 242 $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); 243 assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleids['student'], context_course::instance($course->id)); 244 245 // Suscribe the recipient only. 246 \mod_forum\subscriptions::subscribe_user($recipient->id, $forum); 247 248 $this->assertEquals(1, $DB->count_records('forum_subscriptions', array( 249 'userid' => $recipient->id, 250 'forum' => $forum->id, 251 ))); 252 253 // Post a discussion to the forum. 254 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 255 256 // Run cron and check that the expected number of users received the notification. 257 $expect = [ 258 'author' => (object) [ 259 'userid' => $author->id, 260 ], 261 'recipient' => (object) [ 262 'userid' => $recipient->id, 263 'messages' => 1, 264 ], 265 ]; 266 $this->queue_tasks_and_assert($expect); 267 268 $this->send_notifications_and_assert($author, []); 269 $this->send_notifications_and_assert($recipient, [$post]); 270 } 271 272 /** 273 * Ensure that for a forum with subscription disabled that a user subscribed to the discussion will receive the 274 * post. 275 */ 276 public function test_subscription_disabled_user_subscribed_discussion() { 277 global $DB; 278 279 $this->resetAfterTest(true); 280 281 // Create a course, with a forum. 282 $course = $this->getDataGenerator()->create_course(); 283 284 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); 285 $forum = $this->getDataGenerator()->create_module('forum', $options); 286 287 // Create two users enrolled in the course as students. 288 list($author, $recipient) = $this->helper_create_users($course, 2); 289 290 // A user with the manageactivities capability within the course can subscribe. 291 $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); 292 assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleids['student'], context_course::instance($course->id)); 293 294 // Run cron and check that the expected number of users received the notification. 295 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 296 297 // Subscribe the user to the discussion. 298 \mod_forum\subscriptions::subscribe_user_to_discussion($recipient->id, $discussion); 299 $this->helper_update_subscription_time($recipient, $discussion, -60); 300 301 // Run cron and check that the expected number of users received the notification. 302 $expect = [ 303 'author' => (object) [ 304 'userid' => $author->id, 305 ], 306 'recipient' => (object) [ 307 'userid' => $recipient->id, 308 'messages' => 1, 309 ], 310 ]; 311 $this->queue_tasks_and_assert($expect); 312 313 $this->send_notifications_and_assert($author, []); 314 $this->send_notifications_and_assert($recipient, [$post]); 315 } 316 317 /** 318 * Ensure that for a forum with automatic subscription that users receive posts. 319 */ 320 public function test_automatic() { 321 $this->resetAfterTest(true); 322 323 // Create a course, with a forum. 324 $course = $this->getDataGenerator()->create_course(); 325 326 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 327 $forum = $this->getDataGenerator()->create_module('forum', $options); 328 329 // Create two users enrolled in the course as students. 330 list($author, $recipient) = $this->helper_create_users($course, 2); 331 332 // Post a discussion to the forum. 333 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 334 335 $expect = [ 336 (object) [ 337 'userid' => $author->id, 338 'messages' => 1, 339 ], 340 (object) [ 341 'userid' => $recipient->id, 342 'messages' => 1, 343 ], 344 ]; 345 $this->queue_tasks_and_assert($expect); 346 347 $this->send_notifications_and_assert($author, [$post]); 348 $this->send_notifications_and_assert($recipient, [$post]); 349 } 350 351 /** 352 * Ensure that private replies are not sent to users with an automatic subscription unless they are an expected 353 * recipient. 354 */ 355 public function test_automatic_with_private_reply() { 356 $this->resetAfterTest(true); 357 358 // Create a course, with a forum. 359 $course = $this->getDataGenerator()->create_course(); 360 $forum = $this->getDataGenerator()->create_module('forum', [ 361 'course' => $course->id, 362 'forcesubscribe' => FORUM_INITIALSUBSCRIBE, 363 ]); 364 365 [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student'); 366 [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher'); 367 368 [$discussion, $post] = $this->helper_post_to_forum($forum, $student); 369 $reply = $this->helper_post_to_discussion($forum, $discussion, $teacher, [ 370 'privatereplyto' => $student->id, 371 ]); 372 373 // The private reply is queued to all messages as reply visibility may change between queueing, and sending. 374 $expect = [ 375 (object) [ 376 'userid' => $student->id, 377 'messages' => 2, 378 ], 379 (object) [ 380 'userid' => $otherstudent->id, 381 'messages' => 2, 382 ], 383 (object) [ 384 'userid' => $teacher->id, 385 'messages' => 2, 386 ], 387 (object) [ 388 'userid' => $otherteacher->id, 389 'messages' => 2, 390 ], 391 ]; 392 $this->queue_tasks_and_assert($expect); 393 394 // The actual messages sent will respect private replies. 395 $this->send_notifications_and_assert($student, [$post, $reply]); 396 $this->send_notifications_and_assert($teacher, [$post, $reply]); 397 $this->send_notifications_and_assert($otherteacher, [$post, $reply]); 398 $this->send_notifications_and_assert($otherstudent, [$post]); 399 } 400 401 public function test_optional() { 402 $this->resetAfterTest(true); 403 404 // Create a course, with a forum. 405 $course = $this->getDataGenerator()->create_course(); 406 407 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 408 $forum = $this->getDataGenerator()->create_module('forum', $options); 409 410 // Create two users enrolled in the course as students. 411 list($author, $recipient) = $this->helper_create_users($course, 2); 412 413 // Post a discussion to the forum. 414 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 415 416 $expect = [ 417 (object) [ 418 'userid' => $author->id, 419 'messages' => 0, 420 ], 421 (object) [ 422 'userid' => $recipient->id, 423 'messages' => 0, 424 ], 425 ]; 426 $this->queue_tasks_and_assert($expect); 427 428 $this->send_notifications_and_assert($author, []); 429 $this->send_notifications_and_assert($recipient, []); 430 } 431 432 public function test_automatic_with_unsubscribed_user() { 433 $this->resetAfterTest(true); 434 435 // Create a course, with a forum. 436 $course = $this->getDataGenerator()->create_course(); 437 438 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 439 $forum = $this->getDataGenerator()->create_module('forum', $options); 440 441 // Create two users enrolled in the course as students. 442 list($author, $recipient) = $this->helper_create_users($course, 2); 443 444 // Unsubscribe the 'author' user from the forum. 445 \mod_forum\subscriptions::unsubscribe_user($author->id, $forum); 446 447 // Post a discussion to the forum. 448 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 449 450 $expect = [ 451 (object) [ 452 'userid' => $author->id, 453 'messages' => 0, 454 ], 455 (object) [ 456 'userid' => $recipient->id, 457 'messages' => 1, 458 ], 459 ]; 460 $this->queue_tasks_and_assert($expect); 461 462 $this->send_notifications_and_assert($author, []); 463 $this->send_notifications_and_assert($recipient, [$post]); 464 } 465 466 public function test_optional_with_subscribed_user() { 467 $this->resetAfterTest(true); 468 469 // Create a course, with a forum. 470 $course = $this->getDataGenerator()->create_course(); 471 472 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 473 $forum = $this->getDataGenerator()->create_module('forum', $options); 474 475 // Create two users enrolled in the course as students. 476 list($author, $recipient) = $this->helper_create_users($course, 2); 477 478 // Subscribe the 'recipient' user from the forum. 479 \mod_forum\subscriptions::subscribe_user($recipient->id, $forum); 480 481 // Post a discussion to the forum. 482 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 483 484 $expect = [ 485 (object) [ 486 'userid' => $author->id, 487 'messages' => 0, 488 ], 489 (object) [ 490 'userid' => $recipient->id, 491 'messages' => 1, 492 ], 493 ]; 494 $this->queue_tasks_and_assert($expect); 495 496 $this->send_notifications_and_assert($author, []); 497 $this->send_notifications_and_assert($recipient, [$post]); 498 } 499 500 public function test_automatic_with_unsubscribed_discussion() { 501 $this->resetAfterTest(true); 502 503 // Create a course, with a forum. 504 $course = $this->getDataGenerator()->create_course(); 505 506 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 507 $forum = $this->getDataGenerator()->create_module('forum', $options); 508 509 // Create two users enrolled in the course as students. 510 list($author, $recipient) = $this->helper_create_users($course, 2); 511 512 // Post a discussion to the forum. 513 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 514 515 // Unsubscribe the 'author' user from the discussion. 516 \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion); 517 518 $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id)); 519 $this->assertTrue(\mod_forum\subscriptions::is_subscribed($recipient->id, $forum, $discussion->id)); 520 521 $expect = [ 522 (object) [ 523 'userid' => $author->id, 524 'messages' => 0, 525 ], 526 (object) [ 527 'userid' => $recipient->id, 528 'messages' => 1, 529 ], 530 ]; 531 $this->queue_tasks_and_assert($expect); 532 533 $this->send_notifications_and_assert($author, []); 534 $this->send_notifications_and_assert($recipient, [$post]); 535 } 536 537 public function test_optional_with_subscribed_discussion() { 538 $this->resetAfterTest(true); 539 540 // Create a course, with a forum. 541 $course = $this->getDataGenerator()->create_course(); 542 543 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 544 $forum = $this->getDataGenerator()->create_module('forum', $options); 545 546 // Create two users enrolled in the course as students. 547 list($author, $recipient) = $this->helper_create_users($course, 2); 548 549 // Post a discussion to the forum. 550 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 551 $this->helper_update_post_time($post, -90); 552 553 // Subscribe the 'recipient' user to the discussion. 554 \mod_forum\subscriptions::subscribe_user_to_discussion($recipient->id, $discussion); 555 $this->helper_update_subscription_time($recipient, $discussion, -60); 556 557 // Initially we don't expect any user to receive this post as you cannot subscribe to a discussion until after 558 // you have read it. 559 $expect = [ 560 (object) [ 561 'userid' => $author->id, 562 'messages' => 0, 563 ], 564 (object) [ 565 'userid' => $recipient->id, 566 'messages' => 0, 567 ], 568 ]; 569 $this->queue_tasks_and_assert($expect); 570 571 $this->send_notifications_and_assert($author, []); 572 $this->send_notifications_and_assert($recipient, []); 573 574 // Have a user reply to the discussion. 575 $reply = $this->helper_post_to_discussion($forum, $discussion, $author); 576 $this->helper_update_post_time($reply, -30); 577 578 // We expect only one user to receive this post. 579 $expect = [ 580 (object) [ 581 'userid' => $author->id, 582 'messages' => 0, 583 ], 584 (object) [ 585 'userid' => $recipient->id, 586 'messages' => 1, 587 ], 588 ]; 589 $this->queue_tasks_and_assert($expect); 590 591 $this->send_notifications_and_assert($author, []); 592 $this->send_notifications_and_assert($recipient, [$reply]); 593 } 594 595 public function test_optional_with_subscribed_discussion_and_post() { 596 $this->resetAfterTest(true); 597 598 // Create a course, with a forum. 599 $course = $this->getDataGenerator()->create_course(); 600 601 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 602 $forum = $this->getDataGenerator()->create_module('forum', $options); 603 604 // Create two users enrolled in the course as students. 605 list($author, $recipient) = $this->helper_create_users($course, 2); 606 607 // Post a discussion to the forum. 608 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 609 $this->helper_update_post_time($post, -90); 610 611 // Have a user reply to the discussion before we subscribed. 612 $reply = $this->helper_post_to_discussion($forum, $discussion, $author); 613 $this->helper_update_post_time($reply, -75); 614 615 // Subscribe the 'recipient' user to the discussion. 616 \mod_forum\subscriptions::subscribe_user_to_discussion($recipient->id, $discussion); 617 $this->helper_update_subscription_time($recipient, $discussion, -60); 618 619 // Have a user reply to the discussion. 620 $reply = $this->helper_post_to_discussion($forum, $discussion, $author); 621 $this->helper_update_post_time($reply, -30); 622 623 // We expect only one user to receive this post. 624 // The original post won't be received as it was written before the user subscribed. 625 $expect = [ 626 (object) [ 627 'userid' => $author->id, 628 'messages' => 0, 629 ], 630 (object) [ 631 'userid' => $recipient->id, 632 'messages' => 1, 633 ], 634 ]; 635 $this->queue_tasks_and_assert($expect); 636 637 $this->send_notifications_and_assert($author, []); 638 $this->send_notifications_and_assert($recipient, [$reply]); 639 } 640 641 public function test_automatic_with_subscribed_discussion_in_unsubscribed_forum() { 642 $this->resetAfterTest(true); 643 644 // Create a course, with a forum. 645 $course = $this->getDataGenerator()->create_course(); 646 647 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 648 $forum = $this->getDataGenerator()->create_module('forum', $options); 649 650 // Create two users enrolled in the course as students. 651 list($author, $recipient) = $this->helper_create_users($course, 2); 652 653 // Post a discussion to the forum. 654 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 655 $this->helper_update_post_time($post, -90); 656 657 // Unsubscribe the 'author' user from the forum. 658 \mod_forum\subscriptions::unsubscribe_user($author->id, $forum); 659 660 // Then re-subscribe them to the discussion. 661 \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion); 662 $this->helper_update_subscription_time($author, $discussion, -60); 663 664 $expect = [ 665 (object) [ 666 'userid' => $author->id, 667 'messages' => 0, 668 ], 669 (object) [ 670 'userid' => $recipient->id, 671 'messages' => 1, 672 ], 673 ]; 674 $this->queue_tasks_and_assert($expect); 675 676 $this->send_notifications_and_assert($author, []); 677 $this->send_notifications_and_assert($recipient, [$post]); 678 679 // Now post a reply to the original post. 680 $reply = $this->helper_post_to_discussion($forum, $discussion, $author); 681 $this->helper_update_post_time($reply, -30); 682 683 $expect = [ 684 (object) [ 685 'userid' => $author->id, 686 'messages' => 1, 687 ], 688 (object) [ 689 'userid' => $recipient->id, 690 'messages' => 1, 691 ], 692 ]; 693 $this->queue_tasks_and_assert($expect); 694 695 $this->send_notifications_and_assert($author, [$reply]); 696 $this->send_notifications_and_assert($recipient, [$reply]); 697 } 698 699 public function test_optional_with_unsubscribed_discussion_in_subscribed_forum() { 700 $this->resetAfterTest(true); 701 702 // Create a course, with a forum. 703 $course = $this->getDataGenerator()->create_course(); 704 705 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 706 $forum = $this->getDataGenerator()->create_module('forum', $options); 707 708 // Create two users enrolled in the course as students. 709 list($author, $recipient) = $this->helper_create_users($course, 2); 710 711 // Post a discussion to the forum. 712 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 713 714 // Unsubscribe the 'recipient' user from the discussion. 715 \mod_forum\subscriptions::subscribe_user($recipient->id, $forum); 716 717 // Then unsubscribe them from the discussion. 718 \mod_forum\subscriptions::unsubscribe_user_from_discussion($recipient->id, $discussion); 719 720 // We don't expect any users to receive this post. 721 $expect = [ 722 (object) [ 723 'userid' => $author->id, 724 'messages' => 0, 725 ], 726 (object) [ 727 'userid' => $recipient->id, 728 'messages' => 0, 729 ], 730 ]; 731 $this->queue_tasks_and_assert($expect); 732 733 $this->send_notifications_and_assert($author, []); 734 $this->send_notifications_and_assert($recipient, []); 735 } 736 737 /** 738 * Test that a user unsubscribed from a forum who has subscribed to a discussion, only receives posts made after 739 * they subscribed to the discussion. 740 */ 741 public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed_after_post() { 742 $this->resetAfterTest(true); 743 744 // Create a course, with a forum. 745 $course = $this->getDataGenerator()->create_course(); 746 747 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 748 $forum = $this->getDataGenerator()->create_module('forum', $options); 749 750 $expectedmessages = array(); 751 752 // Create a user enrolled in the course as a student. 753 list($author) = $this->helper_create_users($course, 1); 754 755 // Post a discussion to the forum. 756 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 757 $this->helper_update_post_time($post, -90); 758 759 $expectedmessages[] = array( 760 'id' => $post->id, 761 'subject' => $post->subject, 762 'count' => 0, 763 ); 764 765 // Then subscribe the user to the discussion. 766 $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion)); 767 $this->helper_update_subscription_time($author, $discussion, -60); 768 769 // Then post a reply to the first discussion. 770 $reply = $this->helper_post_to_discussion($forum, $discussion, $author); 771 $this->helper_update_post_time($reply, -30); 772 773 $expect = [ 774 (object) [ 775 'userid' => $author->id, 776 'messages' => 1, 777 ], 778 ]; 779 $this->queue_tasks_and_assert($expect); 780 781 $this->send_notifications_and_assert($author, [$reply]); 782 } 783 784 public function test_subscription_by_inactive_users() { 785 global $DB; 786 $this->resetAfterTest(true); 787 788 $course = $this->getDataGenerator()->create_course(); 789 790 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); 791 $forum = $this->getDataGenerator()->create_module('forum', $options); 792 793 // Create two users enrolled in the course as students. 794 list($author, $u1, $u2, $u3) = $this->helper_create_users($course, 4); 795 796 // Subscribe the three users to the forum. 797 \mod_forum\subscriptions::subscribe_user($u1->id, $forum); 798 \mod_forum\subscriptions::subscribe_user($u2->id, $forum); 799 \mod_forum\subscriptions::subscribe_user($u3->id, $forum); 800 801 // Make the first user inactive - suspended. 802 $DB->set_field('user', 'suspended', 1, ['id' => $u1->id]); 803 804 // Make the second user inactive - unable to log in. 805 $DB->set_field('user', 'auth', 'nologin', ['id' => $u2->id]); 806 807 // Post a discussion to the forum. 808 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 809 810 $expect = [ 811 (object) [ 812 'userid' => $u1->id, 813 'messages' => 0, 814 ], 815 (object) [ 816 'userid' => $u2->id, 817 'messages' => 0, 818 ], 819 (object) [ 820 'userid' => $u3->id, 821 'messages' => 1, 822 ], 823 ]; 824 825 $this->queue_tasks_and_assert($expect); 826 $this->send_notifications_and_assert($u1, []); 827 $this->send_notifications_and_assert($u2, []); 828 $this->send_notifications_and_assert($u3, [$post]); 829 } 830 831 public function test_forum_message_inbound_multiple_posts() { 832 $this->resetAfterTest(true); 833 834 // Create a course, with a forum. 835 $course = $this->getDataGenerator()->create_course(); 836 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 837 $forum = $this->getDataGenerator()->create_module('forum', $options); 838 839 // Create a user enrolled in the course as a student. 840 list($author) = $this->helper_create_users($course, 1); 841 842 $expectedmessages = array(); 843 844 // Post a discussion to the forum. 845 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 846 $this->helper_update_post_time($post, -90); 847 848 $expectedmessages[] = (object) [ 849 'id' => $post->id, 850 'subject' => $post->subject, 851 'count' => 0, 852 ]; 853 854 // Then post a reply to the first discussion. 855 $reply = $this->helper_post_to_discussion($forum, $discussion, $author); 856 $this->helper_update_post_time($reply, -60); 857 858 $expectedmessages[] = (object) [ 859 'id' => $reply->id, 860 'subject' => $reply->subject, 861 'count' => 1, 862 ]; 863 864 // Ensure that messageinbound is enabled and configured for the forum handler. 865 $this->helper_spoof_message_inbound_setup(); 866 867 $author->emailstop = '0'; 868 set_user_preference('message_provider_mod_forum_posts_loggedoff', 'email', $author); 869 set_user_preference('message_provider_mod_forum_posts_loggedin', 'email', $author); 870 871 // Run cron and check that the expected number of users received the notification. 872 // Clear the mailsink, and close the messagesink. 873 $this->mailsink->clear(); 874 $this->messagesink->close(); 875 876 $expect = [ 877 'author' => (object) [ 878 'userid' => $author->id, 879 'messages' => count($expectedmessages), 880 ], 881 ]; 882 $this->queue_tasks_and_assert($expect); 883 884 $this->send_notifications_and_assert($author, $expectedmessages); 885 $messages = $this->mailsink->get_messages(); 886 887 // There should be the expected number of messages. 888 $this->assertEquals(2, count($messages)); 889 890 foreach ($messages as $message) { 891 $this->assertRegExp('/Reply-To: moodlemoodle123\+[^@]*@example.com/', $message->header); 892 } 893 } 894 895 public function test_long_subject() { 896 $this->resetAfterTest(true); 897 898 // Create a course, with a forum. 899 $course = $this->getDataGenerator()->create_course(); 900 901 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 902 $forum = $this->getDataGenerator()->create_module('forum', $options); 903 904 // Create a user enrolled in the course as student. 905 list($author) = $this->helper_create_users($course, 1); 906 907 // Post a discussion to the forum. 908 $subject = 'This is the very long forum post subject that somebody was very kind of leaving, it is intended to check if long subject comes in mail correctly. Thank you.'; 909 $a = (object)array('courseshortname' => $course->shortname, 'forumname' => $forum->name, 'subject' => $subject); 910 $expectedsubject = get_string('postmailsubject', 'forum', $a); 911 list($discussion, $post) = $this->helper_post_to_forum($forum, $author, array('name' => $subject)); 912 913 // Run cron and check that the expected number of users received the notification. 914 $expect = [ 915 'author' => (object) [ 916 'userid' => $author->id, 917 'messages' => 1, 918 ], 919 ]; 920 $this->queue_tasks_and_assert($expect); 921 922 $this->send_notifications_and_assert($author, [$post]); 923 $messages = $this->messagesink->get_messages(); 924 $message = reset($messages); 925 $this->assertEquals($author->id, $message->useridfrom); 926 $this->assertEquals($expectedsubject, $message->subject); 927 } 928 929 /** 930 * Test inital email and reply email subjects 931 */ 932 public function test_subjects() { 933 $this->resetAfterTest(true); 934 935 $course = $this->getDataGenerator()->create_course(); 936 937 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 938 $forum = $this->getDataGenerator()->create_module('forum', $options); 939 940 list($author) = $this->helper_create_users($course, 1); 941 list($commenter) = $this->helper_create_users($course, 1); 942 943 $strre = get_string('re', 'forum'); 944 945 // New posts should not have Re: in the subject. 946 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 947 $expect = [ 948 'author' => (object) [ 949 'userid' => $author->id, 950 'messages' => 1, 951 ], 952 'commenter' => (object) [ 953 'userid' => $commenter->id, 954 'messages' => 1, 955 ], 956 ]; 957 $this->queue_tasks_and_assert($expect); 958 959 $this->send_notifications_and_assert($author, [$post]); 960 $this->send_notifications_and_assert($commenter, [$post]); 961 $messages = $this->messagesink->get_messages(); 962 $this->assertStringNotContainsString($strre, $messages[0]->subject); 963 $this->messagesink->clear(); 964 965 // Replies should have Re: in the subject. 966 $reply = $this->helper_post_to_discussion($forum, $discussion, $commenter); 967 968 $expect = [ 969 'author' => (object) [ 970 'userid' => $author->id, 971 'messages' => 1, 972 ], 973 'commenter' => (object) [ 974 'userid' => $commenter->id, 975 'messages' => 1, 976 ], 977 ]; 978 $this->queue_tasks_and_assert($expect); 979 980 $this->send_notifications_and_assert($commenter, [$reply]); 981 $this->send_notifications_and_assert($author, [$reply]); 982 $messages = $this->messagesink->get_messages(); 983 $this->assertStringContainsString($strre, $messages[0]->subject); 984 $this->assertStringContainsString($strre, $messages[1]->subject); 985 } 986 987 /** 988 * dataProvider for test_forum_post_email_templates(). 989 */ 990 public function forum_post_email_templates_provider() { 991 // Base information, we'll build variations based on it. 992 $base = array( 993 'user' => array('firstname' => 'Love', 'lastname' => 'Moodle', 'mailformat' => 0, 'maildigest' => 0), 994 'course' => array('shortname' => '101', 'fullname' => 'Moodle 101'), 995 'forums' => array( 996 array( 997 'name' => 'Moodle Forum', 998 'forumposts' => array( 999 array( 1000 'name' => 'Hello Moodle', 1001 'message' => 'Welcome to Moodle', 1002 'messageformat' => FORMAT_MOODLE, 1003 'attachments' => array( 1004 array( 1005 'filename' => 'example.txt', 1006 'filecontents' => 'Basic information about the course' 1007 ), 1008 ), 1009 ), 1010 ), 1011 ), 1012 ), 1013 'expectations' => array( 1014 array( 1015 'subject' => '.*101.*Hello', 1016 'contents' => array( 1017 '~{$a', 1018 '~&(amp|lt|gt|quot|\#039);(?!course)', 1019 'Attachment example.txt:' . PHP_EOL . 1020 'https://www.example.com/moodle/pluginfile.php/\d*/mod_forum/attachment/\d*/example.txt' . PHP_EOL, 1021 'Hello Moodle', 'Moodle Forum', 'Welcome.*Moodle', 'Love Moodle', '1\d1' 1022 ), 1023 ), 1024 ), 1025 ); 1026 1027 // Build the text cases. 1028 $textcases = array('Text mail without ampersands, quotes or lt/gt' => array('data' => $base)); 1029 1030 // Single and double quotes everywhere. 1031 $newcase = $base; 1032 $newcase['user']['lastname'] = 'Moodle\'"'; 1033 $newcase['course']['shortname'] = '101\'"'; 1034 $newcase['forums'][0]['name'] = 'Moodle Forum\'"'; 1035 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle\'"'; 1036 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle\'"'; 1037 $newcase['expectations'][0]['contents'] = array( 1038 'Attachment example.txt:', '~{\$a', '~&(quot|\#039);', 'Love Moodle\'', '101\'', 'Moodle Forum\'"', 1039 'Hello Moodle\'"', 'Welcome to Moodle\'"'); 1040 $textcases['Text mail with quotes everywhere'] = array('data' => $newcase); 1041 1042 // Lt and gt everywhere. This case is completely borked because format_string() 1043 // strips tags with $CFG->formatstringstriptags and also escapes < and > (correct 1044 // for web presentation but not for text email). See MDL-19829. 1045 $newcase = $base; 1046 $newcase['user']['lastname'] = 'Moodle>'; 1047 $newcase['course']['shortname'] = '101>'; 1048 $newcase['forums'][0]['name'] = 'Moodle Forum>'; 1049 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle>'; 1050 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle>'; 1051 $newcase['expectations'][0]['contents'] = array( 1052 'Attachment example.txt:', '~{\$a', '~&gt;', 'Love Moodle>', '101>', 'Moodle Forum>', 1053 'Hello Moodle>', 'Welcome to Moodle>'); 1054 $textcases['Text mail with gt and lt everywhere'] = array('data' => $newcase); 1055 1056 // Ampersands everywhere. This case is completely borked because format_string() 1057 // escapes ampersands (correct for web presentation but not for text email). See MDL-19829. 1058 $newcase = $base; 1059 $newcase['user']['lastname'] = 'Moodle&'; 1060 $newcase['course']['shortname'] = '101&'; 1061 $newcase['forums'][0]['name'] = 'Moodle Forum&'; 1062 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle&'; 1063 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle&'; 1064 $newcase['expectations'][0]['contents'] = array( 1065 'Attachment example.txt:', '~{\$a', '~&amp;', 'Love Moodle&', '101&', 'Moodle Forum&', 1066 'Hello Moodle&', 'Welcome to Moodle&'); 1067 $textcases['Text mail with ampersands everywhere'] = array('data' => $newcase); 1068 1069 // Text+image message i.e. @@PLUGINFILE@@ token handling. 1070 $newcase = $base; 1071 $newcase['forums'][0]['forumposts'][0]['name'] = 'Text and image'; 1072 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle, ' 1073 .'@@PLUGINFILE@@/Screen%20Shot%202016-03-22%20at%205.54.36%20AM%20%281%29.png !'; 1074 $newcase['expectations'][0]['subject'] = '.*101.*Text and image'; 1075 $newcase['expectations'][0]['contents'] = array( 1076 '~{$a', 1077 '~&(amp|lt|gt|quot|\#039);(?!course)', 1078 'Attachment example.txt:' . PHP_EOL . 1079 'https://www.example.com/moodle/pluginfile.php/\d*/mod_forum/attachment/\d*/example.txt' . PHP_EOL , 1080 'Text and image', 'Moodle Forum', 1081 'Welcome to Moodle, *' . PHP_EOL . '.*' 1082 .'https://www.example.com/moodle/pluginfile.php/\d+/mod_forum/post/\d+/' 1083 .'Screen%20Shot%202016-03-22%20at%205\.54\.36%20AM%20%281%29\.png *' . PHP_EOL . '.*!', 1084 'Love Moodle', '1\d1'); 1085 $textcases['Text mail with text+image message i.e. @@PLUGINFILE@@ token handling'] = array('data' => $newcase); 1086 1087 // Now the html cases. 1088 $htmlcases = array(); 1089 1090 // New base for html cases, no quotes, lts, gts or ampersands. 1091 $htmlbase = $base; 1092 $htmlbase['user']['mailformat'] = 1; 1093 $htmlbase['expectations'][0]['contents'] = array( 1094 '~{\$a', 1095 '~&(amp|lt|gt|quot|\#039);(?!course|lang|version|iosappid|androidappid)', 1096 '<div class="attachments">( *\n *)?<a href', 1097 '<div class="subject">\n.*Hello Moodle', '>Moodle Forum', '>Welcome.*Moodle', '>Love Moodle', '>1\d1'); 1098 $htmlcases['HTML mail without ampersands, quotes or lt/gt'] = array('data' => $htmlbase); 1099 1100 // Single and double quotes, lt and gt, ampersands everywhere. 1101 $newcase = $htmlbase; 1102 $newcase['user']['lastname'] = 'Moodle\'">&'; 1103 $newcase['course']['shortname'] = '101\'">&'; 1104 $newcase['forums'][0]['name'] = 'Moodle Forum\'">&'; 1105 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle\'">&'; 1106 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle\'">&'; 1107 $newcase['expectations'][0]['contents'] = array( 1108 '~{\$a', 1109 '~&(amp|lt|gt|quot|\#039);', 1110 '<div class="attachments">( *\n *)?<a href', 1111 '<div class="subject">\n.*Hello Moodle\'">&', '>Moodle Forum\'">&', 1112 '>Welcome.*Moodle\'">&', '>Love Moodle&\#039;">&', '>101\'">&'); 1113 $htmlcases['HTML mail with quotes, gt, lt and ampersand everywhere'] = array('data' => $newcase); 1114 1115 // Text+image message i.e. @@PLUGINFILE@@ token handling. 1116 $newcase = $htmlbase; 1117 $newcase['forums'][0]['forumposts'][0]['name'] = 'HTML text and image'; 1118 $newcase['forums'][0]['forumposts'][0]['message'] = '<p>Welcome to Moodle, ' 1119 .'<img src="@@PLUGINFILE@@/Screen%20Shot%202016-03-22%20at%205.54.36%20AM%20%281%29.png"' 1120 .' alt="" width="200" height="393" class="img-fluid" />!</p>'; 1121 $newcase['expectations'][0]['subject'] = '.*101.*HTML text and image'; 1122 $newcase['expectations'][0]['contents'] = array( 1123 '~{\$a', 1124 '~&(amp|lt|gt|quot|\#039);(?!course|lang|version|iosappid|androidappid)', 1125 '<div class="attachments">( *\n *)?<a href', 1126 '<div class="subject">\n.*HTML text and image', '>Moodle Forum', 1127 '<p>Welcome to Moodle, ' 1128 .'<img src="https://www.example.com/moodle/tokenpluginfile.php/[^/]*/\d+/mod_forum/post/\d+/' 1129 .'Screen%20Shot%202016-03-22%20at%205\.54\.36%20AM%20%281%29\.png"' 1130 .' alt="" width="200" height="393" class="img-fluid" />!</p>', 1131 '>Love Moodle', '>1\d1'); 1132 $htmlcases['HTML mail with text+image message i.e. @@PLUGINFILE@@ token handling'] = array('data' => $newcase); 1133 1134 return $textcases + $htmlcases; 1135 } 1136 1137 /** 1138 * Verify forum emails body using templates to generate the expected results. 1139 * 1140 * @dataProvider forum_post_email_templates_provider 1141 * @param array $data provider samples. 1142 */ 1143 public function test_forum_post_email_templates($data) { 1144 global $DB; 1145 1146 $this->resetAfterTest(); 1147 1148 // Create the course, with the specified options. 1149 $options = array(); 1150 foreach ($data['course'] as $option => $value) { 1151 $options[$option] = $value; 1152 } 1153 $course = $this->getDataGenerator()->create_course($options); 1154 1155 // Create the user, with the specified options and enrol in the course. 1156 $options = array(); 1157 foreach ($data['user'] as $option => $value) { 1158 $options[$option] = $value; 1159 } 1160 $user = $this->getDataGenerator()->create_user($options); 1161 $this->getDataGenerator()->enrol_user($user->id, $course->id); 1162 1163 // Create forums, always force susbscribed (for easy), with the specified options. 1164 $posts = array(); 1165 foreach ($data['forums'] as $dataforum) { 1166 $forumposts = isset($dataforum['forumposts']) ? $dataforum['forumposts'] : array(); 1167 unset($dataforum['forumposts']); 1168 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 1169 foreach ($dataforum as $option => $value) { 1170 $options[$option] = $value; 1171 } 1172 $forum = $this->getDataGenerator()->create_module('forum', $options); 1173 1174 // Create posts, always for immediate delivery (for easy), with the specified options. 1175 foreach ($forumposts as $forumpost) { 1176 $attachments = isset($forumpost['attachments']) ? $forumpost['attachments'] : array(); 1177 unset($forumpost['attachments']); 1178 $postoptions = array('course' => $course->id, 'forum' => $forum->id, 'userid' => $user->id, 1179 'mailnow' => 1, 'attachment' => !empty($attachments)); 1180 foreach ($forumpost as $option => $value) { 1181 $postoptions[$option] = $value; 1182 } 1183 list($discussion, $post) = $this->helper_post_to_forum($forum, $user, $postoptions); 1184 $posts[$post->subject] = $post; // Need this to verify cron output. 1185 1186 // Add the attachments to the post. 1187 if ($attachments) { 1188 $fs = get_file_storage(); 1189 foreach ($attachments as $attachment) { 1190 $filerecord = array( 1191 'contextid' => context_module::instance($forum->cmid)->id, 1192 'component' => 'mod_forum', 1193 'filearea' => 'attachment', 1194 'itemid' => $post->id, 1195 'filepath' => '/', 1196 'filename' => $attachment['filename'] 1197 ); 1198 $fs->create_file_from_string($filerecord, $attachment['filecontents']); 1199 } 1200 $DB->set_field('forum_posts', 'attachment', '1', array('id' => $post->id)); 1201 } 1202 } 1203 } 1204 1205 // Clear the mailsink and close the messagesink. 1206 // (surely setup should provide us this cleared but...) 1207 $this->mailsink->clear(); 1208 $this->messagesink->close(); 1209 1210 $expect = [ 1211 'author' => (object) [ 1212 'userid' => $user->id, 1213 'messages' => count($posts), 1214 ], 1215 ]; 1216 $this->queue_tasks_and_assert($expect); 1217 1218 $this->send_notifications_and_assert($user, $posts); 1219 1220 // Get the mails. 1221 $mails = $this->mailsink->get_messages(); 1222 1223 // Start testing the expectations. 1224 $expectations = $data['expectations']; 1225 1226 // Assert the number is the expected. 1227 $this->assertSame(count($expectations), count($mails)); 1228 1229 // Start processing mails, first localizing its expectations, then checking them. 1230 foreach ($mails as $mail) { 1231 // Find the corresponding expectation. 1232 $foundexpectation = null; 1233 foreach ($expectations as $key => $expectation) { 1234 // All expectations must have a subject for matching. 1235 if (!isset($expectation['subject'])) { 1236 $this->fail('Provider expectation missing mandatory subject'); 1237 } 1238 if (preg_match('!' . $expectation['subject'] . '!', $mail->subject)) { 1239 // If we already had found the expectation, there are non-unique subjects. Fail. 1240 if (isset($foundexpectation)) { 1241 $this->fail('Multiple expectations found (by subject matching). Please make them unique.'); 1242 } 1243 $foundexpectation = $expectation; 1244 unset($expectations[$key]); 1245 } 1246 } 1247 // Arrived here, we should have found the expectations. 1248 $this->assertNotEmpty($foundexpectation, 'Expectation not found for the mail'); 1249 1250 // If we have found the expectation and have contents to match, let's do it. 1251 if (isset($foundexpectation) and isset($foundexpectation['contents'])) { 1252 $mail->body = quoted_printable_decode($mail->body); 1253 if (!is_array($foundexpectation['contents'])) { // Accept both string and array. 1254 $foundexpectation['contents'] = array($foundexpectation['contents']); 1255 } 1256 foreach ($foundexpectation['contents'] as $content) { 1257 if (strpos($content, '~') !== 0) { 1258 $this->assertRegexp('#' . $content . '#m', $mail->body); 1259 } else { 1260 preg_match('#' . substr($content, 1) . '#m', $mail->body, $matches); 1261 $this->assertNotRegexp('#' . substr($content, 1) . '#m', $mail->body); 1262 } 1263 } 1264 } 1265 } 1266 1267 // Finished, there should not be remaining expectations. 1268 $this->assertCount(0, $expectations); 1269 } 1270 1271 /** 1272 * Ensure that posts already mailed are not re-sent. 1273 */ 1274 public function test_already_mailed() { 1275 global $DB; 1276 1277 $this->resetAfterTest(true); 1278 1279 // Create a course, with a forum. 1280 $course = $this->getDataGenerator()->create_course(); 1281 1282 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1283 $forum = $this->getDataGenerator()->create_module('forum', $options); 1284 1285 // Create two users enrolled in the course as students. 1286 list($author, $recipient) = $this->helper_create_users($course, 2); 1287 1288 // Post a discussion to the forum. 1289 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1290 $DB->set_field('forum_posts', 'mailed', 1); 1291 1292 // No posts shoudl be considered. 1293 $this->queue_tasks_and_assert([]); 1294 1295 // No notifications should be queued. 1296 $this->send_notifications_and_assert($author, []); 1297 $this->send_notifications_and_assert($recipient, []); 1298 } 1299 1300 /** 1301 * Ensure that posts marked mailnow are not suspect to the maxeditingtime. 1302 */ 1303 public function test_mailnow() { 1304 global $CFG, $DB; 1305 1306 // Update the maxeditingtime to 1 day so that posts won't be sent. 1307 $CFG->maxeditingtime = DAYSECS; 1308 1309 $this->resetAfterTest(true); 1310 1311 // Create a course, with a forum. 1312 $course = $this->getDataGenerator()->create_course(); 1313 1314 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1315 $forum = $this->getDataGenerator()->create_module('forum', $options); 1316 1317 // Create two users enrolled in the course as students. 1318 list($author, $recipient) = $this->helper_create_users($course, 2); 1319 1320 // Post a discussion to the forum. 1321 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1322 1323 // Post a discussion to the forum. 1324 list($discussion, $postmailednow) = $this->helper_post_to_forum($forum, $author, ['mailnow' => 1]); 1325 1326 // Only the mailnow post should be considered. 1327 $expect = [ 1328 'author' => (object) [ 1329 'userid' => $author->id, 1330 'messages' => 1, 1331 ], 1332 'recipient' => (object) [ 1333 'userid' => $recipient->id, 1334 'messages' => 1, 1335 ], 1336 ]; 1337 $this->queue_tasks_and_assert($expect); 1338 1339 // No notifications should be queued. 1340 $this->send_notifications_and_assert($author, [$postmailednow]); 1341 $this->send_notifications_and_assert($recipient, [$postmailednow]); 1342 } 1343 1344 /** 1345 * Ensure that if a user has no permission to view a post, then it is not sent. 1346 */ 1347 public function test_access_coursemodule_hidden() { 1348 global $CFG, $DB; 1349 1350 $this->resetAfterTest(true); 1351 1352 // Create a course, with a forum. 1353 $course = $this->getDataGenerator()->create_course(); 1354 1355 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1356 $forum = $this->getDataGenerator()->create_module('forum', $options); 1357 1358 // Create two users enrolled in the course as students. 1359 list($author, $recipient) = $this->helper_create_users($course, 2); 1360 1361 // Create one users enrolled in the course as an editing teacher. 1362 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1363 1364 // Post a discussion to the forum. 1365 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1366 1367 // Hide the coursemodule. 1368 set_coursemodule_visible($forum->cmid, 0); 1369 1370 // Only the mailnow post should be considered. 1371 $expect = [ 1372 'author' => (object) [ 1373 'userid' => $author->id, 1374 'messages' => 1, 1375 ], 1376 'recipient' => (object) [ 1377 'userid' => $recipient->id, 1378 'messages' => 1, 1379 ], 1380 'editor' => (object) [ 1381 'userid' => $editor->id, 1382 'messages' => 1, 1383 ], 1384 ]; 1385 $this->queue_tasks_and_assert($expect); 1386 1387 // No notifications should be queued. 1388 $this->send_notifications_and_assert($author, [], true); 1389 $this->send_notifications_and_assert($recipient, [], true); 1390 $this->send_notifications_and_assert($editor, [$post], true); 1391 } 1392 1393 /** 1394 * Ensure that if a user loses permission to view a post after it is queued, that it is not sent. 1395 */ 1396 public function test_access_coursemodule_hidden_after_queue() { 1397 global $CFG, $DB; 1398 1399 $this->resetAfterTest(true); 1400 1401 // Create a course, with a forum. 1402 $course = $this->getDataGenerator()->create_course(); 1403 1404 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1405 $forum = $this->getDataGenerator()->create_module('forum', $options); 1406 1407 // Create two users enrolled in the course as students. 1408 list($author, $recipient) = $this->helper_create_users($course, 2); 1409 1410 // Create one users enrolled in the course as an editing teacher. 1411 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1412 1413 // Post a discussion to the forum. 1414 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1415 1416 // Only the mailnow post should be considered. 1417 $expect = [ 1418 'author' => (object) [ 1419 'userid' => $author->id, 1420 'messages' => 1, 1421 ], 1422 'recipient' => (object) [ 1423 'userid' => $recipient->id, 1424 'messages' => 1, 1425 ], 1426 'editor' => (object) [ 1427 'userid' => $editor->id, 1428 'messages' => 1, 1429 ], 1430 ]; 1431 $this->queue_tasks_and_assert($expect); 1432 1433 // Hide the coursemodule. 1434 set_coursemodule_visible($forum->cmid, 0); 1435 1436 // No notifications should be queued for the students. 1437 $this->send_notifications_and_assert($author, [], true); 1438 $this->send_notifications_and_assert($recipient, [], true); 1439 1440 // The editing teacher should still receive the post. 1441 $this->send_notifications_and_assert($editor, [$post]); 1442 } 1443 1444 /** 1445 * Ensure that messages are not sent until the timestart. 1446 */ 1447 public function test_access_before_timestart() { 1448 global $CFG, $DB; 1449 1450 $this->resetAfterTest(true); 1451 1452 // Create a course, with a forum. 1453 $course = $this->getDataGenerator()->create_course(); 1454 1455 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1456 $forum = $this->getDataGenerator()->create_module('forum', $options); 1457 1458 // Create two users enrolled in the course as students. 1459 list($author, $recipient) = $this->helper_create_users($course, 2); 1460 1461 // Create one users enrolled in the course as an editing teacher. 1462 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1463 1464 // Post a discussion to the forum. 1465 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1466 1467 // Update the discussion to have a timestart in the future. 1468 $DB->set_field('forum_discussions', 'timestart', time() + DAYSECS); 1469 1470 // None should be sent. 1471 $this->queue_tasks_and_assert([]); 1472 1473 // No notifications should be queued for any user. 1474 $this->send_notifications_and_assert($author, []); 1475 $this->send_notifications_and_assert($recipient, []); 1476 $this->send_notifications_and_assert($editor, []); 1477 1478 // Update the discussion to have a timestart in the past. 1479 $DB->set_field('forum_discussions', 'timestart', time() - DAYSECS); 1480 1481 // Now should be sent to all. 1482 $expect = [ 1483 'author' => (object) [ 1484 'userid' => $author->id, 1485 'messages' => 1, 1486 ], 1487 'recipient' => (object) [ 1488 'userid' => $recipient->id, 1489 'messages' => 1, 1490 ], 1491 'editor' => (object) [ 1492 'userid' => $editor->id, 1493 'messages' => 1, 1494 ], 1495 ]; 1496 $this->queue_tasks_and_assert($expect); 1497 1498 // No notifications should be queued for any user. 1499 $this->send_notifications_and_assert($author, [$post]); 1500 $this->send_notifications_and_assert($recipient, [$post]); 1501 $this->send_notifications_and_assert($editor, [$post]); 1502 } 1503 1504 /** 1505 * Ensure that messages are not sent after the timeend. 1506 */ 1507 public function test_access_after_timeend() { 1508 global $CFG, $DB; 1509 1510 $this->resetAfterTest(true); 1511 1512 // Create a course, with a forum. 1513 $course = $this->getDataGenerator()->create_course(); 1514 1515 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1516 $forum = $this->getDataGenerator()->create_module('forum', $options); 1517 1518 // Create two users enrolled in the course as students. 1519 list($author, $recipient) = $this->helper_create_users($course, 2); 1520 1521 // Create one users enrolled in the course as an editing teacher. 1522 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1523 1524 // Post a discussion to the forum. 1525 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1526 1527 // Update the discussion to have a timestart in the past. 1528 $DB->set_field('forum_discussions', 'timeend', time() - DAYSECS); 1529 1530 // None should be sent. 1531 $this->queue_tasks_and_assert([]); 1532 1533 // No notifications should be queued for any user. 1534 $this->send_notifications_and_assert($author, []); 1535 $this->send_notifications_and_assert($recipient, []); 1536 $this->send_notifications_and_assert($editor, []); 1537 1538 // Update the discussion to have a timestart in the past. 1539 $DB->set_field('forum_discussions', 'timeend', time() + DAYSECS); 1540 1541 // Now should be sent to all. 1542 $expect = [ 1543 'author' => (object) [ 1544 'userid' => $author->id, 1545 'messages' => 1, 1546 ], 1547 'recipient' => (object) [ 1548 'userid' => $recipient->id, 1549 'messages' => 1, 1550 ], 1551 'editor' => (object) [ 1552 'userid' => $editor->id, 1553 'messages' => 1, 1554 ], 1555 ]; 1556 $this->queue_tasks_and_assert($expect); 1557 1558 // No notifications should be queued for any user. 1559 $this->send_notifications_and_assert($author, [$post]); 1560 $this->send_notifications_and_assert($recipient, [$post]); 1561 $this->send_notifications_and_assert($editor, [$post]); 1562 } 1563 1564 /** 1565 * Test notification comes with customdata. 1566 */ 1567 public function test_notification_customdata() { 1568 $this->resetAfterTest(true); 1569 1570 $course = $this->getDataGenerator()->create_course(); 1571 1572 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 1573 $forum = $this->getDataGenerator()->create_module('forum', $options); 1574 1575 list($author) = $this->helper_create_users($course, 1); 1576 list($commenter) = $this->helper_create_users($course, 1); 1577 1578 $strre = get_string('re', 'forum'); 1579 1580 // New posts should not have Re: in the subject. 1581 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1582 $expect = [ 1583 'author' => (object) [ 1584 'userid' => $author->id, 1585 'messages' => 1, 1586 ], 1587 'commenter' => (object) [ 1588 'userid' => $commenter->id, 1589 'messages' => 1, 1590 ], 1591 ]; 1592 $this->queue_tasks_and_assert($expect); 1593 1594 $this->send_notifications_and_assert($author, [$post]); 1595 $this->send_notifications_and_assert($commenter, [$post]); 1596 $messages = $this->messagesink->get_messages(); 1597 $customdata = json_decode($messages[0]->customdata); 1598 $this->assertEquals($forum->id, $customdata->instance); 1599 $this->assertEquals($forum->cmid, $customdata->cmid); 1600 $this->assertEquals($post->id, $customdata->postid); 1601 $this->assertEquals($discussion->id, $customdata->discussionid); 1602 $this->assertObjectHasAttribute('notificationiconurl', $customdata); 1603 $this->assertObjectHasAttribute('actionbuttons', $customdata); 1604 $this->assertCount(1, (array) $customdata->actionbuttons); 1605 } 1606 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body