Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
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_loggedoff', 'email', $author); 874 set_user_preference('message_provider_mod_forum_posts_loggedin', 'email', $author); 875 876 // Run cron and check that the expected number of users received the notification. 877 // Clear the mailsink, and close the messagesink. 878 $this->mailsink->clear(); 879 $this->messagesink->close(); 880 881 $expect = [ 882 'author' => (object) [ 883 'userid' => $author->id, 884 'messages' => count($expectedmessages), 885 ], 886 ]; 887 $this->queue_tasks_and_assert($expect); 888 889 $this->send_notifications_and_assert($author, $expectedmessages); 890 $messages = $this->mailsink->get_messages(); 891 892 // There should be the expected number of messages. 893 $this->assertEquals(2, count($messages)); 894 895 foreach ($messages as $message) { 896 $this->assertMatchesRegularExpression('/Reply-To: moodlemoodle123\+[^@]*@example.com/', $message->header); 897 } 898 } 899 900 public function test_long_subject() { 901 $this->resetAfterTest(true); 902 903 // Create a course, with a forum. 904 $course = $this->getDataGenerator()->create_course(); 905 906 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 907 $forum = $this->getDataGenerator()->create_module('forum', $options); 908 909 // Create a user enrolled in the course as student. 910 list($author) = $this->helper_create_users($course, 1); 911 912 // Post a discussion to the forum. 913 $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.'; 914 $a = (object)array('courseshortname' => $course->shortname, 'forumname' => $forum->name, 'subject' => $subject); 915 $expectedsubject = get_string('postmailsubject', 'forum', $a); 916 list($discussion, $post) = $this->helper_post_to_forum($forum, $author, array('name' => $subject)); 917 918 // Run cron and check that the expected number of users received the notification. 919 $expect = [ 920 'author' => (object) [ 921 'userid' => $author->id, 922 'messages' => 1, 923 ], 924 ]; 925 $this->queue_tasks_and_assert($expect); 926 927 $this->send_notifications_and_assert($author, [$post]); 928 $messages = $this->messagesink->get_messages(); 929 $message = reset($messages); 930 $this->assertEquals($author->id, $message->useridfrom); 931 $this->assertEquals($expectedsubject, $message->subject); 932 } 933 934 /** 935 * Test inital email and reply email subjects 936 */ 937 public function test_subjects() { 938 $this->resetAfterTest(true); 939 940 $course = $this->getDataGenerator()->create_course(); 941 942 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 943 $forum = $this->getDataGenerator()->create_module('forum', $options); 944 945 list($author) = $this->helper_create_users($course, 1); 946 list($commenter) = $this->helper_create_users($course, 1); 947 948 $strre = get_string('re', 'forum'); 949 950 // New posts should not have Re: in the subject. 951 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 952 $expect = [ 953 'author' => (object) [ 954 'userid' => $author->id, 955 'messages' => 1, 956 ], 957 'commenter' => (object) [ 958 'userid' => $commenter->id, 959 'messages' => 1, 960 ], 961 ]; 962 $this->queue_tasks_and_assert($expect); 963 964 $this->send_notifications_and_assert($author, [$post]); 965 $this->send_notifications_and_assert($commenter, [$post]); 966 $messages = $this->messagesink->get_messages(); 967 $this->assertStringNotContainsString($strre, $messages[0]->subject); 968 $this->messagesink->clear(); 969 970 // Replies should have Re: in the subject. 971 $reply = $this->helper_post_to_discussion($forum, $discussion, $commenter); 972 973 $expect = [ 974 'author' => (object) [ 975 'userid' => $author->id, 976 'messages' => 1, 977 ], 978 'commenter' => (object) [ 979 'userid' => $commenter->id, 980 'messages' => 1, 981 ], 982 ]; 983 $this->queue_tasks_and_assert($expect); 984 985 $this->send_notifications_and_assert($commenter, [$reply]); 986 $this->send_notifications_and_assert($author, [$reply]); 987 $messages = $this->messagesink->get_messages(); 988 $this->assertStringContainsString($strre, $messages[0]->subject); 989 $this->assertStringContainsString($strre, $messages[1]->subject); 990 } 991 992 /** 993 * dataProvider for test_forum_post_email_templates(). 994 */ 995 public function forum_post_email_templates_provider() { 996 // Base information, we'll build variations based on it. 997 $base = array( 998 'user' => array('firstname' => 'Love', 'lastname' => 'Moodle', 'mailformat' => 0, 'maildigest' => 0), 999 'course' => array('shortname' => '101', 'fullname' => 'Moodle 101'), 1000 'forums' => array( 1001 array( 1002 'name' => 'Moodle Forum', 1003 'forumposts' => array( 1004 array( 1005 'name' => 'Hello Moodle', 1006 'message' => 'Welcome to Moodle', 1007 'messageformat' => FORMAT_MOODLE, 1008 'attachments' => array( 1009 array( 1010 'filename' => 'example.txt', 1011 'filecontents' => 'Basic information about the course' 1012 ), 1013 ), 1014 ), 1015 ), 1016 ), 1017 ), 1018 'expectations' => array( 1019 array( 1020 'subject' => '.*101.*Hello', 1021 'contents' => array( 1022 '~{$a', 1023 '~&(amp|lt|gt|quot|\#039);(?!course)', 1024 'Attachment example.txt:' . '\r*\n' . 1025 'https://www.example.com/moodle/pluginfile.php/\d*/mod_forum/attachment/\d*/example.txt' . '\r*\n', 1026 'Hello Moodle', 'Moodle Forum', 'Welcome.*Moodle', 'Love Moodle', '1\d1' 1027 ), 1028 ), 1029 ), 1030 ); 1031 1032 // Build the text cases. 1033 $textcases = array('Text mail without ampersands, quotes or lt/gt' => array('data' => $base)); 1034 1035 // Single and double quotes everywhere. 1036 $newcase = $base; 1037 $newcase['user']['lastname'] = 'Moodle\'"'; 1038 $newcase['course']['shortname'] = '101\'"'; 1039 $newcase['forums'][0]['name'] = 'Moodle Forum\'"'; 1040 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle\'"'; 1041 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle\'"'; 1042 $newcase['expectations'][0]['contents'] = array( 1043 'Attachment example.txt:', '~{\$a', '~&(quot|\#039);', 'Love Moodle\'', '101\'', 'Moodle Forum\'"', 1044 'Hello Moodle\'"', 'Welcome to Moodle\'"'); 1045 $textcases['Text mail with quotes everywhere'] = array('data' => $newcase); 1046 1047 // Lt and gt everywhere. This case is completely borked because format_string() 1048 // strips tags with $CFG->formatstringstriptags and also escapes < and > (correct 1049 // for web presentation but not for text email). See MDL-19829. 1050 $newcase = $base; 1051 $newcase['user']['lastname'] = 'Moodle>'; 1052 $newcase['course']['shortname'] = '101>'; 1053 $newcase['forums'][0]['name'] = 'Moodle Forum>'; 1054 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle>'; 1055 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle>'; 1056 $newcase['expectations'][0]['contents'] = array( 1057 'Attachment example.txt:', '~{\$a', '~&gt;', 'Love Moodle>', '101>', 'Moodle Forum>', 1058 'Hello Moodle>', 'Welcome to Moodle>'); 1059 $textcases['Text mail with gt and lt everywhere'] = array('data' => $newcase); 1060 1061 // Ampersands everywhere. This case is completely borked because format_string() 1062 // escapes ampersands (correct for web presentation but not for text email). See MDL-19829. 1063 $newcase = $base; 1064 $newcase['user']['lastname'] = 'Moodle&'; 1065 $newcase['course']['shortname'] = '101&'; 1066 $newcase['forums'][0]['name'] = 'Moodle Forum&'; 1067 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle&'; 1068 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle&'; 1069 $newcase['expectations'][0]['contents'] = array( 1070 'Attachment example.txt:', '~{\$a', '~&amp;', 'Love Moodle&', '101&', 'Moodle Forum&', 1071 'Hello Moodle&', 'Welcome to Moodle&'); 1072 $textcases['Text mail with ampersands everywhere'] = array('data' => $newcase); 1073 1074 // Text+image message i.e. @@PLUGINFILE@@ token handling. 1075 $newcase = $base; 1076 $newcase['forums'][0]['forumposts'][0]['name'] = 'Text and image'; 1077 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle, ' 1078 .'@@PLUGINFILE@@/Screen%20Shot%202016-03-22%20at%205.54.36%20AM%20%281%29.png !'; 1079 $newcase['expectations'][0]['subject'] = '.*101.*Text and image'; 1080 $newcase['expectations'][0]['contents'] = array( 1081 '~{$a', 1082 '~&(amp|lt|gt|quot|\#039);(?!course)', 1083 'Attachment example.txt:' . '\r*\n' . 1084 'https://www.example.com/moodle/pluginfile.php/\d*/mod_forum/attachment/\d*/example.txt' . '\r*\n' , 1085 'Text and image', 'Moodle Forum', 1086 'Welcome to Moodle, *' . '\r*\n' . '.*' 1087 .'https://www.example.com/moodle/pluginfile.php/\d+/mod_forum/post/\d+/' 1088 .'Screen%20Shot%202016-03-22%20at%205\.54\.36%20AM%20%281%29\.png *' . '\r*\n' . '.*!', 1089 'Love Moodle', '1\d1'); 1090 $textcases['Text mail with text+image message i.e. @@PLUGINFILE@@ token handling'] = array('data' => $newcase); 1091 1092 // Now the html cases. 1093 $htmlcases = array(); 1094 1095 // New base for html cases, no quotes, lts, gts or ampersands. 1096 $htmlbase = $base; 1097 $htmlbase['user']['mailformat'] = 1; 1098 $htmlbase['expectations'][0]['contents'] = array( 1099 '~{\$a', 1100 '~&(amp|lt|gt|quot|\#039);(?!course|lang|version|iosappid|androidappid)', 1101 '<div class="attachments">( *\n *)?<a href', 1102 '<div class="subject">\n.*Hello Moodle', '>Moodle Forum', '>Welcome.*Moodle', '>Love Moodle', '>1\d1'); 1103 $htmlcases['HTML mail without ampersands, quotes or lt/gt'] = array('data' => $htmlbase); 1104 1105 // Single and double quotes, lt and gt, ampersands everywhere. 1106 $newcase = $htmlbase; 1107 $newcase['user']['lastname'] = 'Moodle\'">&'; 1108 $newcase['course']['shortname'] = '101\'">&'; 1109 $newcase['forums'][0]['name'] = 'Moodle Forum\'">&'; 1110 $newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle\'">&'; 1111 $newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle\'">&'; 1112 $newcase['expectations'][0]['contents'] = array( 1113 '~{\$a', 1114 '~&(amp|lt|gt|quot|\#039);', 1115 '<div class="attachments">( *\n *)?<a href', 1116 '<div class="subject">\n.*Hello Moodle\'">&', '>Moodle Forum\'">&', 1117 '>Welcome.*Moodle\'">&', '>Love Moodle&\#039;">&', '>101\'">&'); 1118 $htmlcases['HTML mail with quotes, gt, lt and ampersand everywhere'] = array('data' => $newcase); 1119 1120 // Text+image message i.e. @@PLUGINFILE@@ token handling. 1121 $newcase = $htmlbase; 1122 $newcase['forums'][0]['forumposts'][0]['name'] = 'HTML text and image'; 1123 $newcase['forums'][0]['forumposts'][0]['message'] = '<p>Welcome to Moodle, ' 1124 .'<img src="@@PLUGINFILE@@/Screen%20Shot%202016-03-22%20at%205.54.36%20AM%20%281%29.png"' 1125 .' alt="" width="200" height="393" class="img-fluid" />!</p>'; 1126 $newcase['expectations'][0]['subject'] = '.*101.*HTML text and image'; 1127 $newcase['expectations'][0]['contents'] = array( 1128 '~{\$a', 1129 '~&(amp|lt|gt|quot|\#039);(?!course|lang|version|iosappid|androidappid)', 1130 '<div class="attachments">( *\n *)?<a href', 1131 '<div class="subject">\n.*HTML text and image', '>Moodle Forum', 1132 '<p>Welcome to Moodle, ' 1133 .'<img src="https://www.example.com/moodle/tokenpluginfile.php/[^/]*/\d+/mod_forum/post/\d+/' 1134 .'Screen%20Shot%202016-03-22%20at%205\.54\.36%20AM%20%281%29\.png"' 1135 .' alt="" width="200" height="393" class="img-fluid" />!</p>', 1136 '>Love Moodle', '>1\d1'); 1137 $htmlcases['HTML mail with text+image message i.e. @@PLUGINFILE@@ token handling'] = array('data' => $newcase); 1138 1139 return $textcases + $htmlcases; 1140 } 1141 1142 /** 1143 * Verify forum emails body using templates to generate the expected results. 1144 * 1145 * @dataProvider forum_post_email_templates_provider 1146 * @param array $data provider samples. 1147 */ 1148 public function test_forum_post_email_templates($data) { 1149 global $DB; 1150 1151 $this->resetAfterTest(); 1152 1153 // Create the course, with the specified options. 1154 $options = array(); 1155 foreach ($data['course'] as $option => $value) { 1156 $options[$option] = $value; 1157 } 1158 $course = $this->getDataGenerator()->create_course($options); 1159 1160 // Create the user, with the specified options and enrol in the course. 1161 $options = array(); 1162 foreach ($data['user'] as $option => $value) { 1163 $options[$option] = $value; 1164 } 1165 $user = $this->getDataGenerator()->create_user($options); 1166 $this->getDataGenerator()->enrol_user($user->id, $course->id); 1167 1168 // Create forums, always force susbscribed (for easy), with the specified options. 1169 $posts = array(); 1170 foreach ($data['forums'] as $dataforum) { 1171 $forumposts = isset($dataforum['forumposts']) ? $dataforum['forumposts'] : array(); 1172 unset($dataforum['forumposts']); 1173 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 1174 foreach ($dataforum as $option => $value) { 1175 $options[$option] = $value; 1176 } 1177 $forum = $this->getDataGenerator()->create_module('forum', $options); 1178 1179 // Create posts, always for immediate delivery (for easy), with the specified options. 1180 foreach ($forumposts as $forumpost) { 1181 $attachments = isset($forumpost['attachments']) ? $forumpost['attachments'] : array(); 1182 unset($forumpost['attachments']); 1183 $postoptions = array('course' => $course->id, 'forum' => $forum->id, 'userid' => $user->id, 1184 'mailnow' => 1, 'attachment' => !empty($attachments)); 1185 foreach ($forumpost as $option => $value) { 1186 $postoptions[$option] = $value; 1187 } 1188 list($discussion, $post) = $this->helper_post_to_forum($forum, $user, $postoptions); 1189 $posts[$post->subject] = $post; // Need this to verify cron output. 1190 1191 // Add the attachments to the post. 1192 if ($attachments) { 1193 $fs = get_file_storage(); 1194 foreach ($attachments as $attachment) { 1195 $filerecord = array( 1196 'contextid' => \context_module::instance($forum->cmid)->id, 1197 'component' => 'mod_forum', 1198 'filearea' => 'attachment', 1199 'itemid' => $post->id, 1200 'filepath' => '/', 1201 'filename' => $attachment['filename'] 1202 ); 1203 $fs->create_file_from_string($filerecord, $attachment['filecontents']); 1204 } 1205 $DB->set_field('forum_posts', 'attachment', '1', array('id' => $post->id)); 1206 } 1207 } 1208 } 1209 1210 // Clear the mailsink and close the messagesink. 1211 // (surely setup should provide us this cleared but...) 1212 $this->mailsink->clear(); 1213 $this->messagesink->close(); 1214 1215 $expect = [ 1216 'author' => (object) [ 1217 'userid' => $user->id, 1218 'messages' => count($posts), 1219 ], 1220 ]; 1221 $this->queue_tasks_and_assert($expect); 1222 1223 $this->send_notifications_and_assert($user, $posts); 1224 1225 // Get the mails. 1226 $mails = $this->mailsink->get_messages(); 1227 1228 // Start testing the expectations. 1229 $expectations = $data['expectations']; 1230 1231 // Assert the number is the expected. 1232 $this->assertSame(count($expectations), count($mails)); 1233 1234 // Start processing mails, first localizing its expectations, then checking them. 1235 foreach ($mails as $mail) { 1236 // Find the corresponding expectation. 1237 $foundexpectation = null; 1238 foreach ($expectations as $key => $expectation) { 1239 // All expectations must have a subject for matching. 1240 if (!isset($expectation['subject'])) { 1241 $this->fail('Provider expectation missing mandatory subject'); 1242 } 1243 if (preg_match('!' . $expectation['subject'] . '!', $mail->subject)) { 1244 // If we already had found the expectation, there are non-unique subjects. Fail. 1245 if (isset($foundexpectation)) { 1246 $this->fail('Multiple expectations found (by subject matching). Please make them unique.'); 1247 } 1248 $foundexpectation = $expectation; 1249 unset($expectations[$key]); 1250 } 1251 } 1252 // Arrived here, we should have found the expectations. 1253 $this->assertNotEmpty($foundexpectation, 'Expectation not found for the mail'); 1254 1255 // If we have found the expectation and have contents to match, let's do it. 1256 if (isset($foundexpectation) and isset($foundexpectation['contents'])) { 1257 $mail->body = quoted_printable_decode($mail->body); 1258 if (!is_array($foundexpectation['contents'])) { // Accept both string and array. 1259 $foundexpectation['contents'] = array($foundexpectation['contents']); 1260 } 1261 foreach ($foundexpectation['contents'] as $content) { 1262 if (strpos($content, '~') !== 0) { 1263 $this->assertMatchesRegularExpression('#' . $content . '#m', $mail->body); 1264 } else { 1265 preg_match('#' . substr($content, 1) . '#m', $mail->body, $matches); 1266 $this->assertDoesNotMatchRegularExpression('#' . substr($content, 1) . '#m', $mail->body); 1267 } 1268 } 1269 } 1270 } 1271 1272 // Finished, there should not be remaining expectations. 1273 $this->assertCount(0, $expectations); 1274 } 1275 1276 /** 1277 * Ensure that posts already mailed are not re-sent. 1278 */ 1279 public function test_already_mailed() { 1280 global $DB; 1281 1282 $this->resetAfterTest(true); 1283 1284 // Create a course, with a forum. 1285 $course = $this->getDataGenerator()->create_course(); 1286 1287 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1288 $forum = $this->getDataGenerator()->create_module('forum', $options); 1289 1290 // Create two users enrolled in the course as students. 1291 list($author, $recipient) = $this->helper_create_users($course, 2); 1292 1293 // Post a discussion to the forum. 1294 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1295 $DB->set_field('forum_posts', 'mailed', 1); 1296 1297 // No posts shoudl be considered. 1298 $this->queue_tasks_and_assert([]); 1299 1300 // No notifications should be queued. 1301 $this->send_notifications_and_assert($author, []); 1302 $this->send_notifications_and_assert($recipient, []); 1303 } 1304 1305 /** 1306 * Ensure that posts marked mailnow are not suspect to the maxeditingtime. 1307 */ 1308 public function test_mailnow() { 1309 global $CFG, $DB; 1310 1311 // Update the maxeditingtime to 1 day so that posts won't be sent. 1312 $CFG->maxeditingtime = DAYSECS; 1313 1314 $this->resetAfterTest(true); 1315 1316 // Create a course, with a forum. 1317 $course = $this->getDataGenerator()->create_course(); 1318 1319 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1320 $forum = $this->getDataGenerator()->create_module('forum', $options); 1321 1322 // Create two users enrolled in the course as students. 1323 list($author, $recipient) = $this->helper_create_users($course, 2); 1324 1325 // Post a discussion to the forum. 1326 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1327 1328 // Post a discussion to the forum. 1329 list($discussion, $postmailednow) = $this->helper_post_to_forum($forum, $author, ['mailnow' => 1]); 1330 1331 // Only the mailnow post should be considered. 1332 $expect = [ 1333 'author' => (object) [ 1334 'userid' => $author->id, 1335 'messages' => 1, 1336 ], 1337 'recipient' => (object) [ 1338 'userid' => $recipient->id, 1339 'messages' => 1, 1340 ], 1341 ]; 1342 $this->queue_tasks_and_assert($expect); 1343 1344 // No notifications should be queued. 1345 $this->send_notifications_and_assert($author, [$postmailednow]); 1346 $this->send_notifications_and_assert($recipient, [$postmailednow]); 1347 } 1348 1349 /** 1350 * Ensure that if a user has no permission to view a post, then it is not sent. 1351 */ 1352 public function test_access_coursemodule_hidden() { 1353 global $CFG, $DB; 1354 1355 $this->resetAfterTest(true); 1356 1357 // Create a course, with a forum. 1358 $course = $this->getDataGenerator()->create_course(); 1359 1360 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1361 $forum = $this->getDataGenerator()->create_module('forum', $options); 1362 1363 // Create two users enrolled in the course as students. 1364 list($author, $recipient) = $this->helper_create_users($course, 2); 1365 1366 // Create one users enrolled in the course as an editing teacher. 1367 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1368 1369 // Post a discussion to the forum. 1370 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1371 1372 // Hide the coursemodule. 1373 set_coursemodule_visible($forum->cmid, 0); 1374 1375 // Only the mailnow post should be considered. 1376 $expect = [ 1377 'author' => (object) [ 1378 'userid' => $author->id, 1379 'messages' => 1, 1380 ], 1381 'recipient' => (object) [ 1382 'userid' => $recipient->id, 1383 'messages' => 1, 1384 ], 1385 'editor' => (object) [ 1386 'userid' => $editor->id, 1387 'messages' => 1, 1388 ], 1389 ]; 1390 $this->queue_tasks_and_assert($expect); 1391 1392 // No notifications should be queued. 1393 $this->send_notifications_and_assert($author, [], true); 1394 $this->send_notifications_and_assert($recipient, [], true); 1395 $this->send_notifications_and_assert($editor, [$post], true); 1396 } 1397 1398 /** 1399 * Ensure that if a user loses permission to view a post after it is queued, that it is not sent. 1400 */ 1401 public function test_access_coursemodule_hidden_after_queue() { 1402 global $CFG, $DB; 1403 1404 $this->resetAfterTest(true); 1405 1406 // Create a course, with a forum. 1407 $course = $this->getDataGenerator()->create_course(); 1408 1409 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1410 $forum = $this->getDataGenerator()->create_module('forum', $options); 1411 1412 // Create two users enrolled in the course as students. 1413 list($author, $recipient) = $this->helper_create_users($course, 2); 1414 1415 // Create one users enrolled in the course as an editing teacher. 1416 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1417 1418 // Post a discussion to the forum. 1419 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1420 1421 // Only the mailnow post should be considered. 1422 $expect = [ 1423 'author' => (object) [ 1424 'userid' => $author->id, 1425 'messages' => 1, 1426 ], 1427 'recipient' => (object) [ 1428 'userid' => $recipient->id, 1429 'messages' => 1, 1430 ], 1431 'editor' => (object) [ 1432 'userid' => $editor->id, 1433 'messages' => 1, 1434 ], 1435 ]; 1436 $this->queue_tasks_and_assert($expect); 1437 1438 // Hide the coursemodule. 1439 set_coursemodule_visible($forum->cmid, 0); 1440 1441 // No notifications should be queued for the students. 1442 $this->send_notifications_and_assert($author, [], true); 1443 $this->send_notifications_and_assert($recipient, [], true); 1444 1445 // The editing teacher should still receive the post. 1446 $this->send_notifications_and_assert($editor, [$post]); 1447 } 1448 1449 /** 1450 * Ensure that messages are not sent until the timestart. 1451 */ 1452 public function test_access_before_timestart() { 1453 global $CFG, $DB; 1454 1455 $this->resetAfterTest(true); 1456 1457 // Create a course, with a forum. 1458 $course = $this->getDataGenerator()->create_course(); 1459 1460 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1461 $forum = $this->getDataGenerator()->create_module('forum', $options); 1462 1463 // Create two users enrolled in the course as students. 1464 list($author, $recipient) = $this->helper_create_users($course, 2); 1465 1466 // Create one users enrolled in the course as an editing teacher. 1467 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1468 1469 // Post a discussion to the forum. 1470 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1471 1472 // Update the discussion to have a timestart in the future. 1473 $DB->set_field('forum_discussions', 'timestart', time() + DAYSECS); 1474 1475 // None should be sent. 1476 $this->queue_tasks_and_assert([]); 1477 1478 // No notifications should be queued for any user. 1479 $this->send_notifications_and_assert($author, []); 1480 $this->send_notifications_and_assert($recipient, []); 1481 $this->send_notifications_and_assert($editor, []); 1482 1483 // Update the discussion to have a timestart in the past. 1484 $DB->set_field('forum_discussions', 'timestart', time() - DAYSECS); 1485 1486 // Now should be sent to all. 1487 $expect = [ 1488 'author' => (object) [ 1489 'userid' => $author->id, 1490 'messages' => 1, 1491 ], 1492 'recipient' => (object) [ 1493 'userid' => $recipient->id, 1494 'messages' => 1, 1495 ], 1496 'editor' => (object) [ 1497 'userid' => $editor->id, 1498 'messages' => 1, 1499 ], 1500 ]; 1501 $this->queue_tasks_and_assert($expect); 1502 1503 // No notifications should be queued for any user. 1504 $this->send_notifications_and_assert($author, [$post]); 1505 $this->send_notifications_and_assert($recipient, [$post]); 1506 $this->send_notifications_and_assert($editor, [$post]); 1507 } 1508 1509 /** 1510 * Ensure that messages are not sent after the timeend. 1511 */ 1512 public function test_access_after_timeend() { 1513 global $CFG, $DB; 1514 1515 $this->resetAfterTest(true); 1516 1517 // Create a course, with a forum. 1518 $course = $this->getDataGenerator()->create_course(); 1519 1520 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); 1521 $forum = $this->getDataGenerator()->create_module('forum', $options); 1522 1523 // Create two users enrolled in the course as students. 1524 list($author, $recipient) = $this->helper_create_users($course, 2); 1525 1526 // Create one users enrolled in the course as an editing teacher. 1527 list($editor) = $this->helper_create_users($course, 1, 'editingteacher'); 1528 1529 // Post a discussion to the forum. 1530 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1531 1532 // Update the discussion to have a timestart in the past. 1533 $DB->set_field('forum_discussions', 'timeend', time() - DAYSECS); 1534 1535 // None should be sent. 1536 $this->queue_tasks_and_assert([]); 1537 1538 // No notifications should be queued for any user. 1539 $this->send_notifications_and_assert($author, []); 1540 $this->send_notifications_and_assert($recipient, []); 1541 $this->send_notifications_and_assert($editor, []); 1542 1543 // Update the discussion to have a timestart in the past. 1544 $DB->set_field('forum_discussions', 'timeend', time() + DAYSECS); 1545 1546 // Now should be sent to all. 1547 $expect = [ 1548 'author' => (object) [ 1549 'userid' => $author->id, 1550 'messages' => 1, 1551 ], 1552 'recipient' => (object) [ 1553 'userid' => $recipient->id, 1554 'messages' => 1, 1555 ], 1556 'editor' => (object) [ 1557 'userid' => $editor->id, 1558 'messages' => 1, 1559 ], 1560 ]; 1561 $this->queue_tasks_and_assert($expect); 1562 1563 // No notifications should be queued for any user. 1564 $this->send_notifications_and_assert($author, [$post]); 1565 $this->send_notifications_and_assert($recipient, [$post]); 1566 $this->send_notifications_and_assert($editor, [$post]); 1567 } 1568 1569 /** 1570 * Test notification comes with customdata. 1571 */ 1572 public function test_notification_customdata() { 1573 $this->resetAfterTest(true); 1574 1575 $course = $this->getDataGenerator()->create_course(); 1576 1577 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); 1578 $forum = $this->getDataGenerator()->create_module('forum', $options); 1579 1580 list($author) = $this->helper_create_users($course, 1); 1581 list($commenter) = $this->helper_create_users($course, 1); 1582 1583 $strre = get_string('re', 'forum'); 1584 1585 // New posts should not have Re: in the subject. 1586 list($discussion, $post) = $this->helper_post_to_forum($forum, $author); 1587 $expect = [ 1588 'author' => (object) [ 1589 'userid' => $author->id, 1590 'messages' => 1, 1591 ], 1592 'commenter' => (object) [ 1593 'userid' => $commenter->id, 1594 'messages' => 1, 1595 ], 1596 ]; 1597 $this->queue_tasks_and_assert($expect); 1598 1599 $this->send_notifications_and_assert($author, [$post]); 1600 $this->send_notifications_and_assert($commenter, [$post]); 1601 $messages = $this->messagesink->get_messages(); 1602 $customdata = json_decode($messages[0]->customdata); 1603 $this->assertEquals($forum->id, $customdata->instance); 1604 $this->assertEquals($forum->cmid, $customdata->cmid); 1605 $this->assertEquals($post->id, $customdata->postid); 1606 $this->assertEquals($discussion->id, $customdata->discussionid); 1607 $this->assertObjectHasAttribute('notificationiconurl', $customdata); 1608 $this->assertObjectHasAttribute('actionbuttons', $customdata); 1609 $this->assertCount(1, (array) $customdata->actionbuttons); 1610 } 1611 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body