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