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